diff --git a/INSTALL b/INSTALL index bd8d294d00af..4171ce816f7b 100644 --- a/INSTALL +++ b/INSTALL @@ -1,283 +1,304 @@ Installation Instructions ========================= This file contains instructions on building and installing the libraries and utilities in the elftoolchain project's sources. Supported Operating Systems --------------------------- The source tree is currently built and tested on the following operating systems. ================= ======== ======================= Operating System Version Supported Architectures ----------------- -------- ----------------------- `DragonFly BSD`_ 2.10.1 i386 FreeBSD_ v8.2 amd64 & i386 Minix_ 3.0.2 i386 NetBSD_ v5.0.2 i386 OpenBSD_ v5.0 i386 Ubuntu_ GNU/Linux 10.04LTS i386 & x86_64 + Ubuntu_ GNU/Linux 12.04LTS i386 & x86_64 ================= ======== ======================= .. _DragonFly BSD: http://www.dragonflybsd.org/ .. _FreeBSD: http://www.freebsd.org/ .. _Minix: http://www.minix3.org/ .. _NetBSD: http://www.netbsd.org/ .. _OpenBSD: http://www.openbsd.org/ .. _Ubuntu: http://www.ubuntu.com/ Building the Source Tree ======================== The core libraries and utilities that make up the software release are always built by default. Builds of the project's test suites (in the ``test/`` subdirectory), and of additional documentation (in the directory ``documentation/``) are optional and will only be attempted if these directories are present. Prerequisites ------------- :DragonFly BSD 2.10.1: - The core libraries and utilities should build out of the box on a stock install of DragonFly BSD. - To build and run the test suite: #. The current release of the `Test Execution Toolkit`_ needs to be downloaded and unpacked into the ``test/tet/`` directory. #. The ``py26-yaml`` package needs to be installed:: % sudo pkgin install py26-yaml - Building additional documentation is not currently supported under DragonFly BSD. :FreeBSD 8.2: - The core libraries and utilities should build out of the box on a stock install of FreeBSD. - To build and run the test suite: #. The current release of the `Test Execution Toolkit`_ needs to be downloaded and unpacked into the ``test/tet/`` directory. #. The ``py-yaml`` package needs to be installed:: % sudo pkg_add -r py-yaml - To build additional documentation, the ``latex-pgf`` package is needed:: % sudo pkg_add -r latex-pgf :Minix 3.2.0: - The following packages are pre-requisites for building the sources on Minix 3.2.0: =================== ===================================== **Package** **Description** =================== ===================================== ``gcc44`` The GNU C compiler. =================== ===================================== The following command line may be used to install the necessary pre-requisites:: # pkgin install gcc44 - The test suites cannot currently be built under Minix. - Building additional documentation is not currently supported under Minix. :OpenBSD 5.0: - The following packages are pre-requisites for building the sources on OpenBSD 5.0: =================== ===================================== **Package** **Description** =================== ===================================== ``libarchive`` An archive access library. =================== ===================================== The following command line may be used to install the necessary pre-requisites:: # pkg_add libarchive-2.8.4p0 - The test suites cannot currently be built under OpenBSD. - Building additional documentation is not currently supported under OpenBSD. +:OpenBSD 5.4: + - The following packages are pre-requisites for building the + sources on OpenBSD 5.4: + + =================== ===================================== + **Package** **Description** + =================== ===================================== + ``libarchive`` An archive access library. + =================== ===================================== + + The following command line may be used to install the necessary + pre-requisites:: + + # pkg_add libarchive + + - The test suites cannot currently be built under OpenBSD. + + - Building additional documentation is not currently supported + under OpenBSD. + :NetBSD 5.0.2: - The core libraries and utilities should build out of the box on a stock install of NetBSD. - To build and run the test suite: #. The current release of the `Test Execution Toolkit`_, needs to be downloaded and unpacked into the ``test/tet/`` directory. #. The following additional package needs to be installed, as listed in the example command line below :: % sudo pkg_add py26-yaml - Building additional documentation is not currently supported under NetBSD. :Ubuntu GNU/Linux 10.04: - The following packages are pre-requisites for building the sources on Ubuntu GNU/Linux 10.04: =================== ===================================== **Package** **Description** =================== ===================================== ``binutils`` Needed for the build. ``bison`` Parser generator. ``flex`` Lexical analyser. ``gcc`` C compiler. ``libarchive-dev`` Archive access library. ``libc6-dev`` Files for C language development. ``libexpat1-dev`` An XML processing library. ``m4`` Macro processor. ``pmake`` A ``make`` that uses BSD-make syntax. ``python-yaml`` A YAML library for Python. ``sharutils`` For ``uudecode``. =================== ===================================== The following command line may be used to install the necessary pre-requisites:: % sudo apt-get install binutils bison flex gcc libarchive-dev \ libc6-dev m4 pmake - To build and run the test suite: #. The current release of the `Test Execution Toolkit`_, needs to be downloaded and unpacked into the ``test/tet/`` directory. #. The following additional packages need to be installed, as listed in the example command line below:: % sudo apt-get install libexpat1-dev python-yaml sharutils - To build additional documentation, the ``pgf`` package is needed:: % sudo apt-get install pgf -:Ubuntu GNU/Linux 11.10: +:Ubuntu GNU/Linux 12.04: - The following packages are pre-requisites for building the - sources on Ubuntu GNU/Linux 11.10: + sources on Ubuntu GNU/Linux 12.04: =================== ===================================== **Package** **Description** =================== ===================================== ``bison`` Parser generator. + ``build-essential`` Basic build tools. ``flex`` Lexical analyser. - ``gcc`` C compiler. ``libarchive-dev`` Archive access library. ``libexpat1-dev`` An XML processing library. ``m4`` Macro processor. ``pmake`` A ``make`` that uses BSD-make syntax. ``python-yaml`` A YAML library for Python. ``sharutils`` For ``uudecode``. =================== ===================================== The following command line may be used to install the necessary pre-requisites:: - % sudo apt-get install bison flex gcc libarchive-dev \ + % sudo apt-get install bison build-essential flex libarchive-dev \ m4 pmake - To build and run the test suite: #. The current release of the `Test Execution Toolkit`_, needs to be downloaded and unpacked into the ``test/tet/`` directory. #. The following additional packages need to be installed, as listed in the example command line below:: % sudo apt-get install libexpat1-dev python-yaml sharutils - Builds of additional documentation are not currently supported - under Ubuntu GNU/Linux 11.10. + under Ubuntu GNU/Linux 12.04. .. _Test Execution Toolkit: http://tetworks.opengroup.org/ .. _OpenGroup: http://www.opengroup.org/ Building the software --------------------- The software may be built by running **make**. On `DragonFly BSD`_, FreeBSD_, Minix_, NetBSD_ and OpenBSD_, use:: % make On Ubuntu GNU/Linux with the **pmake** package installed, use:: % pmake Testing the software --------------------- The ``run-tests`` target in the top-level Makefile will build and execute the test suites that are part of this software. On `DragonFly BSD`_, FreeBSD_ and NetBSD_, use:: % make run-tests On Ubuntu GNU/Linux with the **pmake** package installed, use:: % pmake run-tests Installing the Software ======================= The software may be installed using the ``install`` target. On `DragonFly BSD`_, FreeBSD_, Minix_, NetBSD_ and OpenBSD_ use:: % make install On Ubuntu GNU/Linux with the **pmake** package installed, use:: % pmake install By default the ``install`` target will install utilities into ``/usr/bin/``, libraries into ``/usr/lib/`` and manual pages into ``/usr/share/man/man[0-9]/``. The installation directory may be changed using the ``DESTDIR`` variable. For example:: % pmake DESTDIR=$HOME/local install Additional Information ====================== Additional information about the project may be found on the `project website`_. .. _project website: http://elftoolchain.sourceforge.net/ -.. $Id: INSTALL 2777 2012-12-12 17:21:36Z jkoshy $ +.. $Id: INSTALL 3020 2014-04-17 15:52:31Z jkoshy $ .. Local Variables: .. mode: rst .. End: diff --git a/Makefile b/Makefile index 64d2a444fc62..b217fdda1f11 100644 --- a/Makefile +++ b/Makefile @@ -1,54 +1,55 @@ -# $Id: Makefile 2872 2013-01-07 13:57:54Z jkoshy $ +# $Id: Makefile 3016 2014-04-10 16:01:42Z jkoshy $ TOP= . .include "${TOP}/mk/elftoolchain.os.mk" # Build configuration information first. SUBDIR += common # Build the base libraries next. SUBDIR += libelf SUBDIR += libdwarf # Build additional APIs. SUBDIR += libelftc # Build the tools needed for the rest of the build. -SUBDIR += isa + +# SUBDIR += isa # ('isa' does not build on all platforms yet). # Build tools after the libraries. SUBDIR += addr2line SUBDIR += ar SUBDIR += brandelf SUBDIR += cxxfilt SUBDIR += elfcopy SUBDIR += elfdump SUBDIR += findtextrel SUBDIR += nm SUBDIR += readelf SUBDIR += size SUBDIR += strings SUBDIR += tools # Build the test suites. .if exists(${.CURDIR}/test) && defined(MKTESTS) && ${MKTESTS} == "yes" SUBDIR += test .endif # Build documentation at the end. .if exists(${.CURDIR}/documentation) && defined(MKDOC) && ${MKDOC} == "yes" SUBDIR += documentation .endif .include "${TOP}/mk/elftoolchain.subdir.mk" # # Special top-level targets. # # Run the test suites. .if exists(${.CURDIR}/test) && defined(MKTESTS) && ${MKTESTS} == "yes" run-tests: all .PHONY (cd ${.CURDIR}/test; ${MAKE} test) .endif diff --git a/ar/Makefile b/ar/Makefile index c20a9f7ffbd1..ddd811338d92 100644 --- a/ar/Makefile +++ b/ar/Makefile @@ -1,35 +1,35 @@ -# $Id: Makefile 2741 2012-12-10 18:47:00Z jkoshy $ +# $Id: Makefile 3107 2014-12-20 08:31:58Z kaiwang27 $ TOP= .. PROG= ar SRCS= ar.c read.c util.c write.c LSRC= acplex.l YSRC= acpyacc.y WARNS?= 5 -DPADD= ${LIBARCHIVE} ${LIBELFTC} ${LIBELF} -LDADD= -larchive -lelftc -lelf +DPADD= ${LIBARCHIVE} ${LIBELFTC} ${LIBELF} ${LIBZ} +LDADD= -larchive -lelftc -lelf -lz CFLAGS+=-I. -I${.CURDIR} LINKS= ${BINDIR}/ar ${BINDIR}/ranlib EXTRA_TARGETS= ranlib CLEANFILES+= ${EXTRA_TARGETS} MAN= ar.1 ranlib.1 ar.5 all: ${EXTRA_TARGETS} ${EXTRA_TARGETS}: ${PROG} ln -s ${PROG} ${.TARGET} .include "${TOP}/mk/elftoolchain.prog.mk" .if ${OS_HOST} == "OpenBSD" CFLAGS+= -I/usr/local/include LDFLAGS+= -L/usr/local/lib .endif diff --git a/ar/acpyacc.y b/ar/acpyacc.y index bbe26e021dbf..e1d02ec82513 100644 --- a/ar/acpyacc.y +++ b/ar/acpyacc.y @@ -1,661 +1,660 @@ %{ /*- * Copyright (c) 2008 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libelftc.h" #include "ar.h" ELFTC_VCSID("$Id"); #define TEMPLATE "arscp.XXXXXXXX" struct list { char *str; struct list *next; }; extern int yylex(void); extern int yyparse(void); static void yyerror(const char *); static void arscp_addlib(char *archive, struct list *list); static void arscp_addmod(struct list *list); static void arscp_clear(void); static void arscp_create(char *in, char *out); static void arscp_delete(struct list *list); static void arscp_dir(char *archive, struct list *list, char *rlt); static void arscp_end(int eval); static void arscp_extract(struct list *list); static void arscp_free_argv(void); static void arscp_free_mlist(struct list *list); static void arscp_list(void); static struct list *arscp_mlist(struct list *list, char *str); static void arscp_mlist2argv(struct list *list); static int arscp_mlist_len(struct list *list); static void arscp_open(char *fname); static void arscp_prompt(void); static void arscp_replace(struct list *list); static void arscp_save(void); static int arscp_target_exist(void); extern int lineno; static struct bsdar *bsdar; static char *target; static char *tmpac; static int interactive; static int verbose; %} %token ADDLIB %token ADDMOD %token CLEAR %token CREATE %token DELETE %token DIRECTORY %token END %token EXTRACT %token LIST %token OPEN %token REPLACE %token VERBOSE %token SAVE %token LP %token RP %token COMMA %token EOL %token FNAME %type mod_list %union { char *str; struct list *list; } %% begin : { arscp_prompt(); } ar_script ; ar_script : cmd_list | ; mod_list : FNAME { $$ = arscp_mlist(NULL, $1); } | mod_list separator FNAME { $$ = arscp_mlist($1, $3); } ; separator : COMMA | ; cmd_list : rawcmd | cmd_list rawcmd ; rawcmd : cmd EOL { arscp_prompt(); } ; cmd : addlib_cmd | addmod_cmd | clear_cmd | create_cmd | delete_cmd | directory_cmd | end_cmd | extract_cmd | list_cmd | open_cmd | replace_cmd | verbose_cmd | save_cmd | invalid_cmd | empty_cmd | error ; addlib_cmd : ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); } | ADDLIB FNAME { arscp_addlib($2, NULL); } ; addmod_cmd : ADDMOD mod_list { arscp_addmod($2); } ; clear_cmd : CLEAR { arscp_clear(); } ; create_cmd : CREATE FNAME { arscp_create(NULL, $2); } ; delete_cmd : DELETE mod_list { arscp_delete($2); } ; directory_cmd : DIRECTORY FNAME { arscp_dir($2, NULL, NULL); } | DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); } | DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); } ; end_cmd : END { arscp_end(EXIT_SUCCESS); } ; extract_cmd : EXTRACT mod_list { arscp_extract($2); } ; list_cmd : LIST { arscp_list(); } ; open_cmd : OPEN FNAME { arscp_open($2); } ; replace_cmd : REPLACE mod_list { arscp_replace($2); } ; save_cmd : SAVE { arscp_save(); } ; verbose_cmd : VERBOSE { verbose = !verbose; } ; empty_cmd : ; invalid_cmd : FNAME { yyerror(NULL); } ; %% /* ARGSUSED */ static void yyerror(const char *s) { (void) s; printf("Syntax error in archive script, line %d\n", lineno); } /* * The arscp_open() function will first open an archive and check its * validity. If the archive format is valid, it will call * arscp_create() to create a temporary copy of the archive. */ static void arscp_open(char *fname) { struct archive *a; struct archive_entry *entry; int r; if ((a = archive_read_new()) == NULL) bsdar_errc(bsdar, 0, "archive_read_new failed"); - archive_read_support_compression_none(a); archive_read_support_format_ar(a); - AC(archive_read_open_file(a, fname, DEF_BLKSZ)); + AC(archive_read_open_filename(a, fname, DEF_BLKSZ)); if ((r = archive_read_next_header(a, &entry))) bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); AC(archive_read_close(a)); - ACV(archive_read_finish(a)); + ACV(archive_read_free(a)); if (r != ARCHIVE_OK) return; arscp_create(fname, fname); } /* * Create an archive. * * If the parameter 'in' is NULL (the 'CREATE' command), a new empty * archive will be created. If the parameter 'in' is not NULL (the * 'OPEN' command), the resulting archive will be a modified version * of the existing archive. */ static void arscp_create(char *in, char *out) { struct archive *a; int ifd, ofd; /* Delete the previously created temporary archive, if any. */ if (tmpac) { if (unlink(tmpac) < 0) bsdar_errc(bsdar, errno, "unlink failed"); free(tmpac); } tmpac = strdup(TEMPLATE); if (tmpac == NULL) bsdar_errc(bsdar, errno, "strdup failed"); if ((ofd = mkstemp(tmpac)) < 0) bsdar_errc(bsdar, errno, "mkstemp failed"); if (in) { /* * The 'OPEN' command creates a temporary copy of the * input archive. */ if ((ifd = open(in, O_RDONLY)) < 0 || elftc_copyfile(ifd, ofd) < 0) { bsdar_warnc(bsdar, errno, "'OPEN' failed"); (void) close(ofd); if (ifd != -1) (void) close(ifd); return; } (void) close(ifd); (void) close(ofd); } else { /* * The 'CREATE' command creates an "empty" archive (an * archive consisting only of the archive header). */ if ((a = archive_write_new()) == NULL) bsdar_errc(bsdar, 0, "archive_write_new failed"); archive_write_set_format_ar_svr4(a); AC(archive_write_open_fd(a, ofd)); AC(archive_write_close(a)); - ACV(archive_write_finish(a)); + ACV(archive_write_free(a)); } /* Override the previous target, if any. */ if (target) free(target); target = out; bsdar->filename = tmpac; } /* * Add all modules of an archive to the current archive. If the * parameter 'list' is not NULL, only those modules specified by * 'list' will be added. */ static void arscp_addlib(char *archive, struct list *list) { if (!arscp_target_exist()) return; arscp_mlist2argv(list); bsdar->addlib = archive; ar_write_archive(bsdar, 'A'); arscp_free_argv(); arscp_free_mlist(list); } /* * Add modules to the current archive. */ static void arscp_addmod(struct list *list) { if (!arscp_target_exist()) return; arscp_mlist2argv(list); ar_write_archive(bsdar, 'q'); arscp_free_argv(); arscp_free_mlist(list); } /* * Delete modules from the current archive. */ static void arscp_delete(struct list *list) { if (!arscp_target_exist()) return; arscp_mlist2argv(list); ar_write_archive(bsdar, 'd'); arscp_free_argv(); arscp_free_mlist(list); } /* * Extract modules from the current archive. */ static void arscp_extract(struct list *list) { if (!arscp_target_exist()) return; arscp_mlist2argv(list); ar_read_archive(bsdar, 'x'); arscp_free_argv(); arscp_free_mlist(list); } /* * List the contents of an archive (simple mode). */ static void arscp_list(void) { if (!arscp_target_exist()) return; bsdar->argc = 0; bsdar->argv = NULL; /* Always verbose. */ bsdar->options |= AR_V; ar_read_archive(bsdar, 't'); bsdar->options &= ~AR_V; } /* * List the contents of an archive (advanced mode). */ static void arscp_dir(char *archive, struct list *list, char *rlt) { FILE *out; /* If rlt != NULL, redirect the output to it. */ out = NULL; if (rlt) { out = bsdar->output; if ((bsdar->output = fopen(rlt, "w")) == NULL) bsdar_errc(bsdar, errno, "fopen %s failed", rlt); } bsdar->filename = archive; if (list) arscp_mlist2argv(list); else { bsdar->argc = 0; bsdar->argv = NULL; } if (verbose) bsdar->options |= AR_V; ar_read_archive(bsdar, 't'); bsdar->options &= ~AR_V; if (rlt) { if (fclose(bsdar->output) == EOF) bsdar_errc(bsdar, errno, "fclose %s failed", rlt); bsdar->output = out; free(rlt); } free(archive); bsdar->filename = tmpac; arscp_free_argv(); arscp_free_mlist(list); } /* * Replace modules in the current archive. */ static void arscp_replace(struct list *list) { if (!arscp_target_exist()) return; arscp_mlist2argv(list); ar_write_archive(bsdar, 'r'); arscp_free_argv(); arscp_free_mlist(list); } /* * Rename the temporary archive to the target archive. */ static void arscp_save(void) { mode_t mask; if (target) { if (rename(tmpac, target) < 0) bsdar_errc(bsdar, errno, "rename failed"); /* * Because mkstemp() creates temporary files with mode * 0600, we set target archive's mode as per the * process umask. */ mask = umask(0); umask(mask); if (chmod(target, 0666 & ~mask) < 0) bsdar_errc(bsdar, errno, "chmod failed"); free(tmpac); free(target); tmpac = NULL; target= NULL; bsdar->filename = NULL; } else bsdar_warnc(bsdar, 0, "no open output archive"); } /* * Discard the contents of the current archive. This is achieved by * invoking the 'CREATE' cmd on the current archive. */ static void arscp_clear(void) { char *new_target; if (target) { new_target = strdup(target); if (new_target == NULL) bsdar_errc(bsdar, errno, "strdup failed"); arscp_create(NULL, new_target); } } /* * Quit ar(1). Note that the 'END' cmd will not 'SAVE' the current * archive before exiting. */ static void arscp_end(int eval) { if (target) free(target); if (tmpac) { if (unlink(tmpac) == -1) bsdar_errc(bsdar, errno, "unlink %s failed", tmpac); free(tmpac); } exit(eval); } /* * Check if a target was specified, i.e, whether an 'OPEN' or 'CREATE' * had been issued by the user. */ static int arscp_target_exist(void) { if (target) return (1); bsdar_warnc(bsdar, 0, "no open output archive"); return (0); } /* * Construct the list of modules. */ static struct list * arscp_mlist(struct list *list, char *str) { struct list *l; l = malloc(sizeof(*l)); if (l == NULL) bsdar_errc(bsdar, errno, "malloc failed"); l->str = str; l->next = list; return (l); } /* * Calculate the length of an mlist. */ static int arscp_mlist_len(struct list *list) { int len; for(len = 0; list; list = list->next) len++; return (len); } /* * Free the space allocated for a module list. */ static void arscp_free_mlist(struct list *list) { struct list *l; /* Note: list->str was freed in arscp_free_argv(). */ for(; list; list = l) { l = list->next; free(list); } } /* * Convert a module list to an 'argv' array. */ static void arscp_mlist2argv(struct list *list) { char **argv; int i, n; n = arscp_mlist_len(list); argv = malloc(n * sizeof(*argv)); if (argv == NULL) bsdar_errc(bsdar, errno, "malloc failed"); /* Note that module names are stored in reverse order. */ for(i = n - 1; i >= 0; i--, list = list->next) { if (list == NULL) bsdar_errc(bsdar, errno, "invalid mlist"); argv[i] = list->str; } bsdar->argc = n; bsdar->argv = argv; } /* * Free the space allocated for an argv array and its elements. */ static void arscp_free_argv(void) { int i; for(i = 0; i < bsdar->argc; i++) free(bsdar->argv[i]); free(bsdar->argv); } /* * Show a prompt if we are in interactive mode. */ static void arscp_prompt(void) { if (interactive) { printf("AR >"); fflush(stdout); } } /* * The main function implementing script mode. */ void ar_mode_script(struct bsdar *ar) { bsdar = ar; interactive = isatty(fileno(stdin)); while(yyparse()) { if (!interactive) arscp_end(EXIT_FAILURE); } /* Script ends without END */ arscp_end(EXIT_SUCCESS); } diff --git a/ar/os.Linux.mk b/ar/os.Linux.mk new file mode 100644 index 000000000000..daed864eee9e --- /dev/null +++ b/ar/os.Linux.mk @@ -0,0 +1,9 @@ +.if ${OS_DISTRIBUTION} == "Ubuntu" +.if ${OS_DISTRIBUTION_VERSION} >= 14 +# Ubuntu Trusty Tahr and later. + +# Use the --nounput option to flex(1), to prevent unused functions from +# being generated. +LFLAGS += --nounput +.endif +.endif diff --git a/ar/read.c b/ar/read.c index 6c2affe57438..4e79ff2568ae 100644 --- a/ar/read.c +++ b/ar/read.c @@ -1,192 +1,191 @@ /*- * Copyright (c) 2007 Kai Wang * Copyright (c) 2007 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "ar.h" -ELFTC_VCSID("$Id: read.c 2229 2011-11-27 13:25:37Z jkoshy $"); +ELFTC_VCSID("$Id: read.c 3102 2014-10-29 21:09:01Z jkoshy $"); /* * Handle read modes: 'x', 't' and 'p'. */ void ar_read_archive(struct bsdar *bsdar, int mode) { FILE *out; struct archive *a; struct archive_entry *entry; struct stat sb; struct tm *tp; const char *bname; const char *name; mode_t md; size_t size; time_t mtime; uid_t uid; gid_t gid; char **av; char buf[25]; char find; int i, flags, r; assert(mode == 'p' || mode == 't' || mode == 'x'); if ((a = archive_read_new()) == NULL) bsdar_errc(bsdar, 0, "archive_read_new failed"); - archive_read_support_compression_none(a); archive_read_support_format_ar(a); - AC(archive_read_open_file(a, bsdar->filename, DEF_BLKSZ)); + AC(archive_read_open_filename(a, bsdar->filename, DEF_BLKSZ)); out = bsdar->output; for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || r == ARCHIVE_FATAL) bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); if (r == ARCHIVE_EOF || r == ARCHIVE_FATAL) break; if (r == ARCHIVE_RETRY) { bsdar_warnc(bsdar, 0, "Retrying..."); continue; } if (archive_format(a) == ARCHIVE_FORMAT_AR_BSD) bsdar->options |= AR_BSD; else bsdar->options &= ~AR_BSD; name = archive_entry_pathname(entry); /* Skip pseudo members. */ if (bsdar_is_pseudomember(bsdar, name)) continue; if (bsdar->argc > 0) { find = 0; for(i = 0; i < bsdar->argc; i++) { av = &bsdar->argv[i]; if (*av == NULL) continue; if ((bname = basename(*av)) == NULL) bsdar_errc(bsdar, errno, "basename failed"); if (strcmp(bname, name) != 0) continue; *av = NULL; find = 1; break; } if (!find) continue; } if (mode == 't') { if (bsdar->options & AR_V) { md = archive_entry_mode(entry); uid = archive_entry_uid(entry); gid = archive_entry_gid(entry); size = archive_entry_size(entry); mtime = archive_entry_mtime(entry); (void)fprintf(out, "%s %6d/%-6d %8ju ", bsdar_strmode(md) + 1, uid, gid, (uintmax_t)size); tp = localtime(&mtime); (void)strftime(buf, sizeof(buf), "%b %e %H:%M %Y", tp); (void)fprintf(out, "%s %s", buf, name); } else (void)fprintf(out, "%s", name); r = archive_read_data_skip(a); if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || r == ARCHIVE_FATAL) { (void)fprintf(out, "\n"); bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); } if (r == ARCHIVE_FATAL) break; (void)fprintf(out, "\n"); } else { /* mode == 'x' || mode = 'p' */ if (mode == 'p') { if (bsdar->options & AR_V) { (void)fprintf(out, "\n<%s>\n\n", name); fflush(out); } r = archive_read_data_into_fd(a, fileno(out)); } else { /* mode == 'x' */ if (stat(name, &sb) != 0) { if (errno != ENOENT) { bsdar_warnc(bsdar, 0, "stat %s failed", bsdar->filename); continue; } } else { /* stat success, file exist */ if (bsdar->options & AR_CC) continue; if (bsdar->options & AR_U && archive_entry_mtime(entry) <= sb.st_mtime) continue; } if (bsdar->options & AR_V) (void)fprintf(out, "x - %s\n", name); flags = 0; if (bsdar->options & AR_O) flags |= ARCHIVE_EXTRACT_TIME; r = archive_read_extract(a, entry, flags); } if (r) bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); } } AC(archive_read_close(a)); - ACV(archive_read_finish(a)); + ACV(archive_read_free(a)); } diff --git a/ar/write.c b/ar/write.c index f637d378f226..490b22fab07b 100644 --- a/ar/write.c +++ b/ar/write.c @@ -1,978 +1,976 @@ /*- * Copyright (c) 2007 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ar.h" -ELFTC_VCSID("$Id: write.c 2496 2012-04-24 02:33:40Z jkoshy $"); +ELFTC_VCSID("$Id: write.c 3102 2014-10-29 21:09:01Z jkoshy $"); #define _ARMAG_LEN 8 /* length of the magic string */ #define _ARHDR_LEN 60 /* length of the archive header */ #define _INIT_AS_CAP 128 /* initial archive string table size */ #define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ #define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ #define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ #define _MAXNAMELEN_BSD 16 /* max member name length in bsd variant */ #define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */ static void add_to_ar_str_table(struct bsdar *bsdar, const char *name); static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name); static struct ar_obj *create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime); static void create_symtab_entry(struct bsdar *bsdar, Elf *e); static void free_obj(struct ar_obj *obj); static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos); static void read_objs(struct bsdar *bsdar, const char *archive, int checkargv); static void write_cleanup(struct bsdar *bsdar); static void write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s); static void write_objs(struct bsdar *bsdar); /* * Create an object from a file, and return the created object * descriptor. Return NULL if either an error occurs, or if the '-u' * option was specifed and the member is not newer than the existing * one in the archive. */ static struct ar_obj * create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime) { struct ar_obj *obj; struct stat sb; const char *bname; char *tmpname; int fd; if (name == NULL) return (NULL); obj = malloc(sizeof(struct ar_obj)); if (obj == NULL) bsdar_errc(bsdar, errno, "malloc failed"); obj->elf = NULL; if ((fd = open(name, O_RDONLY, 0)) < 0) { bsdar_warnc(bsdar, errno, "can't open file: %s", name); free(obj); return (NULL); } tmpname = strdup(name); if ((bname = basename(tmpname)) == NULL) bsdar_errc(bsdar, errno, "basename failed"); if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) { if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL) bsdar_errc(bsdar, errno, "malloc failed"); (void)strncpy(obj->name, bname, _TRUNCATE_LEN); obj->name[_TRUNCATE_LEN] = '\0'; } else if ((obj->name = strdup(bname)) == NULL) bsdar_errc(bsdar, errno, "strdup failed"); free(tmpname); if (fstat(fd, &sb) < 0) { bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name); goto giveup; } if (!S_ISREG(sb.st_mode)) { bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name); goto giveup; } if (sb.st_dev == bsdar->ar_dev && sb.st_ino == bsdar->ar_ino) { bsdar_warnc(bsdar, 0, "cannot add archive \"%s\" to itself", obj->name); goto giveup; } /* * If the '-u' option is specified and member is not newer * than the existing one, we should not replace the member. * However, if mtime == 0, i.e., if nonexistent members are to * be forcibly replaced, then the '-u' option is to be ignored. */ if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime) goto giveup; /* * When the '-D' option is specified, the mtime and UID/GID of * the member will be set to 0, and the file mode will be set * to 644. This ensures that checksums will match for two * archives containing identical content. */ if (bsdar->options & AR_D) { obj->uid = 0; obj->gid = 0; obj->mtime = 0; obj->md = S_IFREG | 0644; } else { obj->uid = sb.st_uid; obj->gid = sb.st_gid; obj->mtime = sb.st_mtime; obj->md = sb.st_mode; } obj->size = sb.st_size; obj->dev = sb.st_dev; obj->ino = sb.st_ino; if (obj->size == 0) { return (obj); } if ((obj->elf = elf_open(fd)) == NULL) { bsdar_warnc(bsdar, 0, "file initialization failed for %s: %s", obj->name, elf_errmsg(-1)); goto giveup; } /* * Read the object fully into memory and close its file * descriptor. */ if (elf_cntl(obj->elf, ELF_C_FDREAD) < 0) { bsdar_warnc(bsdar, 0, "%s could not be read in: %s", obj->name, elf_errmsg(-1)); goto giveup; } if (close(fd) < 0) bsdar_errc(bsdar, errno, "close failed: %s", obj->name); return (obj); giveup: if (obj->elf) elf_end(obj->elf); if (close(fd) < 0) bsdar_errc(bsdar, errno, "close failed: %s", obj->name); free(obj->name); free(obj); return (NULL); } /* * Free an object and its associated allocations. */ static void free_obj(struct ar_obj *obj) { if (obj->elf) elf_end(obj->elf); free(obj->name); free(obj); } /* * Insert an object into a list, either before/after the 'pos' obj or * at the end of the list. */ static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos) { if (obj == NULL) bsdar_errc(bsdar, 0, "try to insert a null obj"); if (pos == NULL || obj == pos) /* * If the object to move happens to be the position * obj, or if there is no position obj, move the * object to the end. */ goto tail; if (bsdar->options & AR_B) { TAILQ_INSERT_BEFORE(pos, obj, objs); return; } if (bsdar->options & AR_A) { TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs); return; } tail: TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); } /* * Read objects from archive into the 'v_obj' list. Note that * 'checkargv' is set when read_objs() is used to read objects from * the target of 'ADDLIB' command in ar script mode; in this case the * 'argv' array specifies the members that 'ADDLIB' is to operate on. */ static void read_objs(struct bsdar *bsdar, const char *archive, int checkargv) { struct archive *a; struct archive_entry *entry; struct ar_obj *obj; const char *name; const char *bname; char *buff; char **av; size_t size; int i, r, find; if ((a = archive_read_new()) == NULL) bsdar_errc(bsdar, 0, "archive_read_new failed"); - archive_read_support_compression_none(a); archive_read_support_format_ar(a); AC(archive_read_open_filename(a, archive, DEF_BLKSZ)); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_FATAL) bsdar_errc(bsdar, 0, "%s", archive_error_string(a)); if (r == ARCHIVE_EOF) break; if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); if (r == ARCHIVE_RETRY) { bsdar_warnc(bsdar, 0, "Retrying..."); continue; } name = archive_entry_pathname(entry); /* * Skip pseudo members. */ if (bsdar_is_pseudomember(bsdar, name)) continue; /* * If 'checkargv' is set, only read those members * specified in argv. */ if (checkargv && bsdar->argc > 0) { find = 0; for(i = 0; i < bsdar->argc; i++) { av = &bsdar->argv[i]; if (*av == NULL) continue; if ((bname = basename(*av)) == NULL) bsdar_errc(bsdar, errno, "basename failed"); if (strcmp(bname, name) != 0) continue; *av = NULL; find = 1; break; } if (!find) continue; } size = archive_entry_size(entry); if (size > 0) { if ((buff = malloc(size)) == NULL) bsdar_errc(bsdar, errno, "malloc failed"); if (archive_read_data(a, buff, size) != (ssize_t)size) { bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); free(buff); continue; } } else buff = NULL; obj = malloc(sizeof(struct ar_obj)); if (obj == NULL) bsdar_errc(bsdar, errno, "malloc failed"); obj->elf = NULL; if (buff) { obj->elf = elf_openmemory(buff, size); if (obj->elf == NULL) { bsdar_warnc(bsdar, 0, "elf_openmemory() " "failed for %s: %s", name, elf_errmsg(-1)); free(buff); free(obj); continue; } } if ((obj->name = strdup(name)) == NULL) bsdar_errc(bsdar, errno, "strdup failed"); obj->size = size; obj->uid = archive_entry_uid(entry); obj->gid = archive_entry_gid(entry); obj->md = archive_entry_mode(entry); obj->mtime = archive_entry_mtime(entry); obj->dev = 0; obj->ino = 0; TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); } AC(archive_read_close(a)); - ACV(archive_read_finish(a)); + ACV(archive_read_free(a)); } /* * Write an archive. */ void ar_write_archive(struct bsdar *bsdar, int mode) { struct ar_obj *nobj, *obj, *obj_temp, *pos; struct stat sb; const char *bname; char **av; int i; TAILQ_INIT(&bsdar->v_obj); nobj = NULL; pos = NULL; memset(&sb, 0, sizeof(sb)); assert(mode == 'A' || mode == 'd' || mode == 'm' || mode == 'q' || mode == 'r' || mode == 's'); /* * Test if the specified archive exists, to determine * whether we are creating a new archive. */ if (stat(bsdar->filename, &sb) != 0) { if (errno != ENOENT) { bsdar_warnc(bsdar, 0, "stat %s failed", bsdar->filename); return; } /* We do not create archive in mode 'd', 'm' and 's'. */ if (mode != 'r' && mode != 'q') { bsdar_warnc(bsdar, 0, "%s: no such file", bsdar->filename); return; } /* Issue a message if the '-c' option was not specified. */ if (!(bsdar->options & AR_C)) bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename); goto new_archive; } bsdar->ar_dev = sb.st_dev; bsdar->ar_ino = sb.st_ino; /* * First read members from the existing archive. */ read_objs(bsdar, bsdar->filename, 0); /* * For mode 's', no member will be moved, deleted or replaced. */ if (mode == 's') goto write_objs; /* * For mode 'q', we don't need to adjust existing members either. * Also, -a, -b and -i are ignored in this mode. New members are * always inserted at tail. */ if (mode == 'q') goto new_archive; /* * Mode 'A' adds the contents of another archive to the tail * of current archive. Note that mode 'A' is a special mode * for the 'ADDLIB' command in ar's script mode. Currently * there is no option that invokes this function from ar's * command line. */ if (mode == 'A') { /* * Read objects from the target archive of the * 'ADDLIB' command. If there are members spcified in * 'argv', read those members only, otherwise the * entire archive will be read. */ read_objs(bsdar, bsdar->addlib, 1); goto write_objs; } /* * Try to find the position member specified by user. */ if (bsdar->options & AR_A || bsdar->options & AR_B) { TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { if (strcmp(obj->name, bsdar->posarg) == 0) { pos = obj; break; } } /* * If we cannot find the position specified by the * user, sliently insert objects at the tail of the * list. */ if (pos == NULL) bsdar->options &= ~(AR_A | AR_B); } for (i = 0; i < bsdar->argc; i++) { av = &bsdar->argv[i]; TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { if ((bname = basename(*av)) == NULL) bsdar_errc(bsdar, errno, "basename failed"); if (bsdar->options & AR_TR) { if (strncmp(bname, obj->name, _TRUNCATE_LEN)) continue; } else if (strcmp(bname, obj->name) != 0) continue; if (mode == 'r') { /* * If the new member should not * replace the old one, skip it. */ nobj = create_obj_from_file(bsdar, *av, obj->mtime); if (nobj == NULL) goto skip_obj; } if (bsdar->options & AR_V) (void)fprintf(bsdar->output, "%c - %s\n", mode, *av); TAILQ_REMOVE(&bsdar->v_obj, obj, objs); if (mode == 'd' || mode == 'r') free_obj(obj); if (mode == 'm') insert_obj(bsdar, obj, pos); if (mode == 'r') insert_obj(bsdar, nobj, pos); skip_obj: *av = NULL; break; } } new_archive: /* * When operating in mode 'r', directly add the specified * objects which do not exist in current archive. When * operating in mode 'q', all objects specified by the command * line args are appended to the archive, without checking * existing members in the archive. */ for (i = 0; i < bsdar->argc; i++) { av = &bsdar->argv[i]; if (*av != NULL && (mode == 'r' || mode == 'q')) { nobj = create_obj_from_file(bsdar, *av, 0); if (nobj != NULL) insert_obj(bsdar, nobj, pos); if (bsdar->options & AR_V && nobj != NULL) (void)fprintf(bsdar->output, "a - %s\n", *av); *av = NULL; } } write_objs: write_objs(bsdar); write_cleanup(bsdar); } /* * Release memory. */ static void write_cleanup(struct bsdar *bsdar) { struct ar_obj *obj, *obj_temp; TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { TAILQ_REMOVE(&bsdar->v_obj, obj, objs); free_obj(obj); } free(bsdar->as); free(bsdar->s_so); free(bsdar->s_sn); bsdar->as = NULL; bsdar->s_so = NULL; bsdar->s_sn = NULL; } /* * Wrapper for archive_write_data(). */ static void write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s) { if (archive_write_data(a, buf, s) != (ssize_t)s) bsdar_errc(bsdar, 0, "%s", archive_error_string(a)); } /* * Compute the size of the symbol table for an archive. */ static size_t bsdar_symtab_size(struct bsdar *bsdar) { size_t sz; if (bsdar->options & AR_BSD) { /* * A BSD style symbol table has two parts. * Each part is preceded by its size in bytes, * encoded as a C 'long'. In the first part, * there are 's_cnt' entries, each entry being * 2 'long's in size. The second part * contains a string table. */ sz = 2 * sizeof(long) + (bsdar->s_cnt * 2 * sizeof(long)) + bsdar->s_sn_sz; } else { /* * An SVR4 style symbol table comprises of a 32 bit * number holding the number of entries, followed by * that many 32-bit offsets, followed by a string * table. */ sz = sizeof(uint32_t) + bsdar->s_cnt * sizeof(uint32_t) + bsdar->s_sn_sz; } return (sz); } static void write_svr4_symtab_entry(struct bsdar *bsdar, struct archive *a) { int nr; uint32_t i; /* Translate offsets to big-endian form. */ for (i = 0; i < bsdar->s_cnt; i++) bsdar->s_so[i] = htobe32(bsdar->s_so[i]); nr = htobe32(bsdar->s_cnt); write_data(bsdar, a, &nr, sizeof(uint32_t)); write_data(bsdar, a, bsdar->s_so, sizeof(uint32_t) * bsdar->s_cnt); write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz); } static void write_bsd_symtab_entry(struct bsdar *bsdar, struct archive *a) { long br_sz, br_off, br_strx; char *s; uint32_t i; /* * Write out the size in the byte of the array of 'ranlib' * descriptors to follow. */ br_sz = (long) (bsdar->s_cnt * 2 * sizeof(long)); write_data(bsdar, a, &br_sz, sizeof(long)); /* * Write out the array of 'ranlib' descriptors. Each * descriptor comprises of (a) an offset into the following * string table and (b) a file offset to the relevant member. */ for (i = 0, s = bsdar->s_sn; i < bsdar->s_cnt; i++) { br_strx = (long) (s - bsdar->s_sn); br_off = (long) bsdar->s_so[i]; write_data(bsdar, a, &br_strx, sizeof(long)); write_data(bsdar, a, &br_off, sizeof(long)); /* Find the start of the next symbol in the string table. */ while (*s++ != '\0') ; } /* * Write out the size of the string table as a 'long', * followed by the string table itself. */ br_sz = (long) bsdar->s_sn_sz; write_data(bsdar, a, &br_sz, sizeof(long)); write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz); } /* * Write the resulting archive members. */ static void write_objs(struct bsdar *bsdar) { struct ar_obj *obj; struct archive *a; struct archive_entry *entry; size_t s_sz; /* size of archive symbol table. */ size_t pm_sz; /* size of pseudo members */ size_t namelen; /* size of member name. */ size_t obj_sz; /* size of object + extended header. */ int i; char *buf; const char *entry_name; bsdar->rela_off = 0; /* * Create the archive symbol table and the archive string * table, if needed. */ TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { if (!(bsdar->options & AR_SS) && obj->elf != NULL) create_symtab_entry(bsdar, obj->elf); obj_sz = 0; namelen = strlen(obj->name); if (bsdar->options & AR_BSD) { /* Account for the space used by the file name. */ if (namelen > _MAXNAMELEN_BSD || strchr(obj->name, ' ')) obj_sz += namelen; } else if (namelen > _MAXNAMELEN_SVR4) add_to_ar_str_table(bsdar, obj->name); obj_sz += obj->size; /* add the actual object size */ /* Roundup the final size and add the header length. */ bsdar->rela_off += _ARHDR_LEN + obj_sz + (obj_sz & 1); } /* * Pad the symbol name string table. It is treated specially * because symbol name table should be padded by a '\0', and * not '\n' as for normal members. The size of the 'sn' table * includes the pad byte. */ if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0) bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; /* * The archive string table is padded by a "\n" like a normal * member. The difference is that the size of archive string * table includes the pad byte, while normal members' size * fields do not. */ if (bsdar->as != NULL && bsdar->as_sz % 2 != 0) bsdar->as[bsdar->as_sz++] = '\n'; /* * If there is a symbol table, calculate the size of pseudo * members, and convert previously stored relative offsets to * absolute ones. * * absolute_offset = relative_offset + size_of_pseudo_members) */ s_sz = bsdar_symtab_size(bsdar); if (bsdar->s_cnt != 0) { pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); if (bsdar->as != NULL) /* SVR4 archives only */ pm_sz += _ARHDR_LEN + bsdar->as_sz; for (i = 0; (size_t) i < bsdar->s_cnt; i++) bsdar->s_so[i] = bsdar->s_so[i] + pm_sz; } if ((a = archive_write_new()) == NULL) bsdar_errc(bsdar, 0, "archive_write_new failed"); if (bsdar->options & AR_BSD) archive_write_set_format_ar_bsd(a); else archive_write_set_format_ar_svr4(a); - archive_write_set_compression_none(a); AC(archive_write_open_filename(a, bsdar->filename)); /* * Write the archive symbol table, if there is one. If * options '-s' was explicitly specified or if we were invoked * as 'ranlib', write the symbol table even if it is empty. */ if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) || bsdar->options & AR_S) { if (bsdar->options & AR_BSD) entry_name = AR_SYMTAB_NAME_BSD; else entry_name = AR_SYMTAB_NAME_SVR4; entry = archive_entry_new(); archive_entry_copy_pathname(entry, entry_name); if ((bsdar->options & AR_D) == 0) archive_entry_set_mtime(entry, time(NULL), 0); archive_entry_set_size(entry, s_sz); AC(archive_write_header(a, entry)); if (bsdar->options & AR_BSD) write_bsd_symtab_entry(bsdar, a); else write_svr4_symtab_entry(bsdar, a); archive_entry_free(entry); } /* Write the archive string table, if any. */ if (bsdar->as != NULL) { entry = archive_entry_new(); archive_entry_copy_pathname(entry, AR_STRINGTAB_NAME_SVR4); archive_entry_set_size(entry, bsdar->as_sz); AC(archive_write_header(a, entry)); write_data(bsdar, a, bsdar->as, bsdar->as_sz); archive_entry_free(entry); } /* Write normal members. */ TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { if ((buf = elf_rawfile(obj->elf, NULL)) == NULL) { bsdar_warnc(bsdar, 0, "elf_rawfile() failed: %s", elf_errmsg(-1)); continue; } entry = archive_entry_new(); archive_entry_copy_pathname(entry, obj->name); archive_entry_set_uid(entry, obj->uid); archive_entry_set_gid(entry, obj->gid); archive_entry_set_mode(entry, obj->md); archive_entry_set_size(entry, obj->size); archive_entry_set_mtime(entry, obj->mtime, 0); archive_entry_set_dev(entry, obj->dev); archive_entry_set_ino(entry, obj->ino); archive_entry_set_filetype(entry, AE_IFREG); AC(archive_write_header(a, entry)); write_data(bsdar, a, buf, obj->size); archive_entry_free(entry); } AC(archive_write_close(a)); - ACV(archive_write_finish(a)); + ACV(archive_write_free(a)); } /* * Extract global symbols from ELF binary members. */ static void create_symtab_entry(struct bsdar *bsdar, Elf *e) { Elf_Scn *scn; GElf_Shdr shdr; GElf_Sym sym; Elf_Data *data; char *name; size_t n, shstrndx; int elferr, tabndx, len, i; if (elf_kind(e) != ELF_K_ELF) { /* Silently a ignore non-ELF member. */ return; } if (elf_getshstrndx(e, &shstrndx) == 0) { bsdar_warnc(bsdar, 0, "elf_getshstrndx failed: %s", elf_errmsg(-1)); return; } tabndx = -1; scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { bsdar_warnc(bsdar, 0, "elf_getshdr failed: %s", elf_errmsg(-1)); continue; } if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { bsdar_warnc(bsdar, 0, "elf_strptr failed: %s", elf_errmsg(-1)); continue; } if (strcmp(name, ".strtab") == 0) { tabndx = elf_ndxscn(scn); break; } } elferr = elf_errno(); if (elferr != 0) bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s", elf_errmsg(elferr)); if (tabndx == -1) { bsdar_warnc(bsdar, 0, "can't find .strtab section"); return; } scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { bsdar_warnc(bsdar, 0, "elf_getshdr failed: %s", elf_errmsg(-1)); continue; } if (shdr.sh_type != SHT_SYMTAB) continue; data = NULL; n = 0; while (n < shdr.sh_size && (data = elf_getdata(scn, data)) != NULL) { len = data->d_size / shdr.sh_entsize; for (i = 0; i < len; i++) { if (gelf_getsym(data, i, &sym) != &sym) { bsdar_warnc(bsdar, 0, "gelf_getsym failed: %s", elf_errmsg(-1)); continue; } /* Keep only global and weak symbols. */ if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && GELF_ST_BIND(sym.st_info) != STB_WEAK) continue; /* Keep only defined symbols. */ if (sym.st_shndx == SHN_UNDEF) continue; if ((name = elf_strptr(e, tabndx, sym.st_name)) == NULL) { bsdar_warnc(bsdar, 0, "elf_strptr failed: %s", elf_errmsg(-1)); continue; } add_to_ar_sym_table(bsdar, name); } } } elferr = elf_errno(); if (elferr != 0) bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s", elf_errmsg(elferr)); } /* * Append to the archive string table buffer. */ static void add_to_ar_str_table(struct bsdar *bsdar, const char *name) { if (bsdar->as == NULL) { bsdar->as_cap = _INIT_AS_CAP; bsdar->as_sz = 0; if ((bsdar->as = malloc(bsdar->as_cap)) == NULL) bsdar_errc(bsdar, errno, "malloc failed"); } /* * The space required for holding one member name in the 'as' * table includes: strlen(name) + (1 for '/') + (1 for '\n') + * (possibly 1 for padding). */ while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) { bsdar->as_cap *= 2; bsdar->as = realloc(bsdar->as, bsdar->as_cap); if (bsdar->as == NULL) bsdar_errc(bsdar, errno, "realloc failed"); } strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name)); bsdar->as_sz += strlen(name); bsdar->as[bsdar->as_sz++] = '/'; bsdar->as[bsdar->as_sz++] = '\n'; } /* * Append to the archive symbol table buffer. */ static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name) { if (bsdar->s_so == NULL) { if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL) bsdar_errc(bsdar, errno, "malloc failed"); bsdar->s_so_cap = _INIT_SYMOFF_CAP; bsdar->s_cnt = 0; } if (bsdar->s_sn == NULL) { if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) bsdar_errc(bsdar, errno, "malloc failed"); bsdar->s_sn_cap = _INIT_SYMNAME_CAP; bsdar->s_sn_sz = 0; } if (bsdar->s_cnt * sizeof(uint32_t) >= bsdar->s_so_cap) { bsdar->s_so_cap *= 2; bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap); if (bsdar->s_so == NULL) bsdar_errc(bsdar, errno, "realloc failed"); } bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off; bsdar->s_cnt++; /* * The space required for holding one symbol name in the 'sn' * table includes: strlen(name) + (1 for '\n') + (possibly 1 * for padding). */ while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) { bsdar->s_sn_cap *= 2; bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap); if (bsdar->s_sn == NULL) bsdar_errc(bsdar, errno, "realloc failed"); } strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name)); bsdar->s_sn_sz += strlen(name); bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; } diff --git a/brandelf/brandelf.1 b/brandelf/brandelf.1 index 5665b412bb41..5913360d87bd 100644 --- a/brandelf/brandelf.1 +++ b/brandelf/brandelf.1 @@ -1,149 +1,151 @@ .\" Copyright (c) 1997 .\" John-Mark Gurney. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the author nor the names of any co-contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY John-Mark Gurney AND CONTRIBUTORS ``AS IS'' .\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD: src/usr.bin/brandelf/brandelf.1,v 1.17 2007/03/09 14:36:18 ru Exp $ -.\" $Id: brandelf.1 2245 2011-11-29 08:11:00Z jkoshy $ +.\" $Id: brandelf.1 3101 2014-10-27 22:24:40Z jkoshy $ .\" -.Dd November 29, 2011 +.Dd October 27, 2014 .Dt BRANDELF 1 .Os .Sh NAME .Nm brandelf .Nd mark an ELF binary for a specific ABI .Sh SYNOPSIS .Nm .Op Fl V | Fl -version .Op Fl f Ar ELF_ABI_number .Op Fl h | Fl -help .Op Fl l .Op Fl t Ar brand .Op Fl v .Ar .Sh DESCRIPTION The .Nm utility marks an ELF binary to be run under a certain ABI. .Pp The options are as follows: .Bl -tag -width indent .It Fl f Ar ELF_ABI_number Forces branding with the supplied ELF ABI number. Incompatible with the .Fl t option. These values are assigned by SCO/USL. .It Fl h | Fl -help Print a usage message and exit. .It Fl l Writes the list of all known ELF types to standard output. .It Fl t Ar brand Brands the given ELF binaries to be of the ABI specified by argument .Ar brand . Supported ABIs include .Dq Li 86Open , .Dq Li AIX , .Dq Li ARM , .Dq Li AROS , .Dq Li FreeBSD , .Dq Li GNU , .Dq Li HP/UX , .Dq Li Hurd , .Dq Li IRIX , .Dq Li Linux (an alias for .Dq Li GNU ) , .Dq Li Modesto , .Dq Li NSK , .Dq Li NetBSD , .Dq Li None , .Dq Li OpenBSD , .Dq Li OpenVMS , .Dq Li Standalone , .Dq Li SVR4 (an alias for .Dq Li None ) , .Dq Li Solaris and .Dq Li Tru64 . .It Fl v -Turns on verbose output. +This option is accepted for compatibility with other versions of +.Nm , +but is otherwise ignored. .It Fl V | Fl -version Print a version identifier and exit. .El .Pp If the options .Fl f Ar ELF_ABI_number or .Fl t Ar brand were specified, .Nm will brand the files named by command-line arguments .Ar to be of type .Ar ELF_ABI_number or .Ar brand respectively. .Pp If neither of the .Fl f or .Fl t options were specified, .Nm will display the current branding for the files named by the arguments .Ar . .Sh EXIT STATUS Exit status is 0 on success, and 1 if the command fails if a file does not exist, is too short, fails to brand properly, or the brand requested is not one of the known types and the .Fl f option is not set. .Sh EXAMPLES The following is an example of a typical usage of the .Nm command: .Bd -literal -offset indent brandelf file brandelf -t GNU file .Ed .Sh SEE ALSO .Rs .%A The Santa Cruz Operation, Inc. .%T System V Application Binary Interface .%D April 29, 1998 (DRAFT) .%O http://www.sco.com/developer/devspecs/ .Re .Sh HISTORY The .Nm manual page first appeared in .Fx 2.2 . .Sh AUTHORS This manual page was written by .An John-Mark Gurney Aq gurney_j@efn.org . diff --git a/brandelf/brandelf.c b/brandelf/brandelf.c index fac218750ee7..286b6ab12359 100644 --- a/brandelf/brandelf.c +++ b/brandelf/brandelf.c @@ -1,314 +1,313 @@ /*- * Copyright (c) 2008 Hyogeol Lee * Copyright (c) 2000, 2001 David O'Brien * Copyright (c) 1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: brandelf.c 2324 2011-12-12 06:36:27Z jkoshy $"); +ELFTC_VCSID("$Id: brandelf.c 3101 2014-10-27 22:24:40Z jkoshy $"); static int elftype(const char *); static const char *iselftype(int); static void printelftypes(void); static void printversion(void); static void usage(void); struct ELFtypes { const char *str; int value; }; /* XXX - any more types? */ static struct ELFtypes elftypes[] = { { "86Open", ELFOSABI_86OPEN }, { "AIX", ELFOSABI_AIX }, { "ARM", ELFOSABI_ARM }, { "AROS", ELFOSABI_AROS }, { "FreeBSD", ELFOSABI_FREEBSD }, { "GNU", ELFOSABI_GNU }, { "HP/UX", ELFOSABI_HPUX}, { "Hurd", ELFOSABI_HURD }, { "IRIX", ELFOSABI_IRIX }, { "Linux", ELFOSABI_GNU }, { "Modesto", ELFOSABI_MODESTO }, { "NSK", ELFOSABI_NSK }, { "NetBSD", ELFOSABI_NETBSD}, { "None", ELFOSABI_NONE}, { "OpenBSD", ELFOSABI_OPENBSD }, { "OpenVMS", ELFOSABI_OPENVMS }, { "Standalone", ELFOSABI_STANDALONE }, { "SVR4", ELFOSABI_NONE }, { "Solaris", ELFOSABI_SOLARIS }, { "Tru64", ELFOSABI_TRU64 } }; static struct option brandelf_longopts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; int main(int argc, char **argv) { GElf_Ehdr ehdr; Elf *elf; Elf_Kind kind; int type = ELFOSABI_NONE; int retval = 0; - int ch, change = 0, verbose = 0, force = 0, listed = 0; + int ch, change = 0, force = 0, listed = 0; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "elf_version error"); while ((ch = getopt_long(argc, argv, "Vf:hlt:v", brandelf_longopts, NULL)) != -1) switch (ch) { case 'f': if (change) errx(EXIT_FAILURE, "ERROR: the -f option is " "incompatible with the -t option."); force = 1; type = atoi(optarg); if (errno == ERANGE || type < 0 || type > 255) { warnx("ERROR: invalid argument to option " "-f: %s", optarg); usage(); } break; case 'h': usage(); break; case 'l': printelftypes(); listed = 1; break; case 'v': - verbose = 1; + /* This flag is ignored. */ break; case 't': if (force) errx(EXIT_FAILURE, "the -t option is " "incompatible with the -f option."); if ((type = elftype(optarg)) == -1) { warnx("ERROR: invalid ELF type '%s'", optarg); usage(); } change = 1; break; case 'V': printversion(); break; default: usage(); } argc -= optind; argv += optind; if (!argc) { if (listed) exit(0); else { warnx("no file(s) specified"); usage(); } } while (argc) { int fd; elf = NULL; if ((fd = open(argv[0], (change || force) ? O_RDWR : O_RDONLY, 0)) < 0) { warn("error opening file %s", argv[0]); retval = 1; goto fail; } if ((elf = elf_begin(fd, (change || force) ? ELF_C_RDWR : ELF_C_READ, NULL)) == NULL) { warnx("elf_begin failed: %s", elf_errmsg(-1)); retval = 1; goto fail; } if ((kind = elf_kind(elf)) != ELF_K_ELF) { if (kind == ELF_K_AR) warnx("file '%s' is an archive.", argv[0]); else warnx("file '%s' is not an ELF file.", argv[0]); retval = 1; goto fail; } if (gelf_getehdr(elf, &ehdr) == NULL) { warnx("gelf_getehdr: %s", elf_errmsg(-1)); retval = 1; goto fail; } if (!change && !force) { fprintf(stdout, "File '%s' is of brand '%s' (%u).\n", argv[0], iselftype(ehdr.e_ident[EI_OSABI]), ehdr.e_ident[EI_OSABI]); if (!iselftype(type)) { warnx("ELF ABI Brand '%u' is unknown", type); printelftypes(); } } else { /* * Keep the existing layout of the ELF object. */ if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0) { warnx("elf_flagelf failed: %s", elf_errmsg(-1)); retval = 1; goto fail; } /* * Update the ABI type. */ ehdr.e_ident[EI_OSABI] = type; if (gelf_update_ehdr(elf, &ehdr) == 0) { warnx("gelf_update_ehdr error: %s", elf_errmsg(-1)); retval = 1; goto fail; } /* * Write back changes. */ if (elf_update(elf, ELF_C_WRITE) == -1) { warnx("elf_update error: %s", elf_errmsg(-1)); retval = 1; goto fail; } } fail: if (elf) elf_end(elf); if (fd >= 0 && close(fd) == -1) { warnx("%s: close error", argv[0]); retval = 1; } argc--; argv++; } return (retval); } #define USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Set or display the ABI field for an ELF object.\n\n\ Supported options are:\n\ -f NUM Set the ELF ABI to the number 'NUM'.\n\ -h | --help Print a usage message and exit.\n\ -l List known ELF ABI names.\n\ -t ABI Set the ELF ABI to the value named by \"ABI\".\n\ - -v Be verbose.\n\ -V | --version Print a version identifier and exit.\n" static void usage(void) { (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(1); } static void printversion(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(0); } static const char * iselftype(int etype) { size_t elfwalk; for (elfwalk = 0; elfwalk < sizeof(elftypes)/sizeof(elftypes[0]); elfwalk++) if (etype == elftypes[elfwalk].value) return (elftypes[elfwalk].str); return (0); } static int elftype(const char *elfstrtype) { size_t elfwalk; for (elfwalk = 0; elfwalk < sizeof(elftypes)/sizeof(elftypes[0]); elfwalk++) if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0) return (elftypes[elfwalk].value); return (-1); } static void printelftypes(void) { size_t elfwalk; (void) printf("Known ELF types are: "); for (elfwalk = 0; elfwalk < sizeof(elftypes)/sizeof(elftypes[0]); elfwalk++) (void) printf("%s(%u) ", elftypes[elfwalk].str, elftypes[elfwalk].value); (void) printf("\n"); } diff --git a/common/Makefile b/common/Makefile index d3df246e78fc..9551bcd20f34 100644 --- a/common/Makefile +++ b/common/Makefile @@ -1,15 +1,18 @@ -# $Id: Makefile 2606 2012-10-02 17:52:57Z jkoshy $ +# $Id: Makefile 3022 2014-04-17 18:05:58Z jkoshy $ TOP= .. INCS= elfdefinitions.h INCSDIR= /usr/include .PHONY: all clean clobber depend obj all depend obj: clean clobber: rm -f ${CLEANFILES} +cleandepend: + rm -f .depend + .include "${TOP}/mk/elftoolchain.inc.mk" diff --git a/common/elfdefinitions.h b/common/elfdefinitions.h index 7bed9a19a0dc..f63dc7f2178d 100644 --- a/common/elfdefinitions.h +++ b/common/elfdefinitions.h @@ -1,2614 +1,2617 @@ /*- * Copyright (c) 2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: elfdefinitions.h 2950 2013-06-15 13:36:02Z jkoshy $ + * $Id: elfdefinitions.h 3110 2014-12-20 08:32:46Z kaiwang27 $ */ /* * These definitions are based on: * - The public specification of the ELF format as defined in the * October 2009 draft of System V ABI. * See: http://www.sco.com/developers/gabi/latest/ch4.intro.html * - The May 1998 (version 1.5) draft of "The ELF-64 object format". * - Processor-specific ELF ABI definitions for sparc, i386, amd64, mips, * ia64, and powerpc processors. * - The "Linkers and Libraries Guide", from Sun Microsystems. */ #ifndef _ELFDEFINITIONS_H_ #define _ELFDEFINITIONS_H_ #include /* * Types of capabilities. */ #define _ELF_DEFINE_CAPABILITIES() \ _ELF_DEFINE_CA(CA_SUNW_NULL, 0, "ignored") \ _ELF_DEFINE_CA(CA_SUNW_HW_1, 1, "hardware capability") \ _ELF_DEFINE_CA(CA_SUNW_SW_1, 2, "software capability") #undef _ELF_DEFINE_CA #define _ELF_DEFINE_CA(N, V, DESCR) N = V , enum { _ELF_DEFINE_CAPABILITIES() CA__LAST__ }; /* * Flags used with dynamic linking entries. */ #define _ELF_DEFINE_DYN_FLAGS() \ _ELF_DEFINE_DF(DF_ORIGIN, 0x1, \ "object being loaded may refer to $ORIGIN") \ _ELF_DEFINE_DF(DF_SYMBOLIC, 0x2, \ "search library for references before executable") \ _ELF_DEFINE_DF(DF_TEXTREL, 0x4, \ "relocation entries may modify text segment") \ _ELF_DEFINE_DF(DF_BIND_NOW, 0x8, \ "process relocation entries at load time") \ _ELF_DEFINE_DF(DF_STATIC_TLS, 0x10, \ "uses static thread-local storage") #undef _ELF_DEFINE_DF #define _ELF_DEFINE_DF(N, V, DESCR) N = V , enum { _ELF_DEFINE_DYN_FLAGS() DF__LAST__ }; /* * Dynamic linking entry types. */ #define _ELF_DEFINE_DYN_TYPES() \ _ELF_DEFINE_DT(DT_NULL, 0, "end of array") \ _ELF_DEFINE_DT(DT_NEEDED, 1, "names a needed library") \ _ELF_DEFINE_DT(DT_PLTRELSZ, 2, \ "size in bytes of associated relocation entries") \ _ELF_DEFINE_DT(DT_PLTGOT, 3, \ "address associated with the procedure linkage table") \ _ELF_DEFINE_DT(DT_HASH, 4, \ "address of the symbol hash table") \ _ELF_DEFINE_DT(DT_STRTAB, 5, \ "address of the string table") \ _ELF_DEFINE_DT(DT_SYMTAB, 6, \ "address of the symbol table") \ _ELF_DEFINE_DT(DT_RELA, 7, \ "address of the relocation table") \ _ELF_DEFINE_DT(DT_RELASZ, 8, "size of the DT_RELA table") \ _ELF_DEFINE_DT(DT_RELAENT, 9, "size of each DT_RELA entry") \ _ELF_DEFINE_DT(DT_STRSZ, 10, "size of the string table") \ _ELF_DEFINE_DT(DT_SYMENT, 11, \ "size of a symbol table entry") \ _ELF_DEFINE_DT(DT_INIT, 12, \ "address of the initialization function") \ _ELF_DEFINE_DT(DT_FINI, 13, \ "address of the finalization function") \ _ELF_DEFINE_DT(DT_SONAME, 14, "names the shared object") \ _ELF_DEFINE_DT(DT_RPATH, 15, \ "runtime library search path") \ _ELF_DEFINE_DT(DT_SYMBOLIC, 16, \ "alter symbol resolution algorithm") \ _ELF_DEFINE_DT(DT_REL, 17, \ "address of the DT_REL table") \ _ELF_DEFINE_DT(DT_RELSZ, 18, "size of the DT_REL table") \ _ELF_DEFINE_DT(DT_RELENT, 19, "size of each DT_REL entry") \ _ELF_DEFINE_DT(DT_PLTREL, 20, \ "type of relocation entry in the procedure linkage table") \ _ELF_DEFINE_DT(DT_DEBUG, 21, "used for debugging") \ _ELF_DEFINE_DT(DT_TEXTREL, 22, \ "text segment may be written to during relocation") \ _ELF_DEFINE_DT(DT_JMPREL, 23, \ "address of relocation entries associated with the procedure linkage table") \ _ELF_DEFINE_DT(DT_BIND_NOW, 24, \ "bind symbols at loading time") \ _ELF_DEFINE_DT(DT_INIT_ARRAY, 25, \ "pointers to initialization functions") \ _ELF_DEFINE_DT(DT_FINI_ARRAY, 26, \ "pointers to termination functions") \ _ELF_DEFINE_DT(DT_INIT_ARRAYSZ, 27, "size of the DT_INIT_ARRAY") \ _ELF_DEFINE_DT(DT_FINI_ARRAYSZ, 28, "size of the DT_FINI_ARRAY") \ _ELF_DEFINE_DT(DT_RUNPATH, 29, \ "index of library search path string") \ _ELF_DEFINE_DT(DT_FLAGS, 30, \ "flags specific to the object being loaded") \ _ELF_DEFINE_DT(DT_ENCODING, 32, "standard semantics") \ _ELF_DEFINE_DT(DT_PREINIT_ARRAY, 32, \ "pointers to pre-initialization functions") \ _ELF_DEFINE_DT(DT_PREINIT_ARRAYSZ, 33, \ "size of pre-initialization array") \ _ELF_DEFINE_DT(DT_MAXPOSTAGS, 34, \ "the number of positive tags") \ _ELF_DEFINE_DT(DT_LOOS, 0x6000000DUL, \ "start of OS-specific types") \ _ELF_DEFINE_DT(DT_SUNW_AUXILIARY, 0x6000000DUL, \ "offset of string naming auxiliary filtees") \ _ELF_DEFINE_DT(DT_SUNW_RTLDINF, 0x6000000EUL, "rtld internal use") \ _ELF_DEFINE_DT(DT_SUNW_FILTER, 0x6000000FUL, \ "offset of string naming standard filtees") \ _ELF_DEFINE_DT(DT_SUNW_CAP, 0x60000010UL, \ "address of hardware capabilities section") \ _ELF_DEFINE_DT(DT_HIOS, 0x6FFFF000UL, \ "end of OS-specific types") \ _ELF_DEFINE_DT(DT_VALRNGLO, 0x6FFFFD00UL, \ "start of range using the d_val field") \ _ELF_DEFINE_DT(DT_GNU_PRELINKED, 0x6FFFFDF5UL, \ "prelinking timestamp") \ _ELF_DEFINE_DT(DT_GNU_CONFLICTSZ, 0x6FFFFDF6UL, \ "size of conflict section") \ _ELF_DEFINE_DT(DT_GNU_LIBLISTSZ, 0x6FFFFDF7UL, \ "size of library list") \ _ELF_DEFINE_DT(DT_CHECKSUM, 0x6FFFFDF8UL, \ "checksum for the object") \ _ELF_DEFINE_DT(DT_PLTPADSZ, 0x6FFFFDF9UL, \ "size of PLT padding") \ _ELF_DEFINE_DT(DT_MOVEENT, 0x6FFFFDFAUL, \ "size of DT_MOVETAB entries") \ _ELF_DEFINE_DT(DT_MOVESZ, 0x6FFFFDFBUL, \ "total size of the MOVETAB table") \ _ELF_DEFINE_DT(DT_FEATURE_1, 0x6FFFFDFCUL, "feature values") \ _ELF_DEFINE_DT(DT_POSFLAG_1, 0x6FFFFDFDUL, \ "dynamic position flags") \ _ELF_DEFINE_DT(DT_SYMINSZ, 0x6FFFFDFEUL, \ "size of the DT_SYMINFO table") \ _ELF_DEFINE_DT(DT_SYMINENT, 0x6FFFFDFFUL, \ "size of a DT_SYMINFO entry") \ _ELF_DEFINE_DT(DT_VALRNGHI, 0x6FFFFDFFUL, \ "end of range using the d_val field") \ _ELF_DEFINE_DT(DT_ADDRRNGLO, 0x6FFFFE00UL, \ "start of range using the d_ptr field") \ _ELF_DEFINE_DT(DT_GNU_HASH, 0x6FFFFEF5UL, \ "GNU style hash tables") \ _ELF_DEFINE_DT(DT_GNU_CONFLICT, 0x6FFFFEF8UL, \ "address of conflict section") \ _ELF_DEFINE_DT(DT_GNU_LIBLIST, 0x6FFFFEF9UL, \ "address of conflict section") \ _ELF_DEFINE_DT(DT_CONFIG, 0x6FFFFEFAUL, \ "configuration file") \ _ELF_DEFINE_DT(DT_DEPAUDIT, 0x6FFFFEFBUL, \ "string defining audit libraries") \ _ELF_DEFINE_DT(DT_AUDIT, 0x6FFFFEFCUL, \ "string defining audit libraries") \ _ELF_DEFINE_DT(DT_PLTPAD, 0x6FFFFEFDUL, "PLT padding") \ _ELF_DEFINE_DT(DT_MOVETAB, 0x6FFFFEFEUL, \ "address of a move table") \ _ELF_DEFINE_DT(DT_SYMINFO, 0x6FFFFEFFUL, \ "address of the symbol information table") \ _ELF_DEFINE_DT(DT_ADDRRNGHI, 0x6FFFFEFFUL, \ "end of range using the d_ptr field") \ _ELF_DEFINE_DT(DT_VERSYM, 0x6FFFFFF0UL, \ "address of the version section") \ _ELF_DEFINE_DT(DT_RELACOUNT, 0x6FFFFFF9UL, \ "count of RELA relocations") \ _ELF_DEFINE_DT(DT_RELCOUNT, 0x6FFFFFFAUL, \ "count of REL relocations") \ _ELF_DEFINE_DT(DT_FLAGS_1, 0x6FFFFFFBUL, "flag values") \ _ELF_DEFINE_DT(DT_VERDEF, 0x6FFFFFFCUL, \ "address of the version definition segment") \ _ELF_DEFINE_DT(DT_VERDEFNUM, 0x6FFFFFFDUL, \ "the number of version definition entries") \ _ELF_DEFINE_DT(DT_VERNEED, 0x6FFFFFFEUL, \ "address of section with needed versions") \ _ELF_DEFINE_DT(DT_VERNEEDNUM, 0x6FFFFFFFUL, \ "the number of version needed entries") \ _ELF_DEFINE_DT(DT_LOPROC, 0x70000000UL, \ "start of processor-specific types") \ _ELF_DEFINE_DT(DT_ARM_SYMTABSZ, 0x70000001UL, \ "number of entries in the dynamic symbol table") \ _ELF_DEFINE_DT(DT_SPARC_REGISTER, 0x70000001UL, \ "index of an STT_SPARC_REGISTER symbol") \ _ELF_DEFINE_DT(DT_ARM_PREEMPTMAP, 0x70000002UL, \ "address of the preemption map") \ _ELF_DEFINE_DT(DT_MIPS_RLD_VERSION, 0x70000001UL, \ "version ID for runtime linker interface") \ _ELF_DEFINE_DT(DT_MIPS_TIME_STAMP, 0x70000002UL, \ "timestamp") \ _ELF_DEFINE_DT(DT_MIPS_ICHECKSUM, 0x70000003UL, \ "checksum of all external strings and common sizes") \ _ELF_DEFINE_DT(DT_MIPS_IVERSION, 0x70000004UL, \ "string table index of a version string") \ _ELF_DEFINE_DT(DT_MIPS_FLAGS, 0x70000005UL, \ "MIPS-specific flags") \ _ELF_DEFINE_DT(DT_MIPS_BASE_ADDRESS, 0x70000006UL, \ "base address for the executable/DSO") \ _ELF_DEFINE_DT(DT_MIPS_CONFLICT, 0x70000008UL, \ "address of .conflict section") \ _ELF_DEFINE_DT(DT_MIPS_LIBLIST, 0x70000009UL, \ "address of .liblist section") \ _ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTNO, 0x7000000AUL, \ "number of local GOT entries") \ _ELF_DEFINE_DT(DT_MIPS_CONFLICTNO, 0x7000000BUL, \ "number of entries in the .conflict section") \ _ELF_DEFINE_DT(DT_MIPS_LIBLISTNO, 0x70000010UL, \ "number of entries in the .liblist section") \ _ELF_DEFINE_DT(DT_MIPS_SYMTABNO, 0x70000011UL, \ "number of entries in the .dynsym section") \ _ELF_DEFINE_DT(DT_MIPS_UNREFEXTNO, 0x70000012UL, \ "index of first external dynamic symbol not ref'ed locally") \ _ELF_DEFINE_DT(DT_MIPS_GOTSYM, 0x70000013UL, \ "index of first dynamic symbol corresponds to a GOT entry") \ _ELF_DEFINE_DT(DT_MIPS_HIPAGENO, 0x70000014UL, \ "number of page table entries in GOT") \ _ELF_DEFINE_DT(DT_MIPS_RLD_MAP, 0x70000016UL, \ "address of runtime linker map") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS, 0x70000017UL, \ "Delta C++ class definition") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS_NO, 0x70000018UL, \ "number of entries in DT_MIPS_DELTA_CLASS") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE, 0x70000019UL, \ "Delta C++ class instances") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE_NO, 0x7000001AUL, \ "number of entries in DT_MIPS_DELTA_INSTANCE") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC, 0x7000001BUL, \ "Delta relocations") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC_NO, 0x7000001CUL, \ "number of entries in DT_MIPS_DELTA_RELOC") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_SYM, 0x7000001DUL, \ "Delta symbols refered by Delta relocations") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_SYM_NO, 0x7000001EUL, \ "number of entries in DT_MIPS_DELTA_SYM") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM, 0x70000020UL, \ "Delta symbols for class declarations") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM_NO, 0x70000021UL, \ "number of entries in DT_MIPS_DELTA_CLASSSYM") \ _ELF_DEFINE_DT(DT_MIPS_CXX_FLAGS, 0x70000022UL, \ "C++ flavor flags") \ _ELF_DEFINE_DT(DT_MIPS_PIXIE_INIT, 0x70000023UL, \ "address of an initialization routine created by pixie") \ _ELF_DEFINE_DT(DT_MIPS_SYMBOL_LIB, 0x70000024UL, \ "address of .MIPS.symlib section") \ _ELF_DEFINE_DT(DT_MIPS_LOCALPAGE_GOTIDX, 0x70000025UL, \ "GOT index of first page table entry for a segment") \ _ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTIDX, 0x70000026UL, \ "GOT index of first page table entry for a local symbol") \ _ELF_DEFINE_DT(DT_MIPS_HIDDEN_GOTIDX, 0x70000027UL, \ "GOT index of first page table entry for a hidden symbol") \ _ELF_DEFINE_DT(DT_MIPS_PROTECTED_GOTIDX, 0x70000028UL, \ "GOT index of first page table entry for a protected symbol") \ _ELF_DEFINE_DT(DT_MIPS_OPTIONS, 0x70000029UL, \ "address of .MIPS.options section") \ _ELF_DEFINE_DT(DT_MIPS_INTERFACE, 0x7000002AUL, \ "address of .MIPS.interface section") \ _ELF_DEFINE_DT(DT_MIPS_DYNSTR_ALIGN, 0x7000002BUL, "???") \ _ELF_DEFINE_DT(DT_MIPS_INTERFACE_SIZE, 0x7000002CUL, \ "size of .MIPS.interface section") \ _ELF_DEFINE_DT(DT_MIPS_RLD_TEXT_RESOLVE_ADDR, 0x7000002DUL, \ "address of _rld_text_resolve in GOT") \ _ELF_DEFINE_DT(DT_MIPS_PERF_SUFFIX, 0x7000002EUL, \ "default suffix of DSO to be appended by dlopen") \ _ELF_DEFINE_DT(DT_MIPS_COMPACT_SIZE, 0x7000002FUL, \ "size of a ucode compact relocation record (o32)") \ _ELF_DEFINE_DT(DT_MIPS_GP_VALUE, 0x70000030UL, \ "GP value of a specified GP relative range") \ _ELF_DEFINE_DT(DT_MIPS_AUX_DYNAMIC, 0x70000031UL, \ "address of an auxiliary dynamic table") \ _ELF_DEFINE_DT(DT_MIPS_PLTGOT, 0x70000032UL, \ "address of the PLTGOT") \ _ELF_DEFINE_DT(DT_MIPS_RLD_OBJ_UPDATE, 0x70000033UL, \ "object list update callback") \ _ELF_DEFINE_DT(DT_MIPS_RWPLT, 0x70000034UL, \ "address of a writable PLT") \ _ELF_DEFINE_DT(DT_PPC_GOT, 0x70000000UL, \ "value of _GLOBAL_OFFSET_TABLE_") \ _ELF_DEFINE_DT(DT_PPC_TLSOPT, 0x70000001UL, \ "TLS descriptor should be optimized") \ _ELF_DEFINE_DT(DT_PPC64_GLINK, 0x70000000UL, \ "address of .glink section") \ _ELF_DEFINE_DT(DT_PPC64_OPD, 0x70000001UL, \ "address of .opd section") \ _ELF_DEFINE_DT(DT_PPC64_OPDSZ, 0x70000002UL, \ "size of .opd section") \ _ELF_DEFINE_DT(DT_PPC64_TLSOPT, 0x70000003UL, \ "TLS descriptor should be optimized") \ _ELF_DEFINE_DT(DT_AUXILIARY, 0x7FFFFFFDUL, \ "offset of string naming auxiliary filtees") \ _ELF_DEFINE_DT(DT_USED, 0x7FFFFFFEUL, "ignored") \ _ELF_DEFINE_DT(DT_FILTER, 0x7FFFFFFFUL, \ "index of string naming filtees") \ _ELF_DEFINE_DT(DT_HIPROC, 0x7FFFFFFFUL, \ "end of processor-specific types") #undef _ELF_DEFINE_DT #define _ELF_DEFINE_DT(N, V, DESCR) N = V , enum { _ELF_DEFINE_DYN_TYPES() DT__LAST__ = DT_HIPROC }; #define DT_DEPRECATED_SPARC_REGISTER DT_SPARC_REGISTER /* * Flags used in the executable header (field: e_flags). */ #define _ELF_DEFINE_EHDR_FLAGS() \ _ELF_DEFINE_EF(EF_ARM_RELEXEC, 0x00000001UL, \ "dynamic segment describes only how to relocate segments") \ _ELF_DEFINE_EF(EF_ARM_HASENTRY, 0x00000002UL, \ "e_entry contains a program entry point") \ _ELF_DEFINE_EF(EF_ARM_SYMSARESORTED, 0x00000004UL, \ "subsection of symbol table is sorted by symbol value") \ _ELF_DEFINE_EF(EF_ARM_DYNSYMSUSESEGIDX, 0x00000008UL, \ "dynamic symbol st_shndx = containing segment index + 1") \ _ELF_DEFINE_EF(EF_ARM_MAPSYMSFIRST, 0x00000010UL, \ "mapping symbols precede other local symbols in symtab") \ _ELF_DEFINE_EF(EF_ARM_BE8, 0x00800000UL, \ "file contains BE-8 code") \ _ELF_DEFINE_EF(EF_ARM_LE8, 0x00400000UL, \ "file contains LE-8 code") \ _ELF_DEFINE_EF(EF_ARM_EABIMASK, 0xFF000000UL, \ "mask for ARM EABI version number (0 denotes GNU or unknown)") \ _ELF_DEFINE_EF(EF_ARM_EABI_UNKNOWN, 0x00000000UL, \ "Unknown or GNU ARM EABI version number") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER1, 0x01000000UL, \ "ARM EABI version 1") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER2, 0x02000000UL, \ "ARM EABI version 2") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER3, 0x03000000UL, \ "ARM EABI version 3") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER4, 0x04000000UL, \ "ARM EABI version 4") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER5, 0x05000000UL, \ "ARM EABI version 5") \ _ELF_DEFINE_EF(EF_ARM_INTERWORK, 0x00000004UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_APCS_26, 0x00000008UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_APCS_FLOAT, 0x00000010UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_PIC, 0x00000020UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_ALIGN8, 0x00000040UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_NEW_ABI, 0x00000080UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_OLD_ABI, 0x00000100UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_SOFT_FLOAT, 0x00000200UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_VFP_FLOAT, 0x00000400UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_MAVERICK_FLOAT, 0x00000800UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_MIPS_NOREORDER, 0x00000001UL, \ "at least one .noreorder directive appeared in the source") \ _ELF_DEFINE_EF(EF_MIPS_PIC, 0x00000002UL, \ "file contains position independent code") \ _ELF_DEFINE_EF(EF_MIPS_CPIC, 0x00000004UL, \ "file's code uses standard conventions for calling PIC") \ _ELF_DEFINE_EF(EF_MIPS_UCODE, 0x00000010UL, \ "file contains UCODE (obsolete)") \ _ELF_DEFINE_EF(EF_MIPS_ABI2, 0x00000020UL, \ "file follows MIPS III 32-bit ABI") \ _ELF_DEFINE_EF(EF_MIPS_OPTIONS_FIRST, 0x00000080UL, \ "ld(1) should process .MIPS.options section first") \ _ELF_DEFINE_EF(EF_MIPS_ARCH_ASE, 0x0F000000UL, \ "file uses application-specific architectural extensions") \ _ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_MDMX, 0x08000000UL, \ "file uses MDMX multimedia extensions") \ _ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_M16, 0x04000000UL, \ "file uses MIPS-16 ISA extensions") \ _ELF_DEFINE_EF(EF_MIPS_ARCH, 0xF0000000UL, \ "4-bit MIPS architecture field") \ _ELF_DEFINE_EF(EF_PPC_EMB, 0x80000000UL, \ "Embedded PowerPC flag") \ _ELF_DEFINE_EF(EF_PPC_RELOCATABLE, 0x00010000UL, \ "-mrelocatable flag") \ _ELF_DEFINE_EF(EF_PPC_RELOCATABLE_LIB, 0x00008000UL, \ "-mrelocatable-lib flag") \ _ELF_DEFINE_EF(EF_SPARC_EXT_MASK, 0x00ffff00UL, \ "Vendor Extension mask") \ _ELF_DEFINE_EF(EF_SPARC_32PLUS, 0x00000100UL, \ "Generic V8+ features") \ _ELF_DEFINE_EF(EF_SPARC_SUN_US1, 0x00000200UL, \ "Sun UltraSPARCTM 1 Extensions") \ _ELF_DEFINE_EF(EF_SPARC_HAL_R1, 0x00000400UL, "HAL R1 Extensions") \ _ELF_DEFINE_EF(EF_SPARC_SUN_US3, 0x00000800UL, \ "Sun UltraSPARC 3 Extensions") \ _ELF_DEFINE_EF(EF_SPARCV9_MM, 0x00000003UL, \ "Mask for Memory Model") \ _ELF_DEFINE_EF(EF_SPARCV9_TSO, 0x00000000UL, \ "Total Store Ordering") \ _ELF_DEFINE_EF(EF_SPARCV9_PSO, 0x00000001UL, \ "Partial Store Ordering") \ _ELF_DEFINE_EF(EF_SPARCV9_RMO, 0x00000002UL, \ "Relaxed Memory Ordering") #undef _ELF_DEFINE_EF #define _ELF_DEFINE_EF(N, V, DESCR) N = V , enum { _ELF_DEFINE_EHDR_FLAGS() EF__LAST__ }; /* * Offsets in the `ei_ident[]` field of an ELF executable header. */ #define _ELF_DEFINE_EI_OFFSETS() \ _ELF_DEFINE_EI(EI_MAG0, 0, "magic number") \ _ELF_DEFINE_EI(EI_MAG1, 1, "magic number") \ _ELF_DEFINE_EI(EI_MAG2, 2, "magic number") \ _ELF_DEFINE_EI(EI_MAG3, 3, "magic number") \ _ELF_DEFINE_EI(EI_CLASS, 4, "file class") \ _ELF_DEFINE_EI(EI_DATA, 5, "data encoding") \ _ELF_DEFINE_EI(EI_VERSION, 6, "file version") \ _ELF_DEFINE_EI(EI_OSABI, 7, "OS ABI kind") \ _ELF_DEFINE_EI(EI_ABIVERSION, 8, "OS ABI version") \ _ELF_DEFINE_EI(EI_PAD, 9, "padding start") \ _ELF_DEFINE_EI(EI_NIDENT, 16, "total size") #undef _ELF_DEFINE_EI #define _ELF_DEFINE_EI(N, V, DESCR) N = V , enum { _ELF_DEFINE_EI_OFFSETS() EI__LAST__ }; /* * The ELF class of an object. */ #define _ELF_DEFINE_ELFCLASS() \ _ELF_DEFINE_EC(ELFCLASSNONE, 0, "Unknown ELF class") \ _ELF_DEFINE_EC(ELFCLASS32, 1, "32 bit objects") \ _ELF_DEFINE_EC(ELFCLASS64, 2, "64 bit objects") #undef _ELF_DEFINE_EC #define _ELF_DEFINE_EC(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELFCLASS() EC__LAST__ }; /* * Endianness of data in an ELF object. */ #define _ELF_DEFINE_ELF_DATA_ENDIANNESS() \ _ELF_DEFINE_ED(ELFDATANONE, 0, "Unknown data endianness") \ _ELF_DEFINE_ED(ELFDATA2LSB, 1, "little endian") \ _ELF_DEFINE_ED(ELFDATA2MSB, 2, "big endian") #undef _ELF_DEFINE_ED #define _ELF_DEFINE_ED(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_DATA_ENDIANNESS() ED__LAST__ }; /* * Values of the magic numbers used in identification array. */ #define _ELF_DEFINE_ELF_MAGIC() \ _ELF_DEFINE_EMAG(ELFMAG0, 0x7FU) \ _ELF_DEFINE_EMAG(ELFMAG1, 'E') \ _ELF_DEFINE_EMAG(ELFMAG2, 'L') \ _ELF_DEFINE_EMAG(ELFMAG3, 'F') #undef _ELF_DEFINE_EMAG #define _ELF_DEFINE_EMAG(N, V) N = V , enum { _ELF_DEFINE_ELF_MAGIC() ELFMAG__LAST__ }; /* * ELF OS ABI field. */ #define _ELF_DEFINE_ELF_OSABI() \ _ELF_DEFINE_EABI(ELFOSABI_NONE, 0, \ "No extensions or unspecified") \ _ELF_DEFINE_EABI(ELFOSABI_SYSV, 0, "SYSV") \ _ELF_DEFINE_EABI(ELFOSABI_HPUX, 1, "Hewlett-Packard HP-UX") \ _ELF_DEFINE_EABI(ELFOSABI_NETBSD, 2, "NetBSD") \ _ELF_DEFINE_EABI(ELFOSABI_GNU, 3, "GNU") \ _ELF_DEFINE_EABI(ELFOSABI_HURD, 4, "GNU/HURD") \ _ELF_DEFINE_EABI(ELFOSABI_86OPEN, 5, "86Open Common ABI") \ _ELF_DEFINE_EABI(ELFOSABI_SOLARIS, 6, "Sun Solaris") \ _ELF_DEFINE_EABI(ELFOSABI_AIX, 7, "AIX") \ _ELF_DEFINE_EABI(ELFOSABI_IRIX, 8, "IRIX") \ _ELF_DEFINE_EABI(ELFOSABI_FREEBSD, 9, "FreeBSD") \ _ELF_DEFINE_EABI(ELFOSABI_TRU64, 10, "Compaq TRU64 UNIX") \ _ELF_DEFINE_EABI(ELFOSABI_MODESTO, 11, "Novell Modesto") \ _ELF_DEFINE_EABI(ELFOSABI_OPENBSD, 12, "Open BSD") \ _ELF_DEFINE_EABI(ELFOSABI_OPENVMS, 13, "Open VMS") \ _ELF_DEFINE_EABI(ELFOSABI_NSK, 14, \ "Hewlett-Packard Non-Stop Kernel") \ _ELF_DEFINE_EABI(ELFOSABI_AROS, 15, "Amiga Research OS") \ _ELF_DEFINE_EABI(ELFOSABI_FENIXOS, 16, \ "The FenixOS highly scalable multi-core OS") \ _ELF_DEFINE_EABI(ELFOSABI_ARM_AEABI, 64, \ "ARM specific symbol versioning extensions") \ _ELF_DEFINE_EABI(ELFOSABI_ARM, 97, "ARM ABI") \ _ELF_DEFINE_EABI(ELFOSABI_STANDALONE, 255, \ "Standalone (embedded) application") #undef _ELF_DEFINE_EABI #define _ELF_DEFINE_EABI(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_OSABI() ELFOSABI__LAST__ }; #define ELFOSABI_LINUX ELFOSABI_GNU /* * ELF Machine types: (EM_*). */ #define _ELF_DEFINE_ELF_MACHINES() \ _ELF_DEFINE_EM(EM_NONE, 0, "No machine") \ _ELF_DEFINE_EM(EM_M32, 1, "AT&T WE 32100") \ _ELF_DEFINE_EM(EM_SPARC, 2, "SPARC") \ _ELF_DEFINE_EM(EM_386, 3, "Intel 80386") \ _ELF_DEFINE_EM(EM_68K, 4, "Motorola 68000") \ _ELF_DEFINE_EM(EM_88K, 5, "Motorola 88000") \ _ELF_DEFINE_EM(EM_860, 7, "Intel 80860") \ _ELF_DEFINE_EM(EM_MIPS, 8, "MIPS I Architecture") \ _ELF_DEFINE_EM(EM_S370, 9, "IBM System/370 Processor") \ _ELF_DEFINE_EM(EM_MIPS_RS3_LE, 10, "MIPS RS3000 Little-endian") \ _ELF_DEFINE_EM(EM_PARISC, 15, "Hewlett-Packard PA-RISC") \ _ELF_DEFINE_EM(EM_VPP500, 17, "Fujitsu VPP500") \ _ELF_DEFINE_EM(EM_SPARC32PLUS, 18, \ "Enhanced instruction set SPARC") \ _ELF_DEFINE_EM(EM_960, 19, "Intel 80960") \ _ELF_DEFINE_EM(EM_PPC, 20, "PowerPC") \ _ELF_DEFINE_EM(EM_PPC64, 21, "64-bit PowerPC") \ _ELF_DEFINE_EM(EM_S390, 22, "IBM System/390 Processor") \ _ELF_DEFINE_EM(EM_SPU, 23, "IBM SPU/SPC") \ _ELF_DEFINE_EM(EM_V800, 36, "NEC V800") \ _ELF_DEFINE_EM(EM_FR20, 37, "Fujitsu FR20") \ _ELF_DEFINE_EM(EM_RH32, 38, "TRW RH-32") \ _ELF_DEFINE_EM(EM_RCE, 39, "Motorola RCE") \ _ELF_DEFINE_EM(EM_ARM, 40, "Advanced RISC Machines ARM") \ _ELF_DEFINE_EM(EM_ALPHA, 41, "Digital Alpha") \ _ELF_DEFINE_EM(EM_SH, 42, "Hitachi SH") \ _ELF_DEFINE_EM(EM_SPARCV9, 43, "SPARC Version 9") \ _ELF_DEFINE_EM(EM_TRICORE, 44, \ "Siemens TriCore embedded processor") \ _ELF_DEFINE_EM(EM_ARC, 45, \ "Argonaut RISC Core, Argonaut Technologies Inc.") \ _ELF_DEFINE_EM(EM_H8_300, 46, "Hitachi H8/300") \ _ELF_DEFINE_EM(EM_H8_300H, 47, "Hitachi H8/300H") \ _ELF_DEFINE_EM(EM_H8S, 48, "Hitachi H8S") \ _ELF_DEFINE_EM(EM_H8_500, 49, "Hitachi H8/500") \ _ELF_DEFINE_EM(EM_IA_64, 50, \ "Intel IA-64 processor architecture") \ _ELF_DEFINE_EM(EM_MIPS_X, 51, "Stanford MIPS-X") \ _ELF_DEFINE_EM(EM_COLDFIRE, 52, "Motorola ColdFire") \ _ELF_DEFINE_EM(EM_68HC12, 53, "Motorola M68HC12") \ _ELF_DEFINE_EM(EM_MMA, 54, \ "Fujitsu MMA Multimedia Accelerator") \ _ELF_DEFINE_EM(EM_PCP, 55, "Siemens PCP") \ _ELF_DEFINE_EM(EM_NCPU, 56, \ "Sony nCPU embedded RISC processor") \ _ELF_DEFINE_EM(EM_NDR1, 57, "Denso NDR1 microprocessor") \ _ELF_DEFINE_EM(EM_STARCORE, 58, "Motorola Star*Core processor") \ _ELF_DEFINE_EM(EM_ME16, 59, "Toyota ME16 processor") \ _ELF_DEFINE_EM(EM_ST100, 60, \ "STMicroelectronics ST100 processor") \ _ELF_DEFINE_EM(EM_TINYJ, 61, \ "Advanced Logic Corp. TinyJ embedded processor family") \ _ELF_DEFINE_EM(EM_X86_64, 62, "AMD x86-64 architecture") \ _ELF_DEFINE_EM(EM_PDSP, 63, "Sony DSP Processor") \ _ELF_DEFINE_EM(EM_PDP10, 64, \ "Digital Equipment Corp. PDP-10") \ _ELF_DEFINE_EM(EM_PDP11, 65, \ "Digital Equipment Corp. PDP-11") \ _ELF_DEFINE_EM(EM_FX66, 66, "Siemens FX66 microcontroller") \ _ELF_DEFINE_EM(EM_ST9PLUS, 67, \ "STMicroelectronics ST9+ 8/16 bit microcontroller") \ _ELF_DEFINE_EM(EM_ST7, 68, \ "STMicroelectronics ST7 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_68HC16, 69, \ "Motorola MC68HC16 Microcontroller") \ _ELF_DEFINE_EM(EM_68HC11, 70, \ "Motorola MC68HC11 Microcontroller") \ _ELF_DEFINE_EM(EM_68HC08, 71, \ "Motorola MC68HC08 Microcontroller") \ _ELF_DEFINE_EM(EM_68HC05, 72, \ "Motorola MC68HC05 Microcontroller") \ _ELF_DEFINE_EM(EM_SVX, 73, "Silicon Graphics SVx") \ _ELF_DEFINE_EM(EM_ST19, 74, \ "STMicroelectronics ST19 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_VAX, 75, "Digital VAX") \ _ELF_DEFINE_EM(EM_CRIS, 76, \ "Axis Communications 32-bit embedded processor") \ _ELF_DEFINE_EM(EM_JAVELIN, 77, \ "Infineon Technologies 32-bit embedded processor") \ _ELF_DEFINE_EM(EM_FIREPATH, 78, \ "Element 14 64-bit DSP Processor") \ _ELF_DEFINE_EM(EM_ZSP, 79, \ "LSI Logic 16-bit DSP Processor") \ _ELF_DEFINE_EM(EM_MMIX, 80, \ "Donald Knuth's educational 64-bit processor") \ _ELF_DEFINE_EM(EM_HUANY, 81, \ "Harvard University machine-independent object files") \ _ELF_DEFINE_EM(EM_PRISM, 82, "SiTera Prism") \ _ELF_DEFINE_EM(EM_AVR, 83, \ "Atmel AVR 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_FR30, 84, "Fujitsu FR30") \ _ELF_DEFINE_EM(EM_D10V, 85, "Mitsubishi D10V") \ _ELF_DEFINE_EM(EM_D30V, 86, "Mitsubishi D30V") \ _ELF_DEFINE_EM(EM_V850, 87, "NEC v850") \ _ELF_DEFINE_EM(EM_M32R, 88, "Mitsubishi M32R") \ _ELF_DEFINE_EM(EM_MN10300, 89, "Matsushita MN10300") \ _ELF_DEFINE_EM(EM_MN10200, 90, "Matsushita MN10200") \ _ELF_DEFINE_EM(EM_PJ, 91, "picoJava") \ _ELF_DEFINE_EM(EM_OPENRISC, 92, \ "OpenRISC 32-bit embedded processor") \ _ELF_DEFINE_EM(EM_ARC_COMPACT, 93, \ "ARC International ARCompact processor") \ _ELF_DEFINE_EM(EM_XTENSA, 94, \ "Tensilica Xtensa Architecture") \ _ELF_DEFINE_EM(EM_VIDEOCORE, 95, \ "Alphamosaic VideoCore processor") \ _ELF_DEFINE_EM(EM_TMM_GPP, 96, \ "Thompson Multimedia General Purpose Processor") \ _ELF_DEFINE_EM(EM_NS32K, 97, \ "National Semiconductor 32000 series") \ _ELF_DEFINE_EM(EM_TPC, 98, "Tenor Network TPC processor") \ _ELF_DEFINE_EM(EM_SNP1K, 99, "Trebia SNP 1000 processor") \ _ELF_DEFINE_EM(EM_ST200, 100, \ "STMicroelectronics (www.st.com) ST200 microcontroller") \ _ELF_DEFINE_EM(EM_IP2K, 101, \ "Ubicom IP2xxx microcontroller family") \ _ELF_DEFINE_EM(EM_MAX, 102, "MAX Processor") \ _ELF_DEFINE_EM(EM_CR, 103, \ "National Semiconductor CompactRISC microprocessor") \ _ELF_DEFINE_EM(EM_F2MC16, 104, "Fujitsu F2MC16") \ _ELF_DEFINE_EM(EM_MSP430, 105, \ "Texas Instruments embedded microcontroller msp430") \ _ELF_DEFINE_EM(EM_BLACKFIN, 106, \ "Analog Devices Blackfin (DSP) processor") \ _ELF_DEFINE_EM(EM_SE_C33, 107, \ "S1C33 Family of Seiko Epson processors") \ _ELF_DEFINE_EM(EM_SEP, 108, \ "Sharp embedded microprocessor") \ _ELF_DEFINE_EM(EM_ARCA, 109, "Arca RISC Microprocessor") \ _ELF_DEFINE_EM(EM_UNICORE, 110, \ "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University") \ _ELF_DEFINE_EM(EM_EXCESS, 111, \ "eXcess: 16/32/64-bit configurable embedded CPU") \ _ELF_DEFINE_EM(EM_DXP, 112, \ "Icera Semiconductor Inc. Deep Execution Processor") \ _ELF_DEFINE_EM(EM_ALTERA_NIOS2, 113, \ "Altera Nios II soft-core processor") \ _ELF_DEFINE_EM(EM_CRX, 114, \ "National Semiconductor CompactRISC CRX microprocessor") \ _ELF_DEFINE_EM(EM_XGATE, 115, \ "Motorola XGATE embedded processor") \ _ELF_DEFINE_EM(EM_C166, 116, \ "Infineon C16x/XC16x processor") \ _ELF_DEFINE_EM(EM_M16C, 117, \ "Renesas M16C series microprocessors") \ _ELF_DEFINE_EM(EM_DSPIC30F, 118, \ "Microchip Technology dsPIC30F Digital Signal Controller") \ _ELF_DEFINE_EM(EM_CE, 119, \ "Freescale Communication Engine RISC core") \ _ELF_DEFINE_EM(EM_M32C, 120, \ "Renesas M32C series microprocessors") \ _ELF_DEFINE_EM(EM_TSK3000, 131, "Altium TSK3000 core") \ _ELF_DEFINE_EM(EM_RS08, 132, \ "Freescale RS08 embedded processor") \ _ELF_DEFINE_EM(EM_SHARC, 133, \ "Analog Devices SHARC family of 32-bit DSP processors") \ _ELF_DEFINE_EM(EM_ECOG2, 134, \ "Cyan Technology eCOG2 microprocessor") \ _ELF_DEFINE_EM(EM_SCORE7, 135, \ "Sunplus S+core7 RISC processor") \ _ELF_DEFINE_EM(EM_DSP24, 136, \ "New Japan Radio (NJR) 24-bit DSP Processor") \ _ELF_DEFINE_EM(EM_VIDEOCORE3, 137, \ "Broadcom VideoCore III processor") \ _ELF_DEFINE_EM(EM_LATTICEMICO32, 138, \ "RISC processor for Lattice FPGA architecture") \ _ELF_DEFINE_EM(EM_SE_C17, 139, "Seiko Epson C17 family") \ _ELF_DEFINE_EM(EM_TI_C6000, 140, \ "The Texas Instruments TMS320C6000 DSP family") \ _ELF_DEFINE_EM(EM_TI_C2000, 141, \ "The Texas Instruments TMS320C2000 DSP family") \ _ELF_DEFINE_EM(EM_TI_C5500, 142, \ "The Texas Instruments TMS320C55x DSP family") \ _ELF_DEFINE_EM(EM_MMDSP_PLUS, 160, \ "STMicroelectronics 64bit VLIW Data Signal Processor") \ _ELF_DEFINE_EM(EM_CYPRESS_M8C, 161, "Cypress M8C microprocessor") \ _ELF_DEFINE_EM(EM_R32C, 162, \ "Renesas R32C series microprocessors") \ _ELF_DEFINE_EM(EM_TRIMEDIA, 163, \ "NXP Semiconductors TriMedia architecture family") \ _ELF_DEFINE_EM(EM_QDSP6, 164, "QUALCOMM DSP6 Processor") \ _ELF_DEFINE_EM(EM_8051, 165, "Intel 8051 and variants") \ _ELF_DEFINE_EM(EM_STXP7X, 166, \ "STMicroelectronics STxP7x family of configurable and extensible RISC processors") \ _ELF_DEFINE_EM(EM_NDS32, 167, \ "Andes Technology compact code size embedded RISC processor family") \ _ELF_DEFINE_EM(EM_ECOG1, 168, \ "Cyan Technology eCOG1X family") \ _ELF_DEFINE_EM(EM_ECOG1X, 168, \ "Cyan Technology eCOG1X family") \ _ELF_DEFINE_EM(EM_MAXQ30, 169, \ "Dallas Semiconductor MAXQ30 Core Micro-controllers") \ _ELF_DEFINE_EM(EM_XIMO16, 170, \ "New Japan Radio (NJR) 16-bit DSP Processor") \ _ELF_DEFINE_EM(EM_MANIK, 171, \ "M2000 Reconfigurable RISC Microprocessor") \ _ELF_DEFINE_EM(EM_CRAYNV2, 172, \ "Cray Inc. NV2 vector architecture") \ _ELF_DEFINE_EM(EM_RX, 173, "Renesas RX family") \ _ELF_DEFINE_EM(EM_METAG, 174, \ "Imagination Technologies META processor architecture") \ _ELF_DEFINE_EM(EM_MCST_ELBRUS, 175, \ "MCST Elbrus general purpose hardware architecture") \ _ELF_DEFINE_EM(EM_ECOG16, 176, \ "Cyan Technology eCOG16 family") \ _ELF_DEFINE_EM(EM_CR16, 177, \ "National Semiconductor CompactRISC CR16 16-bit microprocessor") \ _ELF_DEFINE_EM(EM_ETPU, 178, \ "Freescale Extended Time Processing Unit") \ _ELF_DEFINE_EM(EM_SLE9X, 179, \ "Infineon Technologies SLE9X core") \ +_ELF_DEFINE_EM(EM_AARCH64, 183, \ + "AArch64 (64-bit ARM)") \ _ELF_DEFINE_EM(EM_AVR32, 185, \ "Atmel Corporation 32-bit microprocessor family") \ _ELF_DEFINE_EM(EM_STM8, 186, \ "STMicroeletronics STM8 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_TILE64, 187, \ "Tilera TILE64 multicore architecture family") \ _ELF_DEFINE_EM(EM_TILEPRO, 188, \ "Tilera TILEPro multicore architecture family") \ _ELF_DEFINE_EM(EM_MICROBLAZE, 189, \ "Xilinx MicroBlaze 32-bit RISC soft processor core") \ _ELF_DEFINE_EM(EM_CUDA, 190, "NVIDIA CUDA architecture") \ _ELF_DEFINE_EM(EM_TILEGX, 191, \ "Tilera TILE-Gx multicore architecture family") \ _ELF_DEFINE_EM(EM_CLOUDSHIELD, 192, \ "CloudShield architecture family") \ _ELF_DEFINE_EM(EM_COREA_1ST, 193, \ "KIPO-KAIST Core-A 1st generation processor family") \ _ELF_DEFINE_EM(EM_COREA_2ND, 194, \ "KIPO-KAIST Core-A 2nd generation processor family") \ _ELF_DEFINE_EM(EM_ARC_COMPACT2, 195, "Synopsys ARCompact V2") \ _ELF_DEFINE_EM(EM_OPEN8, 196, \ "Open8 8-bit RISC soft processor core") \ _ELF_DEFINE_EM(EM_RL78, 197, "Renesas RL78 family") \ _ELF_DEFINE_EM(EM_VIDEOCORE5, 198, "Broadcom VideoCore V processor") \ _ELF_DEFINE_EM(EM_78KOR, 199, "Renesas 78KOR family") \ _ELF_DEFINE_EM(EM_56800EX, 200, \ "Freescale 56800EX Digital Signal Controller") \ _ELF_DEFINE_EM(EM_BA1, 201, "Beyond BA1 CPU architecture") \ _ELF_DEFINE_EM(EM_BA2, 202, "Beyond BA2 CPU architecture") \ _ELF_DEFINE_EM(EM_XCORE, 203, "XMOS xCORE processor family") \ _ELF_DEFINE_EM(EM_MCHP_PIC, 204, "Microchip 8-bit PIC(r) family") \ _ELF_DEFINE_EM(EM_INTEL205, 205, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL206, 206, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL207, 207, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL208, 208, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL209, 209, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_KM32, 210, "KM211 KM32 32-bit processor") \ _ELF_DEFINE_EM(EM_KMX32, 211, "KM211 KMX32 32-bit processor") \ _ELF_DEFINE_EM(EM_KMX16, 212, "KM211 KMX16 16-bit processor") \ _ELF_DEFINE_EM(EM_KMX8, 213, "KM211 KMX8 8-bit processor") \ _ELF_DEFINE_EM(EM_KVARC, 214, "KM211 KMX32 KVARC processor") #undef _ELF_DEFINE_EM #define _ELF_DEFINE_EM(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_MACHINES() EM__LAST__ }; -/* Older synonyms. */ +/* Other synonyms. */ +#define EM_AMD64 EM_X86_64 #define EM_ARC_A5 EM_ARC_COMPACT /* * ELF file types: (ET_*). */ #define _ELF_DEFINE_ELF_TYPES() \ _ELF_DEFINE_ET(ET_NONE, 0, "No file type") \ _ELF_DEFINE_ET(ET_REL, 1, "Relocatable object") \ _ELF_DEFINE_ET(ET_EXEC, 2, "Executable") \ _ELF_DEFINE_ET(ET_DYN, 3, "Shared object") \ _ELF_DEFINE_ET(ET_CORE, 4, "Core file") \ _ELF_DEFINE_ET(ET_LOOS, 0xFE00U, "Begin OS-specific range") \ _ELF_DEFINE_ET(ET_HIOS, 0xFEFFU, "End OS-specific range") \ _ELF_DEFINE_ET(ET_LOPROC, 0xFF00U, "Begin processor-specific range") \ _ELF_DEFINE_ET(ET_HIPROC, 0xFFFFU, "End processor-specific range") #undef _ELF_DEFINE_ET #define _ELF_DEFINE_ET(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_TYPES() ET__LAST__ }; /* ELF file format version numbers. */ #define EV_NONE 0 #define EV_CURRENT 1 /* * Flags for section groups. */ #define GRP_COMDAT 0x1 /* COMDAT semantics */ #define GRP_MASKOS 0x0ff00000 /* OS-specific flags */ #define GRP_MASKPROC 0xf0000000 /* processor-specific flags */ /* * Flags used by program header table entries. */ #define _ELF_DEFINE_PHDR_FLAGS() \ _ELF_DEFINE_PF(PF_X, 0x1, "Execute") \ _ELF_DEFINE_PF(PF_W, 0x2, "Write") \ _ELF_DEFINE_PF(PF_R, 0x4, "Read") \ _ELF_DEFINE_PF(PF_MASKOS, 0x0ff00000, "OS-specific flags") \ _ELF_DEFINE_PF(PF_MASKPROC, 0xf0000000, "Processor-specific flags") \ _ELF_DEFINE_PF(PF_ARM_SB, 0x10000000, \ "segment contains the location addressed by the static base") \ _ELF_DEFINE_PF(PF_ARM_PI, 0x20000000, \ "segment is position-independent") \ _ELF_DEFINE_PF(PF_ARM_ABS, 0x40000000, \ "segment must be loaded at its base address") #undef _ELF_DEFINE_PF #define _ELF_DEFINE_PF(N, V, DESCR) N = V , enum { _ELF_DEFINE_PHDR_FLAGS() PF__LAST__ }; /* * Types of program header table entries. */ #define _ELF_DEFINE_PHDR_TYPES() \ _ELF_DEFINE_PT(PT_NULL, 0, "ignored entry") \ _ELF_DEFINE_PT(PT_LOAD, 1, "loadable segment") \ _ELF_DEFINE_PT(PT_DYNAMIC, 2, \ "contains dynamic linking information") \ _ELF_DEFINE_PT(PT_INTERP, 3, "names an interpreter") \ _ELF_DEFINE_PT(PT_NOTE, 4, "auxiliary information") \ _ELF_DEFINE_PT(PT_SHLIB, 5, "reserved") \ _ELF_DEFINE_PT(PT_PHDR, 6, \ "describes the program header itself") \ _ELF_DEFINE_PT(PT_TLS, 7, "thread local storage") \ _ELF_DEFINE_PT(PT_LOOS, 0x60000000UL, \ "start of OS-specific range") \ _ELF_DEFINE_PT(PT_SUNW_UNWIND, 0x6464E550UL, \ "Solaris/amd64 stack unwind tables") \ _ELF_DEFINE_PT(PT_GNU_EH_FRAME, 0x6474E550UL, \ "GCC generated .eh_frame_hdr segment") \ _ELF_DEFINE_PT(PT_GNU_STACK, 0x6474E551UL, \ "Stack flags") \ _ELF_DEFINE_PT(PT_GNU_RELRO, 0x6474E552UL, \ "Segment becomes read-only after relocation") \ _ELF_DEFINE_PT(PT_SUNWBSS, 0x6FFFFFFAUL, \ "A Solaris .SUNW_bss section") \ _ELF_DEFINE_PT(PT_SUNWSTACK, 0x6FFFFFFBUL, \ "A Solaris process stack") \ _ELF_DEFINE_PT(PT_SUNWDTRACE, 0x6FFFFFFCUL, \ "Used by dtrace(1)") \ _ELF_DEFINE_PT(PT_SUNWCAP, 0x6FFFFFFDUL, \ "Special hardware capability requirements") \ _ELF_DEFINE_PT(PT_HIOS, 0x6FFFFFFFUL, \ "end of OS-specific range") \ _ELF_DEFINE_PT(PT_LOPROC, 0x70000000UL, \ "start of processor-specific range") \ _ELF_DEFINE_PT(PT_ARM_ARCHEXT, 0x70000000UL, \ "platform architecture compatibility information") \ _ELF_DEFINE_PT(PT_ARM_EXIDX, 0x70000001UL, \ "exception unwind tables") \ _ELF_DEFINE_PT(PT_MIPS_REGINFO, 0x70000000UL, \ "register usage information") \ _ELF_DEFINE_PT(PT_MIPS_RTPROC, 0x70000001UL, \ "runtime procedure table") \ _ELF_DEFINE_PT(PT_MIPS_OPTIONS, 0x70000002UL, \ "options segment") \ _ELF_DEFINE_PT(PT_HIPROC, 0x7FFFFFFFUL, \ "end of processor-specific range") #undef _ELF_DEFINE_PT #define _ELF_DEFINE_PT(N, V, DESCR) N = V , enum { _ELF_DEFINE_PHDR_TYPES() PT__LAST__ = PT_HIPROC }; /* synonyms. */ #define PT_ARM_UNWIND PT_ARM_EXIDX #define PT_HISUNW PT_HIOS #define PT_LOSUNW PT_SUNWBSS /* * Section flags. */ #define _ELF_DEFINE_SECTION_FLAGS() \ _ELF_DEFINE_SHF(SHF_WRITE, 0x1, \ "writable during program execution") \ _ELF_DEFINE_SHF(SHF_ALLOC, 0x2, \ "occupies memory during program execution") \ _ELF_DEFINE_SHF(SHF_EXECINSTR, 0x4, "executable instructions") \ _ELF_DEFINE_SHF(SHF_MERGE, 0x10, \ "may be merged to prevent duplication") \ _ELF_DEFINE_SHF(SHF_STRINGS, 0x20, \ "NUL-terminated character strings") \ _ELF_DEFINE_SHF(SHF_INFO_LINK, 0x40, \ "the sh_info field holds a link") \ _ELF_DEFINE_SHF(SHF_LINK_ORDER, 0x80, \ "special ordering requirements during linking") \ _ELF_DEFINE_SHF(SHF_OS_NONCONFORMING, 0x100, \ "requires OS-specific processing during linking") \ _ELF_DEFINE_SHF(SHF_GROUP, 0x200, \ "member of a section group") \ _ELF_DEFINE_SHF(SHF_TLS, 0x400, \ "holds thread-local storage") \ _ELF_DEFINE_SHF(SHF_COMPRESSED, 0x800, \ "holds compressed data") \ _ELF_DEFINE_SHF(SHF_MASKOS, 0x0FF00000UL, \ "bits reserved for OS-specific semantics") \ _ELF_DEFINE_SHF(SHF_AMD64_LARGE, 0x10000000UL, \ "section uses large code model") \ _ELF_DEFINE_SHF(SHF_ENTRYSECT, 0x10000000UL, \ "section contains an entry point (ARM)") \ _ELF_DEFINE_SHF(SHF_COMDEF, 0x80000000UL, \ "section may be multiply defined in input to link step (ARM)") \ _ELF_DEFINE_SHF(SHF_MIPS_GPREL, 0x10000000UL, \ "section must be part of global data area") \ _ELF_DEFINE_SHF(SHF_MIPS_MERGE, 0x20000000UL, \ "section data should be merged to eliminate duplication") \ _ELF_DEFINE_SHF(SHF_MIPS_ADDR, 0x40000000UL, \ "section data is addressed by default") \ _ELF_DEFINE_SHF(SHF_MIPS_STRING, 0x80000000UL, \ "section data is string data by default") \ _ELF_DEFINE_SHF(SHF_MIPS_NOSTRIP, 0x08000000UL, \ "section data may not be stripped") \ _ELF_DEFINE_SHF(SHF_MIPS_LOCAL, 0x04000000UL, \ "section data local to process") \ _ELF_DEFINE_SHF(SHF_MIPS_NAMES, 0x02000000UL, \ "linker must generate implicit hidden weak names") \ _ELF_DEFINE_SHF(SHF_MIPS_NODUPE, 0x01000000UL, \ "linker must retain only one copy") \ _ELF_DEFINE_SHF(SHF_ORDERED, 0x40000000UL, \ "section is ordered with respect to other sections") \ _ELF_DEFINE_SHF(SHF_EXCLUDE, 0x80000000UL, \ "section is excluded from executables and shared objects") \ _ELF_DEFINE_SHF(SHF_MASKPROC, 0xF0000000UL, \ "bits reserved for processor-specific semantics") #undef _ELF_DEFINE_SHF #define _ELF_DEFINE_SHF(N, V, DESCR) N = V , enum { _ELF_DEFINE_SECTION_FLAGS() SHF__LAST__ }; /* * Special section indices. */ #define _ELF_DEFINE_SECTION_INDICES() \ _ELF_DEFINE_SHN(SHN_UNDEF, 0, "undefined section") \ _ELF_DEFINE_SHN(SHN_LORESERVE, 0xFF00U, "start of reserved area") \ _ELF_DEFINE_SHN(SHN_LOPROC, 0xFF00U, \ "start of processor-specific range") \ _ELF_DEFINE_SHN(SHN_BEFORE, 0xFF00U, "used for section ordering") \ _ELF_DEFINE_SHN(SHN_AFTER, 0xFF01U, "used for section ordering") \ _ELF_DEFINE_SHN(SHN_AMD64_LCOMMON, 0xFF02U, "large common block label") \ _ELF_DEFINE_SHN(SHN_MIPS_ACOMMON, 0xFF00U, \ "allocated common symbols in a DSO") \ _ELF_DEFINE_SHN(SHN_MIPS_TEXT, 0xFF01U, "Reserved (obsolete)") \ _ELF_DEFINE_SHN(SHN_MIPS_DATA, 0xFF02U, "Reserved (obsolete)") \ _ELF_DEFINE_SHN(SHN_MIPS_SCOMMON, 0xFF03U, \ "gp-addressable common symbols") \ _ELF_DEFINE_SHN(SHN_MIPS_SUNDEFINED, 0xFF04U, \ "gp-addressable undefined symbols") \ _ELF_DEFINE_SHN(SHN_MIPS_LCOMMON, 0xFF05U, "local common symbols") \ _ELF_DEFINE_SHN(SHN_MIPS_LUNDEFINED, 0xFF06U, \ "local undefined symbols") \ _ELF_DEFINE_SHN(SHN_HIPROC, 0xFF1FU, \ "end of processor-specific range") \ _ELF_DEFINE_SHN(SHN_LOOS, 0xFF20U, \ "start of OS-specific range") \ _ELF_DEFINE_SHN(SHN_SUNW_IGNORE, 0xFF3FU, "used by dtrace") \ _ELF_DEFINE_SHN(SHN_HIOS, 0xFF3FU, \ "end of OS-specific range") \ _ELF_DEFINE_SHN(SHN_ABS, 0xFFF1U, "absolute references") \ _ELF_DEFINE_SHN(SHN_COMMON, 0xFFF2U, "references to COMMON areas") \ _ELF_DEFINE_SHN(SHN_XINDEX, 0xFFFFU, "extended index") \ _ELF_DEFINE_SHN(SHN_HIRESERVE, 0xFFFFU, "end of reserved area") #undef _ELF_DEFINE_SHN #define _ELF_DEFINE_SHN(N, V, DESCR) N = V , enum { _ELF_DEFINE_SECTION_INDICES() SHN__LAST__ }; /* * Section types. */ #define _ELF_DEFINE_SECTION_TYPES() \ _ELF_DEFINE_SHT(SHT_NULL, 0, "inactive header") \ _ELF_DEFINE_SHT(SHT_PROGBITS, 1, "program defined information") \ _ELF_DEFINE_SHT(SHT_SYMTAB, 2, "symbol table") \ _ELF_DEFINE_SHT(SHT_STRTAB, 3, "string table") \ _ELF_DEFINE_SHT(SHT_RELA, 4, \ "relocation entries with addends") \ _ELF_DEFINE_SHT(SHT_HASH, 5, "symbol hash table") \ _ELF_DEFINE_SHT(SHT_DYNAMIC, 6, \ "information for dynamic linking") \ _ELF_DEFINE_SHT(SHT_NOTE, 7, "additional notes") \ _ELF_DEFINE_SHT(SHT_NOBITS, 8, "section occupying no space") \ _ELF_DEFINE_SHT(SHT_REL, 9, \ "relocation entries without addends") \ _ELF_DEFINE_SHT(SHT_SHLIB, 10, "reserved") \ _ELF_DEFINE_SHT(SHT_DYNSYM, 11, "symbol table") \ _ELF_DEFINE_SHT(SHT_INIT_ARRAY, 14, \ "pointers to initialization functions") \ _ELF_DEFINE_SHT(SHT_FINI_ARRAY, 15, \ "pointers to termination functions") \ _ELF_DEFINE_SHT(SHT_PREINIT_ARRAY, 16, \ "pointers to functions called before initialization") \ _ELF_DEFINE_SHT(SHT_GROUP, 17, "defines a section group") \ _ELF_DEFINE_SHT(SHT_SYMTAB_SHNDX, 18, \ "used for extended section numbering") \ _ELF_DEFINE_SHT(SHT_LOOS, 0x60000000UL, \ "start of OS-specific range") \ _ELF_DEFINE_SHT(SHT_SUNW_dof, 0x6FFFFFF4UL, \ "used by dtrace") \ _ELF_DEFINE_SHT(SHT_SUNW_cap, 0x6FFFFFF5UL, \ "capability requirements") \ _ELF_DEFINE_SHT(SHT_GNU_ATTRIBUTES, 0x6FFFFFF5UL, \ "object attributes") \ _ELF_DEFINE_SHT(SHT_SUNW_SIGNATURE, 0x6FFFFFF6UL, \ "module verification signature") \ _ELF_DEFINE_SHT(SHT_GNU_HASH, 0x6FFFFFF6UL, \ "GNU Hash sections") \ _ELF_DEFINE_SHT(SHT_GNU_LIBLIST, 0x6FFFFFF7UL, \ "List of libraries to be prelinked") \ _ELF_DEFINE_SHT(SHT_SUNW_ANNOTATE, 0x6FFFFFF7UL, \ "special section where unresolved references are allowed") \ _ELF_DEFINE_SHT(SHT_SUNW_DEBUGSTR, 0x6FFFFFF8UL, \ "debugging information") \ _ELF_DEFINE_SHT(SHT_CHECKSUM, 0x6FFFFFF8UL, \ "checksum for dynamic shared objects") \ _ELF_DEFINE_SHT(SHT_SUNW_DEBUG, 0x6FFFFFF9UL, \ "debugging information") \ _ELF_DEFINE_SHT(SHT_SUNW_move, 0x6FFFFFFAUL, \ "information to handle partially initialized symbols") \ _ELF_DEFINE_SHT(SHT_SUNW_COMDAT, 0x6FFFFFFBUL, \ "section supporting merging of multiple copies of data") \ _ELF_DEFINE_SHT(SHT_SUNW_syminfo, 0x6FFFFFFCUL, \ "additional symbol information") \ _ELF_DEFINE_SHT(SHT_SUNW_verdef, 0x6FFFFFFDUL, \ "symbol versioning information") \ _ELF_DEFINE_SHT(SHT_SUNW_verneed, 0x6FFFFFFEUL, \ "symbol versioning requirements") \ _ELF_DEFINE_SHT(SHT_SUNW_versym, 0x6FFFFFFFUL, \ "symbol versioning table") \ _ELF_DEFINE_SHT(SHT_HIOS, 0x6FFFFFFFUL, \ "end of OS-specific range") \ _ELF_DEFINE_SHT(SHT_LOPROC, 0x70000000UL, \ "start of processor-specific range") \ _ELF_DEFINE_SHT(SHT_ARM_EXIDX, 0x70000001UL, \ "exception index table") \ _ELF_DEFINE_SHT(SHT_ARM_PREEMPTMAP, 0x70000002UL, \ "BPABI DLL dynamic linking preemption map") \ _ELF_DEFINE_SHT(SHT_ARM_ATTRIBUTES, 0x70000003UL, \ "object file compatibility attributes") \ _ELF_DEFINE_SHT(SHT_ARM_DEBUGOVERLAY, 0x70000004UL, \ "overlay debug information") \ _ELF_DEFINE_SHT(SHT_ARM_OVERLAYSECTION, 0x70000005UL, \ "overlay debug information") \ _ELF_DEFINE_SHT(SHT_MIPS_LIBLIST, 0x70000000UL, \ "DSO library information used in link") \ _ELF_DEFINE_SHT(SHT_MIPS_MSYM, 0x70000001UL, \ "MIPS symbol table extension") \ _ELF_DEFINE_SHT(SHT_MIPS_CONFLICT, 0x70000002UL, \ "symbol conflicting with DSO-defined symbols ") \ _ELF_DEFINE_SHT(SHT_MIPS_GPTAB, 0x70000003UL, \ "global pointer table") \ _ELF_DEFINE_SHT(SHT_MIPS_UCODE, 0x70000004UL, \ "reserved") \ _ELF_DEFINE_SHT(SHT_MIPS_DEBUG, 0x70000005UL, \ "reserved (obsolete debug information)") \ _ELF_DEFINE_SHT(SHT_MIPS_REGINFO, 0x70000006UL, \ "register usage information") \ _ELF_DEFINE_SHT(SHT_MIPS_PACKAGE, 0x70000007UL, \ "OSF reserved") \ _ELF_DEFINE_SHT(SHT_MIPS_PACKSYM, 0x70000008UL, \ "OSF reserved") \ _ELF_DEFINE_SHT(SHT_MIPS_RELD, 0x70000009UL, \ "dynamic relocation") \ _ELF_DEFINE_SHT(SHT_MIPS_IFACE, 0x7000000BUL, \ "subprogram interface information") \ _ELF_DEFINE_SHT(SHT_MIPS_CONTENT, 0x7000000CUL, \ "section content classification") \ _ELF_DEFINE_SHT(SHT_MIPS_OPTIONS, 0x7000000DUL, \ "general options") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTASYM, 0x7000001BUL, \ "Delta C++: symbol table") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTAINST, 0x7000001CUL, \ "Delta C++: instance table") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTACLASS, 0x7000001DUL, \ "Delta C++: class table") \ _ELF_DEFINE_SHT(SHT_MIPS_DWARF, 0x7000001EUL, \ "DWARF debug information") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTADECL, 0x7000001FUL, \ "Delta C++: declarations") \ _ELF_DEFINE_SHT(SHT_MIPS_SYMBOL_LIB, 0x70000020UL, \ "symbol-to-library mapping") \ _ELF_DEFINE_SHT(SHT_MIPS_EVENTS, 0x70000021UL, \ "event locations") \ _ELF_DEFINE_SHT(SHT_MIPS_TRANSLATE, 0x70000022UL, \ "???") \ _ELF_DEFINE_SHT(SHT_MIPS_PIXIE, 0x70000023UL, \ "special pixie sections") \ _ELF_DEFINE_SHT(SHT_MIPS_XLATE, 0x70000024UL, \ "address translation table") \ _ELF_DEFINE_SHT(SHT_MIPS_XLATE_DEBUG, 0x70000025UL, \ "SGI internal address translation table") \ _ELF_DEFINE_SHT(SHT_MIPS_WHIRL, 0x70000026UL, \ "intermediate code") \ _ELF_DEFINE_SHT(SHT_MIPS_EH_REGION, 0x70000027UL, \ "C++ exception handling region info") \ _ELF_DEFINE_SHT(SHT_MIPS_XLATE_OLD, 0x70000028UL, \ "obsolete") \ _ELF_DEFINE_SHT(SHT_MIPS_PDR_EXCEPTION, 0x70000029UL, \ "runtime procedure descriptor table exception information") \ _ELF_DEFINE_SHT(SHT_SPARC_GOTDATA, 0x70000000UL, \ "SPARC-specific data") \ _ELF_DEFINE_SHT(SHT_AMD64_UNWIND, 0x70000001UL, \ "unwind tables for the AMD64") \ _ELF_DEFINE_SHT(SHT_ORDERED, 0x7FFFFFFFUL, \ "sort entries in the section") \ _ELF_DEFINE_SHT(SHT_HIPROC, 0x7FFFFFFFUL, \ "end of processor-specific range") \ _ELF_DEFINE_SHT(SHT_LOUSER, 0x80000000UL, \ "start of application-specific range") \ _ELF_DEFINE_SHT(SHT_HIUSER, 0xFFFFFFFFUL, \ "end of application-specific range") #undef _ELF_DEFINE_SHT #define _ELF_DEFINE_SHT(N, V, DESCR) N = V , enum { _ELF_DEFINE_SECTION_TYPES() SHT__LAST__ = SHT_HIUSER }; /* Aliases for section types. */ #define SHT_GNU_verdef SHT_SUNW_verdef #define SHT_GNU_verneed SHT_SUNW_verneed #define SHT_GNU_versym SHT_SUNW_versym /* * Symbol binding information. */ #define _ELF_DEFINE_SYMBOL_BINDING() \ _ELF_DEFINE_STB(STB_LOCAL, 0, \ "not visible outside defining object file") \ _ELF_DEFINE_STB(STB_GLOBAL, 1, \ "visible across all object files being combined") \ _ELF_DEFINE_STB(STB_WEAK, 2, \ "visible across all object files but with low precedence") \ _ELF_DEFINE_STB(STB_LOOS, 10, "start of OS-specific range") \ _ELF_DEFINE_STB(STB_HIOS, 12, "end of OS-specific range") \ _ELF_DEFINE_STB(STB_LOPROC, 13, \ "start of processor-specific range") \ _ELF_DEFINE_STB(STB_HIPROC, 15, \ "end of processor-specific range") #undef _ELF_DEFINE_STB #define _ELF_DEFINE_STB(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_BINDING() STB__LAST__ }; /* * Symbol types */ #define _ELF_DEFINE_SYMBOL_TYPES() \ _ELF_DEFINE_STT(STT_NOTYPE, 0, "unspecified type") \ _ELF_DEFINE_STT(STT_OBJECT, 1, "data object") \ _ELF_DEFINE_STT(STT_FUNC, 2, "executable code") \ _ELF_DEFINE_STT(STT_SECTION, 3, "section") \ _ELF_DEFINE_STT(STT_FILE, 4, "source file") \ _ELF_DEFINE_STT(STT_COMMON, 5, "uninitialized common block") \ _ELF_DEFINE_STT(STT_TLS, 6, "thread local storage") \ _ELF_DEFINE_STT(STT_LOOS, 10, "start of OS-specific types") \ _ELF_DEFINE_STT(STT_HIOS, 12, "end of OS-specific types") \ _ELF_DEFINE_STT(STT_LOPROC, 13, \ "start of processor-specific types") \ _ELF_DEFINE_STT(STT_ARM_TFUNC, 13, "Thumb function (GNU)") \ _ELF_DEFINE_STT(STT_ARM_16BIT, 15, "Thumb label (GNU)") \ _ELF_DEFINE_STT(STT_HIPROC, 15, \ "end of processor-specific types") #undef _ELF_DEFINE_STT #define _ELF_DEFINE_STT(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_TYPES() STT__LAST__ }; /* * Symbol binding. */ #define _ELF_DEFINE_SYMBOL_BINDING_KINDS() \ _ELF_DEFINE_SYB(SYMINFO_BT_SELF, 0xFFFFU, \ "bound to self") \ _ELF_DEFINE_SYB(SYMINFO_BT_PARENT, 0xFFFEU, \ "bound to parent") \ _ELF_DEFINE_SYB(SYMINFO_BT_NONE, 0xFFFDU, \ "no special binding") #undef _ELF_DEFINE_SYB #define _ELF_DEFINE_SYB(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_BINDING_KINDS() SYMINFO__LAST__ }; /* * Symbol visibility. */ #define _ELF_DEFINE_SYMBOL_VISIBILITY() \ _ELF_DEFINE_STV(STV_DEFAULT, 0, \ "as specified by symbol type") \ _ELF_DEFINE_STV(STV_INTERNAL, 1, \ "as defined by processor semantics") \ _ELF_DEFINE_STV(STV_HIDDEN, 2, \ "hidden from other components") \ _ELF_DEFINE_STV(STV_PROTECTED, 3, \ "local references are not preemptable") #undef _ELF_DEFINE_STV #define _ELF_DEFINE_STV(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_VISIBILITY() STV__LAST__ }; /* * Symbol flags. */ #define _ELF_DEFINE_SYMBOL_FLAGS() \ _ELF_DEFINE_SYF(SYMINFO_FLG_DIRECT, 0x01, \ "directly assocated reference") \ _ELF_DEFINE_SYF(SYMINFO_FLG_COPY, 0x04, \ "definition by copy-relocation") \ _ELF_DEFINE_SYF(SYMINFO_FLG_LAZYLOAD, 0x08, \ "object should be lazily loaded") \ _ELF_DEFINE_SYF(SYMINFO_FLG_DIRECTBIND, 0x10, \ "reference should be directly bound") \ _ELF_DEFINE_SYF(SYMINFO_FLG_NOEXTDIRECT, 0x20, \ "external references not allowed to bind to definition") #undef _ELF_DEFINE_SYF #define _ELF_DEFINE_SYF(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_FLAGS() SYMINFO_FLG__LAST__ }; /* * Version dependencies. */ #define _ELF_DEFINE_VERSIONING_DEPENDENCIES() \ _ELF_DEFINE_VERD(VER_NDX_LOCAL, 0, "local scope") \ _ELF_DEFINE_VERD(VER_NDX_GLOBAL, 1, "global scope") #undef _ELF_DEFINE_VERD #define _ELF_DEFINE_VERD(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_DEPENDENCIES() VER_NDX__LAST__ }; /* * Version flags. */ #define _ELF_DEFINE_VERSIONING_FLAGS() \ _ELF_DEFINE_VERF(VER_FLG_BASE, 0x1, "file version") \ _ELF_DEFINE_VERF(VER_FLG_WEAK, 0x2, "weak version") #undef _ELF_DEFINE_VERF #define _ELF_DEFINE_VERF(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_FLAGS() VER_FLG__LAST__ }; /* * Version needs */ #define _ELF_DEFINE_VERSIONING_NEEDS() \ _ELF_DEFINE_VRN(VER_NEED_NONE, 0, "invalid version") \ _ELF_DEFINE_VRN(VER_NEED_CURRENT, 1, "current version") #undef _ELF_DEFINE_VRN #define _ELF_DEFINE_VRN(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_NEEDS() VER_NEED__LAST__ }; /* * Version numbers. */ #define _ELF_DEFINE_VERSIONING_NUMBERS() \ _ELF_DEFINE_VRNU(VER_DEF_NONE, 0, "invalid version") \ _ELF_DEFINE_VRNU(VER_DEF_CURRENT, 1, "current version") #undef _ELF_DEFINE_VRNU #define _ELF_DEFINE_VRNU(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_NUMBERS() VER_DEF__LAST__ }; /** ** Relocation types. **/ #define _ELF_DEFINE_386_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_386_NONE, 0) \ _ELF_DEFINE_RELOC(R_386_32, 1) \ _ELF_DEFINE_RELOC(R_386_PC32, 2) \ _ELF_DEFINE_RELOC(R_386_GOT32, 3) \ _ELF_DEFINE_RELOC(R_386_PLT32, 4) \ _ELF_DEFINE_RELOC(R_386_COPY, 5) \ _ELF_DEFINE_RELOC(R_386_GLOB_DAT, 6) \ _ELF_DEFINE_RELOC(R_386_JMP_SLOT, 7) \ _ELF_DEFINE_RELOC(R_386_RELATIVE, 8) \ _ELF_DEFINE_RELOC(R_386_GOTOFF, 9) \ _ELF_DEFINE_RELOC(R_386_GOTPC, 10) \ _ELF_DEFINE_RELOC(R_386_32PLT, 11) \ _ELF_DEFINE_RELOC(R_386_16, 20) \ _ELF_DEFINE_RELOC(R_386_PC16, 21) \ _ELF_DEFINE_RELOC(R_386_8, 22) \ _ELF_DEFINE_RELOC(R_386_PC8, 23) /* * These are the symbols used in the Sun ``Linkers and Loaders * Guide'', Document No: 817-1984-17. See the X86_64 relocations list * below for the spellings used in the ELF specification. */ #define _ELF_DEFINE_AMD64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_AMD64_NONE, 0) \ _ELF_DEFINE_RELOC(R_AMD64_64, 1) \ _ELF_DEFINE_RELOC(R_AMD64_PC32, 2) \ _ELF_DEFINE_RELOC(R_AMD64_GOT32, 3) \ _ELF_DEFINE_RELOC(R_AMD64_PLT32, 4) \ _ELF_DEFINE_RELOC(R_AMD64_COPY, 5) \ _ELF_DEFINE_RELOC(R_AMD64_GLOB_DAT, 6) \ _ELF_DEFINE_RELOC(R_AMD64_JUMP_SLOT, 7) \ _ELF_DEFINE_RELOC(R_AMD64_RELATIVE, 8) \ _ELF_DEFINE_RELOC(R_AMD64_GOTPCREL, 9) \ _ELF_DEFINE_RELOC(R_AMD64_32, 10) \ _ELF_DEFINE_RELOC(R_AMD64_32S, 11) \ _ELF_DEFINE_RELOC(R_AMD64_16, 12) \ _ELF_DEFINE_RELOC(R_AMD64_PC16, 13) \ _ELF_DEFINE_RELOC(R_AMD64_8, 14) \ _ELF_DEFINE_RELOC(R_AMD64_PC8, 15) \ _ELF_DEFINE_RELOC(R_AMD64_PC64, 24) \ _ELF_DEFINE_RELOC(R_AMD64_GOTOFF64, 25) \ _ELF_DEFINE_RELOC(R_AMD64_GOTPC32, 26) /* * Relocation definitions from the ARM ELF ABI, version "ARM IHI * 0044E" released on 30th November 2012. */ #define _ELF_DEFINE_ARM_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_ARM_NONE, 0) \ _ELF_DEFINE_RELOC(R_ARM_PC24, 1) \ _ELF_DEFINE_RELOC(R_ARM_ABS32, 2) \ _ELF_DEFINE_RELOC(R_ARM_REL32, 3) \ _ELF_DEFINE_RELOC(R_ARM_LDR_PC_G0, 4) \ _ELF_DEFINE_RELOC(R_ARM_ABS16, 5) \ _ELF_DEFINE_RELOC(R_ARM_ABS12, 6) \ _ELF_DEFINE_RELOC(R_ARM_THM_ABS5, 7) \ _ELF_DEFINE_RELOC(R_ARM_ABS8, 8) \ _ELF_DEFINE_RELOC(R_ARM_SBREL32, 9) \ _ELF_DEFINE_RELOC(R_ARM_THM_CALL, 10) \ _ELF_DEFINE_RELOC(R_ARM_THM_PC8, 11) \ _ELF_DEFINE_RELOC(R_ARM_BREL_ADJ, 12) \ _ELF_DEFINE_RELOC(R_ARM_SWI24, 13) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DESC, 13) \ _ELF_DEFINE_RELOC(R_ARM_THM_SWI8, 14) \ _ELF_DEFINE_RELOC(R_ARM_XPC25, 15) \ _ELF_DEFINE_RELOC(R_ARM_THM_XPC22, 16) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DTPMOD32, 17) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DTPOFF32, 18) \ _ELF_DEFINE_RELOC(R_ARM_TLS_TPOFF32, 19) \ _ELF_DEFINE_RELOC(R_ARM_COPY, 20) \ _ELF_DEFINE_RELOC(R_ARM_GLOB_DAT, 21) \ _ELF_DEFINE_RELOC(R_ARM_JUMP_SLOT, 22) \ _ELF_DEFINE_RELOC(R_ARM_RELATIVE, 23) \ _ELF_DEFINE_RELOC(R_ARM_GOTOFF32, 24) \ _ELF_DEFINE_RELOC(R_ARM_BASE_PREL, 25) \ _ELF_DEFINE_RELOC(R_ARM_GOT_BREL, 26) \ _ELF_DEFINE_RELOC(R_ARM_PLT32, 27) \ _ELF_DEFINE_RELOC(R_ARM_CALL, 28) \ _ELF_DEFINE_RELOC(R_ARM_JUMP24, 29) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP24, 30) \ _ELF_DEFINE_RELOC(R_ARM_BASE_ABS, 31) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PCREL_7_0, 32) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PCREL_15_8, 33) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PCREL_23_15, 34) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SBREL_11_0_NC, 35) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_19_12_NC, 36) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_27_20_CK, 37) \ _ELF_DEFINE_RELOC(R_ARM_TARGET1, 38) \ _ELF_DEFINE_RELOC(R_ARM_SBREL31, 39) \ _ELF_DEFINE_RELOC(R_ARM_V4BX, 40) \ _ELF_DEFINE_RELOC(R_ARM_TARGET2, 41) \ _ELF_DEFINE_RELOC(R_ARM_PREL31, 42) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_ABS_NC, 43) \ _ELF_DEFINE_RELOC(R_ARM_MOVT_ABS, 44) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_PREL_NC, 45) \ _ELF_DEFINE_RELOC(R_ARM_MOVT_PREL, 46) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_ABS_NC, 47) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVT_ABS, 48) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_PREL_NC, 49) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVT_PREL, 50) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP19, 51) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP6, 52) \ _ELF_DEFINE_RELOC(R_ARM_THM_ALU_PREL_11_0, 53) \ _ELF_DEFINE_RELOC(R_ARM_THM_PC12, 54) \ _ELF_DEFINE_RELOC(R_ARM_ABS32_NOI, 55) \ _ELF_DEFINE_RELOC(R_ARM_REL32_NOI, 56) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0_NC, 57) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0, 58) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1_NC, 59) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1, 60) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G2, 61) \ _ELF_DEFINE_RELOC(R_ARM_LDR_PC_G1, 62) \ _ELF_DEFINE_RELOC(R_ARM_LDR_PC_G2, 63) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G0, 64) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G1, 65) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G2, 66) \ _ELF_DEFINE_RELOC(R_ARM_LDC_PC_G0, 67) \ _ELF_DEFINE_RELOC(R_ARM_LDC_PC_G1, 68) \ _ELF_DEFINE_RELOC(R_ARM_LDC_PC_G2, 69) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0_NC, 70) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0, 71) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1_NC, 72) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1, 73) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G2, 74) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SB_G0, 75) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SB_G1, 76) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SB_G2, 77) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G0, 78) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G1, 79) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G2, 80) \ _ELF_DEFINE_RELOC(R_ARM_LDC_SB_G0, 81) \ _ELF_DEFINE_RELOC(R_ARM_LDC_SB_G1, 82) \ _ELF_DEFINE_RELOC(R_ARM_LDC_SB_G2, 83) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_BREL_NC, 84) \ _ELF_DEFINE_RELOC(R_ARM_MOVT_BREL, 85) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_BREL, 86) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL_NC, 87) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVT_BREL, 88) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL, 89) \ _ELF_DEFINE_RELOC(R_ARM_TLS_GOTDESC, 90) \ _ELF_DEFINE_RELOC(R_ARM_TLS_CALL, 91) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DESCSEQ, 92) \ _ELF_DEFINE_RELOC(R_ARM_THM_TLS_CALL, 93) \ _ELF_DEFINE_RELOC(R_ARM_PLT32_ABS, 94) \ _ELF_DEFINE_RELOC(R_ARM_GOT_ABS, 95) \ _ELF_DEFINE_RELOC(R_ARM_GOT_PREL, 96) \ _ELF_DEFINE_RELOC(R_ARM_GOT_BREL12, 97) \ _ELF_DEFINE_RELOC(R_ARM_GOTOFF12, 98) \ _ELF_DEFINE_RELOC(R_ARM_GOTRELAX, 99) \ _ELF_DEFINE_RELOC(R_ARM_GNU_VTENTRY, 100) \ _ELF_DEFINE_RELOC(R_ARM_GNU_VTINHERIT, 101) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP11, 102) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP8, 103) \ _ELF_DEFINE_RELOC(R_ARM_TLS_GD32, 104) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LDM32, 105) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LDO32, 106) \ _ELF_DEFINE_RELOC(R_ARM_TLS_IE32, 107) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LE32, 108) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LDO12, 109) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LE12, 110) \ _ELF_DEFINE_RELOC(R_ARM_TLS_IE12GP, 111) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_0, 112) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_1, 113) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_2, 114) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_3, 115) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_4, 116) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_5, 117) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_6, 118) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_7, 119) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_8, 120) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_9, 121) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_10, 122) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_11, 123) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_12, 124) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_13, 125) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_14, 126) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_15, 127) \ _ELF_DEFINE_RELOC(R_ARM_ME_TOO, 128) \ _ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ16, 129) \ _ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ32, 130) \ _ELF_DEFINE_RELOC(R_ARM_THM_GOT_BREL12, 131) \ _ELF_DEFINE_RELOC(R_ARM_IRELATIVE, 140) #define _ELF_DEFINE_IA64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_IA_64_NONE, 0) \ _ELF_DEFINE_RELOC(R_IA_64_IMM14, 0x21) \ _ELF_DEFINE_RELOC(R_IA_64_IMM22, 0x22) \ _ELF_DEFINE_RELOC(R_IA_64_IMM64, 0x23) \ _ELF_DEFINE_RELOC(R_IA_64_DIR32MSB, 0x24) \ _ELF_DEFINE_RELOC(R_IA_64_DIR32LSB, 0x25) \ _ELF_DEFINE_RELOC(R_IA_64_DIR64MSB, 0x26) \ _ELF_DEFINE_RELOC(R_IA_64_DIR64LSB, 0x27) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL22, 0x2a) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL64I, 0x2b) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL32MSB, 0x2c) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL32LSB, 0x2d) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL64MSB, 0x2e) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL64LSB, 0x2f) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF22, 0x32) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF64I, 0x33) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF22, 0x3a) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF64I, 0x3b) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF64MSB, 0x3e) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF64LSB, 0x3f) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR64I, 0x43) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR32MSB, 0x44) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR32LSB, 0x45) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR64MSB, 0x46) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR64LSB, 0x47) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL60B, 0x48) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21B, 0x49) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21M, 0x4a) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21F, 0x4b) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL32MSB, 0x4c) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL32LSB, 0x4d) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL64MSB, 0x4e) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL64LSB, 0x4f) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR22, 0x52) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64I, 0x53) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32MSB, 0x54) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32LSB, 0x55) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64MSB, 0x56) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64LSB, 0x57) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL32MSB, 0x5c) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL32LSB, 0x5d) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL64MSB, 0x5e) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL64LSB, 0x5f) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL32MSB, 0x64) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL32LSB, 0x65) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL64MSB, 0x66) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL64LSB, 0x67) \ _ELF_DEFINE_RELOC(R_IA_64_REL32MSB, 0x6c) \ _ELF_DEFINE_RELOC(R_IA_64_REL32LSB, 0x6d) \ _ELF_DEFINE_RELOC(R_IA_64_REL64MSB, 0x6e) \ _ELF_DEFINE_RELOC(R_IA_64_REL64LSB, 0x6f) \ _ELF_DEFINE_RELOC(R_IA_64_LTV32MSB, 0x74) \ _ELF_DEFINE_RELOC(R_IA_64_LTV32LSB, 0x75) \ _ELF_DEFINE_RELOC(R_IA_64_LTV64MSB, 0x76) \ _ELF_DEFINE_RELOC(R_IA_64_LTV64LSB, 0x77) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21BIa, 0x79) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL22, 0x7A) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL64I, 0x7B) \ _ELF_DEFINE_RELOC(R_IA_64_IPLTMSB, 0x80) \ _ELF_DEFINE_RELOC(R_IA_64_IPLTLSB, 0x81) \ _ELF_DEFINE_RELOC(R_IA_64_SUB, 0x85) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF22X, 0x86) \ _ELF_DEFINE_RELOC(R_IA_64_LDXMOV, 0x87) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL14, 0x91) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL22, 0x92) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL64I, 0x93) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL64MSB, 0x96) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL64LSB, 0x97) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_TPREL22, 0x9A) \ _ELF_DEFINE_RELOC(R_IA_64_DTPMOD64MSB, 0xA6) \ _ELF_DEFINE_RELOC(R_IA_64_DTPMOD64LSB, 0xA7) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPMOD22, 0xAA) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL14, 0xB1) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL22, 0xB2) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL64I, 0xB3) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL32MSB, 0xB4) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL32LSB, 0xB5) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL64MSB, 0xB6) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL64LSB, 0xB7) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPREL22, 0xBA) #define _ELF_DEFINE_MIPS_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_MIPS_NONE, 0) \ _ELF_DEFINE_RELOC(R_MIPS_16, 1) \ _ELF_DEFINE_RELOC(R_MIPS_32, 2) \ _ELF_DEFINE_RELOC(R_MIPS_REL32, 3) \ _ELF_DEFINE_RELOC(R_MIPS_26, 4) \ _ELF_DEFINE_RELOC(R_MIPS_HI16, 5) \ _ELF_DEFINE_RELOC(R_MIPS_LO16, 6) \ _ELF_DEFINE_RELOC(R_MIPS_GPREL16, 7) \ _ELF_DEFINE_RELOC(R_MIPS_LITERAL, 8) \ _ELF_DEFINE_RELOC(R_MIPS_GOT16, 9) \ _ELF_DEFINE_RELOC(R_MIPS_PC16, 10) \ _ELF_DEFINE_RELOC(R_MIPS_CALL16, 11) \ _ELF_DEFINE_RELOC(R_MIPS_GPREL32, 12) \ _ELF_DEFINE_RELOC(R_MIPS_64, 18) \ _ELF_DEFINE_RELOC(R_MIPS_GOTHI16, 21) \ _ELF_DEFINE_RELOC(R_MIPS_GOTLO16, 22) \ _ELF_DEFINE_RELOC(R_MIPS_CALLHI16, 30) \ _ELF_DEFINE_RELOC(R_MIPS_CALLLO16, 31) #define _ELF_DEFINE_PPC32_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_PPC_NONE, 0) \ _ELF_DEFINE_RELOC(R_PPC_ADDR32, 1) \ _ELF_DEFINE_RELOC(R_PPC_ADDR24, 2) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16, 3) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16_LO, 4) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16_HI, 5) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16_HA, 6) \ _ELF_DEFINE_RELOC(R_PPC_ADDR14, 7) \ _ELF_DEFINE_RELOC(R_PPC_ADDR14_BRTAKEN, 8) \ _ELF_DEFINE_RELOC(R_PPC_ADDR14_BRNTAKEN, 9) \ _ELF_DEFINE_RELOC(R_PPC_REL24, 10) \ _ELF_DEFINE_RELOC(R_PPC_REL14, 11) \ _ELF_DEFINE_RELOC(R_PPC_REL14_BRTAKEN, 12) \ _ELF_DEFINE_RELOC(R_PPC_REL14_BRNTAKEN, 13) \ _ELF_DEFINE_RELOC(R_PPC_GOT16, 14) \ _ELF_DEFINE_RELOC(R_PPC_GOT16_LO, 15) \ _ELF_DEFINE_RELOC(R_PPC_GOT16_HI, 16) \ _ELF_DEFINE_RELOC(R_PPC_GOT16_HA, 17) \ _ELF_DEFINE_RELOC(R_PPC_PLTREL24, 18) \ _ELF_DEFINE_RELOC(R_PPC_COPY, 19) \ _ELF_DEFINE_RELOC(R_PPC_GLOB_DAT, 20) \ _ELF_DEFINE_RELOC(R_PPC_JMP_SLOT, 21) \ _ELF_DEFINE_RELOC(R_PPC_RELATIVE, 22) \ _ELF_DEFINE_RELOC(R_PPC_LOCAL24PC, 23) \ _ELF_DEFINE_RELOC(R_PPC_UADDR32, 24) \ _ELF_DEFINE_RELOC(R_PPC_UADDR16, 25) \ _ELF_DEFINE_RELOC(R_PPC_REL32, 26) \ _ELF_DEFINE_RELOC(R_PPC_PLT32, 27) \ _ELF_DEFINE_RELOC(R_PPC_PLTREL32, 28) \ _ELF_DEFINE_RELOC(R_PPC_PLT16_LO, 29) \ _ELF_DEFINE_RELOC(R_PPL_PLT16_HI, 30) \ _ELF_DEFINE_RELOC(R_PPC_PLT16_HA, 31) \ _ELF_DEFINE_RELOC(R_PPC_SDAREL16, 32) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF, 33) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF_LO, 34) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF_HI, 35) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF_HA, 36) \ _ELF_DEFINE_RELOC(R_PPC_ADDR30, 37) \ _ELF_DEFINE_RELOC(R_PPC_TLS, 67) \ _ELF_DEFINE_RELOC(R_PPC_DTPMOD32, 68) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16, 69) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16_LO, 70) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16_HI, 71) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16_HA, 72) \ _ELF_DEFINE_RELOC(R_PPC_TPREL32, 73) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16, 74) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16_LO, 75) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16_HI, 76) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16_HA, 77) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL32, 78) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16, 79) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_LO, 80) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HI, 81) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HA, 82) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16, 83) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_LO, 84) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HI, 85) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HA, 86) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16, 87) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_LO, 88) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HI, 89) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HA, 90) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16, 91) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_LO, 92) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HI, 93) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HA, 94) \ _ELF_DEFINE_RELOC(R_PPC_TLSGD, 95) \ _ELF_DEFINE_RELOC(R_PPC_TLSLD, 96) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR32, 101) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16, 102) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_LO, 103) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HI, 104) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HA, 105) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDAI16, 106) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDA2I16, 107) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDA2REL, 108) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDA21, 109) \ _ELF_DEFINE_RELOC(R_PPC_EMB_MRKREF, 110) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELSEC16, 111) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELST_LO, 112) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HI, 113) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HA, 114) \ _ELF_DEFINE_RELOC(R_PPC_EMB_BIT_FLD, 115) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELSDA, 116) \ #define _ELF_DEFINE_PPC64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_PPC64_NONE, 0) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR32, 1) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR24, 2) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16, 3) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO, 4) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HI, 5) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HA, 6) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR14, 7) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRTAKEN, 8) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRNTAKEN, 9) \ _ELF_DEFINE_RELOC(R_PPC64_REL24, 10) \ _ELF_DEFINE_RELOC(R_PPC64_REL14, 11) \ _ELF_DEFINE_RELOC(R_PPC64_REL14_BRTAKEN, 12) \ _ELF_DEFINE_RELOC(R_PPC64_REL14_BRNTAKEN, 13) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16, 14) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_LO, 15) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_HI, 16) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_HA, 17) \ _ELF_DEFINE_RELOC(R_PPC64_COPY, 19) \ _ELF_DEFINE_RELOC(R_PPC64_GLOB_DAT, 20) \ _ELF_DEFINE_RELOC(R_PPC64_JMP_SLOT, 21) \ _ELF_DEFINE_RELOC(R_PPC64_RELATIVE, 22) \ _ELF_DEFINE_RELOC(R_PPC64_UADDR32, 24) \ _ELF_DEFINE_RELOC(R_PPC64_UADDR16, 25) \ _ELF_DEFINE_RELOC(R_PPC64_REL32, 26) \ _ELF_DEFINE_RELOC(R_PPC64_PLT32, 27) \ _ELF_DEFINE_RELOC(R_PPC64_PLTREL32, 28) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_LO, 29) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_HI, 30) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_HA, 31) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF, 33) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO, 34) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HI, 35) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HA, 36) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR30, 37) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR64, 38) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHER, 39) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHERA, 40) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHEST, 41) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHESTA, 42) \ _ELF_DEFINE_RELOC(R_PPC64_UADDR64, 43) \ _ELF_DEFINE_RELOC(R_PPC64_REL64, 44) \ _ELF_DEFINE_RELOC(R_PPC64_PLT64, 45) \ _ELF_DEFINE_RELOC(R_PPC64_PLTREL64, 46) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16, 47) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_LO, 48) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_HI, 49) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_HA, 50) \ _ELF_DEFINE_RELOC(R_PPC64_TOC, 51) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16, 52) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO, 53) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HI, 54) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HA, 55) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_DS, 56) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO_DS, 57) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_DS, 58) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_LO_DS, 59) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_LO_DS, 60) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_DS, 61) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO_DS, 62) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_DS, 63) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_LO_DS, 64) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_DS, 65) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO_DS, 66) \ _ELF_DEFINE_RELOC(R_PPC64_TLS, 67) \ _ELF_DEFINE_RELOC(R_PPC64_DTPMOD64, 68) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16, 69) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO, 60) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HI, 71) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HA, 72) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL64, 73) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16, 74) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO, 75) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HI, 76) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HA, 77) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL64, 78) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16, 79) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_LO, 80) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HI, 81) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HA, 82) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16, 83) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_LO, 84) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HI, 85) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HA, 86) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_DS, 87) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_LO_DS, 88) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HI, 89) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HA, 90) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_DS, 91) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_LO_DS, 92) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HI, 93) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HA, 94) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_DS, 95) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO_DS, 96) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHER, 97) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHERA, 98) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHEST, 99) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHESTA, 100) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_DS, 101) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO_DS, 102) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHER, 103) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHERA, 104) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHEST, 105) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHESTA, 106) \ _ELF_DEFINE_RELOC(R_PPC64_TLSGD, 107) \ _ELF_DEFINE_RELOC(R_PPC64_TLSLD, 108) #define _ELF_DEFINE_SPARC_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_SPARC_NONE, 0) \ _ELF_DEFINE_RELOC(R_SPARC_8, 1) \ _ELF_DEFINE_RELOC(R_SPARC_16, 2) \ _ELF_DEFINE_RELOC(R_SPARC_32, 3) \ _ELF_DEFINE_RELOC(R_SPARC_DISP8, 4) \ _ELF_DEFINE_RELOC(R_SPARC_DISP16, 5) \ _ELF_DEFINE_RELOC(R_SPARC_DISP32, 6) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP30, 7) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP22, 8) \ _ELF_DEFINE_RELOC(R_SPARC_HI22, 9) \ _ELF_DEFINE_RELOC(R_SPARC_22, 10) \ _ELF_DEFINE_RELOC(R_SPARC_13, 11) \ _ELF_DEFINE_RELOC(R_SPARC_LO10, 12) \ _ELF_DEFINE_RELOC(R_SPARC_GOT10, 13) \ _ELF_DEFINE_RELOC(R_SPARC_GOT13, 14) \ _ELF_DEFINE_RELOC(R_SPARC_GOT22, 15) \ _ELF_DEFINE_RELOC(R_SPARC_PC10, 16) \ _ELF_DEFINE_RELOC(R_SPARC_PC22, 17) \ _ELF_DEFINE_RELOC(R_SPARC_WPLT30, 18) \ _ELF_DEFINE_RELOC(R_SPARC_COPY, 19) \ _ELF_DEFINE_RELOC(R_SPARC_GLOB_DAT, 20) \ _ELF_DEFINE_RELOC(R_SPARC_JMP_SLOT, 21) \ _ELF_DEFINE_RELOC(R_SPARC_RELATIVE, 22) \ _ELF_DEFINE_RELOC(R_SPARC_UA32, 23) \ _ELF_DEFINE_RELOC(R_SPARC_PLT32, 24) \ _ELF_DEFINE_RELOC(R_SPARC_HIPLT22, 25) \ _ELF_DEFINE_RELOC(R_SPARC_LOPLT10, 26) \ _ELF_DEFINE_RELOC(R_SPARC_PCPLT32, 27) \ _ELF_DEFINE_RELOC(R_SPARC_PCPLT22, 28) \ _ELF_DEFINE_RELOC(R_SPARC_PCPLT10, 29) \ _ELF_DEFINE_RELOC(R_SPARC_10, 30) \ _ELF_DEFINE_RELOC(R_SPARC_11, 31) \ _ELF_DEFINE_RELOC(R_SPARC_64, 32) \ _ELF_DEFINE_RELOC(R_SPARC_OLO10, 33) \ _ELF_DEFINE_RELOC(R_SPARC_HH22, 34) \ _ELF_DEFINE_RELOC(R_SPARC_HM10, 35) \ _ELF_DEFINE_RELOC(R_SPARC_LM22, 36) \ _ELF_DEFINE_RELOC(R_SPARC_PC_HH22, 37) \ _ELF_DEFINE_RELOC(R_SPARC_PC_HM10, 38) \ _ELF_DEFINE_RELOC(R_SPARC_PC_LM22, 39) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP16, 40) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP19, 41) \ _ELF_DEFINE_RELOC(R_SPARC_7, 43) \ _ELF_DEFINE_RELOC(R_SPARC_5, 44) \ _ELF_DEFINE_RELOC(R_SPARC_6, 45) \ _ELF_DEFINE_RELOC(R_SPARC_DISP64, 46) \ _ELF_DEFINE_RELOC(R_SPARC_PLT64, 47) \ _ELF_DEFINE_RELOC(R_SPARC_HIX22, 48) \ _ELF_DEFINE_RELOC(R_SPARC_LOX10, 49) \ _ELF_DEFINE_RELOC(R_SPARC_H44, 50) \ _ELF_DEFINE_RELOC(R_SPARC_M44, 51) \ _ELF_DEFINE_RELOC(R_SPARC_L44, 52) \ _ELF_DEFINE_RELOC(R_SPARC_REGISTER, 53) \ _ELF_DEFINE_RELOC(R_SPARC_UA64, 54) \ _ELF_DEFINE_RELOC(R_SPARC_UA16, 55) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_HIX22, 80) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_LOX10, 81) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_HIX22, 82) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_LOX10, 83) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP, 84) \ _ELF_DEFINE_RELOC(R_SPARC_H34, 85) #define _ELF_DEFINE_X86_64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_X86_64_NONE, 0) \ _ELF_DEFINE_RELOC(R_X86_64_64, 1) \ _ELF_DEFINE_RELOC(R_X86_64_PC32, 2) \ _ELF_DEFINE_RELOC(R_X86_64_GOT32, 3) \ _ELF_DEFINE_RELOC(R_X86_64_PLT32, 4) \ _ELF_DEFINE_RELOC(R_X86_64_COPY, 5) \ _ELF_DEFINE_RELOC(R_X86_64_GLOB_DAT, 6) \ _ELF_DEFINE_RELOC(R_X86_64_JUMP_SLOT, 7) \ _ELF_DEFINE_RELOC(R_X86_64_RELATIVE, 8) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPCREL, 9) \ _ELF_DEFINE_RELOC(R_X86_64_32, 10) \ _ELF_DEFINE_RELOC(R_X86_64_32S, 11) \ _ELF_DEFINE_RELOC(R_X86_64_16, 12) \ _ELF_DEFINE_RELOC(R_X86_64_PC16, 13) \ _ELF_DEFINE_RELOC(R_X86_64_8, 14) \ _ELF_DEFINE_RELOC(R_X86_64_PC8, 15) \ _ELF_DEFINE_RELOC(R_X86_64_DTPMOD64, 16) \ _ELF_DEFINE_RELOC(R_X86_64_DTPOFF64, 17) \ _ELF_DEFINE_RELOC(R_X86_64_TPOFF64, 18) \ _ELF_DEFINE_RELOC(R_X86_64_TLSGD, 19) \ _ELF_DEFINE_RELOC(R_X86_64_TLSLD, 20) \ _ELF_DEFINE_RELOC(R_X86_64_DTPOFF32, 21) \ _ELF_DEFINE_RELOC(R_X86_64_GOTTPOFF, 22) \ _ELF_DEFINE_RELOC(R_X86_64_TPOFF32, 23) \ _ELF_DEFINE_RELOC(R_X86_64_PC64, 24) \ _ELF_DEFINE_RELOC(R_X86_64_GOTOFF64, 25) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC32, 26) \ _ELF_DEFINE_RELOC(R_X86_64_SIZE32, 32) \ _ELF_DEFINE_RELOC(R_X86_64_SIZE64, 33) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC32_TLSDESC, 34) \ _ELF_DEFINE_RELOC(R_X86_64_TLSDESC_CALL, 35) \ _ELF_DEFINE_RELOC(R_X86_64_TLSDESC, 36) #define _ELF_DEFINE_RELOCATIONS() \ _ELF_DEFINE_386_RELOCATIONS() \ _ELF_DEFINE_AMD64_RELOCATIONS() \ _ELF_DEFINE_ARM_RELOCATIONS() \ _ELF_DEFINE_IA64_RELOCATIONS() \ _ELF_DEFINE_MIPS_RELOCATIONS() \ _ELF_DEFINE_PPC32_RELOCATIONS() \ _ELF_DEFINE_PPC64_RELOCATIONS() \ _ELF_DEFINE_SPARC_RELOCATIONS() \ _ELF_DEFINE_X86_64_RELOCATIONS() #undef _ELF_DEFINE_RELOC #define _ELF_DEFINE_RELOC(N, V) N = V , enum { _ELF_DEFINE_RELOCATIONS() R__LAST__ }; #define PN_XNUM 0xFFFFU /* Use extended section numbering. */ /** ** ELF Types. **/ typedef uint32_t Elf32_Addr; /* Program address. */ typedef uint8_t Elf32_Byte; /* Unsigned tiny integer. */ typedef uint16_t Elf32_Half; /* Unsigned medium integer. */ typedef uint32_t Elf32_Off; /* File offset. */ typedef uint16_t Elf32_Section; /* Section index. */ typedef int32_t Elf32_Sword; /* Signed integer. */ typedef uint32_t Elf32_Word; /* Unsigned integer. */ typedef uint64_t Elf32_Lword; /* Unsigned long integer. */ typedef uint64_t Elf64_Addr; /* Program address. */ typedef uint8_t Elf64_Byte; /* Unsigned tiny integer. */ typedef uint16_t Elf64_Half; /* Unsigned medium integer. */ typedef uint64_t Elf64_Off; /* File offset. */ typedef uint16_t Elf64_Section; /* Section index. */ typedef int32_t Elf64_Sword; /* Signed integer. */ typedef uint32_t Elf64_Word; /* Unsigned integer. */ typedef uint64_t Elf64_Lword; /* Unsigned long integer. */ typedef uint64_t Elf64_Xword; /* Unsigned long integer. */ typedef int64_t Elf64_Sxword; /* Signed long integer. */ /* * Capability descriptors. */ /* 32-bit capability descriptor. */ typedef struct { Elf32_Word c_tag; /* Type of entry. */ union { Elf32_Word c_val; /* Integer value. */ Elf32_Addr c_ptr; /* Pointer value. */ } c_un; } Elf32_Cap; /* 64-bit capability descriptor. */ typedef struct { Elf64_Xword c_tag; /* Type of entry. */ union { Elf64_Xword c_val; /* Integer value. */ Elf64_Addr c_ptr; /* Pointer value. */ } c_un; } Elf64_Cap; /* * MIPS .conflict section entries. */ /* 32-bit entry. */ typedef struct { Elf32_Addr c_index; } Elf32_Conflict; /* 64-bit entry. */ typedef struct { Elf64_Addr c_index; } Elf64_Conflict; /* * Dynamic section entries. */ /* 32-bit entry. */ typedef struct { Elf32_Sword d_tag; /* Type of entry. */ union { Elf32_Word d_val; /* Integer value. */ Elf32_Addr d_ptr; /* Pointer value. */ } d_un; } Elf32_Dyn; /* 64-bit entry. */ typedef struct { Elf64_Sxword d_tag; /* Type of entry. */ union { Elf64_Xword d_val; /* Integer value. */ Elf64_Addr d_ptr; /* Pointer value; */ } d_un; } Elf64_Dyn; /* * The executable header (EHDR). */ /* 32 bit EHDR. */ typedef struct { unsigned char e_ident[EI_NIDENT]; /* ELF identification. */ Elf32_Half e_type; /* Object file type (ET_*). */ Elf32_Half e_machine; /* Machine type (EM_*). */ Elf32_Word e_version; /* File format version (EV_*). */ Elf32_Addr e_entry; /* Start address. */ Elf32_Off e_phoff; /* File offset to the PHDR table. */ Elf32_Off e_shoff; /* File offset to the SHDRheader. */ Elf32_Word e_flags; /* Flags (EF_*). */ Elf32_Half e_ehsize; /* Elf header size in bytes. */ Elf32_Half e_phentsize; /* PHDR table entry size in bytes. */ Elf32_Half e_phnum; /* Number of PHDR entries. */ Elf32_Half e_shentsize; /* SHDR table entry size in bytes. */ Elf32_Half e_shnum; /* Number of SHDR entries. */ Elf32_Half e_shstrndx; /* Index of section name string table. */ } Elf32_Ehdr; /* 64 bit EHDR. */ typedef struct { unsigned char e_ident[EI_NIDENT]; /* ELF identification. */ Elf64_Half e_type; /* Object file type (ET_*). */ Elf64_Half e_machine; /* Machine type (EM_*). */ Elf64_Word e_version; /* File format version (EV_*). */ Elf64_Addr e_entry; /* Start address. */ Elf64_Off e_phoff; /* File offset to the PHDR table. */ Elf64_Off e_shoff; /* File offset to the SHDRheader. */ Elf64_Word e_flags; /* Flags (EF_*). */ Elf64_Half e_ehsize; /* Elf header size in bytes. */ Elf64_Half e_phentsize; /* PHDR table entry size in bytes. */ Elf64_Half e_phnum; /* Number of PHDR entries. */ Elf64_Half e_shentsize; /* SHDR table entry size in bytes. */ Elf64_Half e_shnum; /* Number of SHDR entries. */ Elf64_Half e_shstrndx; /* Index of section name string table. */ } Elf64_Ehdr; /* * Shared object information. */ /* 32-bit entry. */ typedef struct { Elf32_Word l_name; /* The name of a shared object. */ Elf32_Word l_time_stamp; /* 32-bit timestamp. */ Elf32_Word l_checksum; /* Checksum of visible symbols, sizes. */ Elf32_Word l_version; /* Interface version string index. */ Elf32_Word l_flags; /* Flags (LL_*). */ } Elf32_Lib; /* 64-bit entry. */ typedef struct { - Elf64_Word l_name; - Elf64_Word l_time_stamp; - Elf64_Word l_checksum; - Elf64_Word l_version; - Elf64_Word l_flags; + Elf64_Word l_name; /* The name of a shared object. */ + Elf64_Word l_time_stamp; /* 32-bit timestamp. */ + Elf64_Word l_checksum; /* Checksum of visible symbols, sizes. */ + Elf64_Word l_version; /* Interface version string index. */ + Elf64_Word l_flags; /* Flags (LL_*). */ } Elf64_Lib; #define _ELF_DEFINE_LL_FLAGS() \ _ELF_DEFINE_LL(LL_NONE, 0, \ "no flags") \ _ELF_DEFINE_LL(LL_EXACT_MATCH, 0x1, \ "require an exact match") \ _ELF_DEFINE_LL(LL_IGNORE_INT_VER, 0x2, \ "ignore version incompatibilities") \ _ELF_DEFINE_LL(LL_REQUIRE_MINOR, 0x4, \ "") \ _ELF_DEFINE_LL(LL_EXPORTS, 0x8, \ "") \ _ELF_DEFINE_LL(LL_DELAY_LOAD, 0x10, \ "") \ _ELF_DEFINE_LL(LL_DELTA, 0x20, \ "") #undef _ELF_DEFINE_LL #define _ELF_DEFINE_LL(N, V, DESCR) N = V , enum { _ELF_DEFINE_LL_FLAGS() LL__LAST__ }; /* * Note tags */ #define _ELF_DEFINE_NOTE_ENTRY_TYPES() \ _ELF_DEFINE_NT(NT_ABI_TAG, 1, "Tag indicating the ABI") \ _ELF_DEFINE_NT(NT_GNU_HWCAP, 2, "Hardware capabilities") \ _ELF_DEFINE_NT(NT_GNU_BUILD_ID, 3, "Build id, set by ld(1)") \ _ELF_DEFINE_NT(NT_GNU_GOLD_VERSION, 4, \ "Version number of the GNU gold linker") \ _ELF_DEFINE_NT(NT_PRSTATUS, 1, "Process status") \ _ELF_DEFINE_NT(NT_FPREGSET, 2, "Floating point information") \ _ELF_DEFINE_NT(NT_PRPSINFO, 3, "Process information") \ _ELF_DEFINE_NT(NT_AUXV, 6, "Auxiliary vector") \ _ELF_DEFINE_NT(NT_PRXFPREG, 0x46E62B7FUL, \ "Linux user_xfpregs structure") \ _ELF_DEFINE_NT(NT_PSTATUS, 10, "Linux process status") \ _ELF_DEFINE_NT(NT_FPREGS, 12, "Linux floating point regset") \ _ELF_DEFINE_NT(NT_PSINFO, 13, "Linux process information") \ _ELF_DEFINE_NT(NT_LWPSTATUS, 16, "Linux lwpstatus_t type") \ _ELF_DEFINE_NT(NT_LWPSINFO, 17, "Linux lwpinfo_t type") #undef _ELF_DEFINE_NT #define _ELF_DEFINE_NT(N, V, DESCR) N = V , enum { _ELF_DEFINE_NOTE_ENTRY_TYPES() NT__LAST__ }; /* Aliases for the ABI tag. */ #define NT_FREEBSD_ABI_TAG NT_ABI_TAG #define NT_GNU_ABI_TAG NT_ABI_TAG #define NT_NETBSD_IDENT NT_ABI_TAG #define NT_OPENBSD_IDENT NT_ABI_TAG /* * Note descriptors. */ typedef struct { uint32_t n_namesz; /* Length of note's name. */ uint32_t n_descsz; /* Length of note's value. */ uint32_t n_type; /* Type of note. */ } Elf_Note; typedef Elf_Note Elf32_Nhdr; /* 32-bit note header. */ typedef Elf_Note Elf64_Nhdr; /* 64-bit note header. */ /* * MIPS ELF options descriptor header. */ typedef struct { Elf64_Byte kind; /* Type of options. */ Elf64_Byte size; /* Size of option descriptor. */ Elf64_Half section; /* Index of section affected. */ Elf64_Word info; /* Kind-specific information. */ } Elf_Options; /* * Option kinds. */ #define _ELF_DEFINE_OPTION_KINDS() \ _ELF_DEFINE_ODK(ODK_NULL, 0, "undefined") \ _ELF_DEFINE_ODK(ODK_REGINFO, 1, "register usage info") \ _ELF_DEFINE_ODK(ODK_EXCEPTIONS, 2, "exception processing info") \ _ELF_DEFINE_ODK(ODK_PAD, 3, "section padding") \ _ELF_DEFINE_ODK(ODK_HWPATCH, 4, "hardware patch applied") \ _ELF_DEFINE_ODK(ODK_FILL, 5, "fill value used by linker") \ _ELF_DEFINE_ODK(ODK_TAGS, 6, "reserved space for tools") \ _ELF_DEFINE_ODK(ODK_HWAND, 7, "hardware AND patch applied") \ _ELF_DEFINE_ODK(ODK_HWOR, 8, "hardware OR patch applied") \ _ELF_DEFINE_ODK(ODK_GP_GROUP, 9, \ "GP group to use for text/data sections") \ _ELF_DEFINE_ODK(ODK_IDENT, 10, "ID information") \ _ELF_DEFINE_ODK(ODK_PAGESIZE, 11, "page size infomation") #undef _ELF_DEFINE_ODK #define _ELF_DEFINE_ODK(N, V, DESCR) N = V , enum { _ELF_DEFINE_OPTION_KINDS() ODK__LAST__ }; /* * ODK_EXCEPTIONS info field masks. */ #define _ELF_DEFINE_ODK_EXCEPTIONS_MASK() \ _ELF_DEFINE_OEX(OEX_FPU_MIN, 0x0000001FUL, \ "minimum FPU exception which must be enabled") \ _ELF_DEFINE_OEX(OEX_FPU_MAX, 0x00001F00UL, \ "maximum FPU exception which can be enabled") \ _ELF_DEFINE_OEX(OEX_PAGE0, 0x00010000UL, \ "page zero must be mapped") \ _ELF_DEFINE_OEX(OEX_SMM, 0x00020000UL, \ "run in sequential memory mode") \ _ELF_DEFINE_OEX(OEX_PRECISEFP, 0x00040000UL, \ "run in precise FP exception mode") \ _ELF_DEFINE_OEX(OEX_DISMISS, 0x00080000UL, \ "dismiss invalid address traps") #undef _ELF_DEFINE_OEX #define _ELF_DEFINE_OEX(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_EXCEPTIONS_MASK() OEX__LAST__ }; /* * ODK_PAD info field masks. */ #define _ELF_DEFINE_ODK_PAD_MASK() \ _ELF_DEFINE_OPAD(OPAD_PREFIX, 0x0001) \ _ELF_DEFINE_OPAD(OPAD_POSTFIX, 0x0002) \ _ELF_DEFINE_OPAD(OPAD_SYMBOL, 0x0004) #undef _ELF_DEFINE_OPAD #define _ELF_DEFINE_OPAD(N, V) N = V , enum { _ELF_DEFINE_ODK_PAD_MASK() OPAD__LAST__ }; /* * ODK_HWPATCH info field masks. */ #define _ELF_DEFINE_ODK_HWPATCH_MASK() \ _ELF_DEFINE_OHW(OHW_R4KEOP, 0x00000001UL, \ "patch for R4000 branch at end-of-page bug") \ _ELF_DEFINE_OHW(OHW_R8KPFETCH, 0x00000002UL, \ "R8000 prefetch bug may occur") \ _ELF_DEFINE_OHW(OHW_R5KEOP, 0x00000004UL, \ "patch for R5000 branch at end-of-page bug") \ _ELF_DEFINE_OHW(OHW_R5KCVTL, 0x00000008UL, \ "R5000 cvt.[ds].l bug: clean == 1") \ _ELF_DEFINE_OHW(OHW_R10KLDL, 0x00000010UL, \ "needd patch for R10000 misaligned load") #undef _ELF_DEFINE_OHW #define _ELF_DEFINE_OHW(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_HWPATCH_MASK() OHW__LAST__ }; /* * ODK_HWAND/ODK_HWOR info field and hwp_flags[12] masks. */ #define _ELF_DEFINE_ODK_HWP_MASK() \ _ELF_DEFINE_HWP(OHWA0_R4KEOP_CHECKED, 0x00000001UL, \ "object checked for R4000 end-of-page bug") \ _ELF_DEFINE_HWP(OHWA0_R4KEOP_CLEAN, 0x00000002UL, \ "object verified clean for R4000 end-of-page bug") \ _ELF_DEFINE_HWP(OHWO0_FIXADE, 0x00000001UL, \ "object requires call to fixade") #undef _ELF_DEFINE_HWP #define _ELF_DEFINE_HWP(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_HWP_MASK() OHWX0__LAST__ }; /* * ODK_IDENT/ODK_GP_GROUP info field masks. */ #define _ELF_DEFINE_ODK_GP_MASK() \ _ELF_DEFINE_OGP(OGP_GROUP, 0x0000FFFFUL, "GP group number") \ _ELF_DEFINE_OGP(OGP_SELF, 0x00010000UL, \ "GP group is self-contained") #undef _ELF_DEFINE_OGP #define _ELF_DEFINE_OGP(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_GP_MASK() OGP__LAST__ }; /* * MIPS ELF register info descriptor. */ /* 32 bit RegInfo entry. */ typedef struct { Elf32_Word ri_gprmask; /* Mask of general register used. */ Elf32_Word ri_cprmask[4]; /* Mask of coprocessor register used. */ Elf32_Addr ri_gp_value; /* GP register value. */ } Elf32_RegInfo; /* 64 bit RegInfo entry. */ typedef struct { Elf64_Word ri_gprmask; /* Mask of general register used. */ Elf64_Word ri_pad; /* Padding. */ Elf64_Word ri_cprmask[4]; /* Mask of coprocessor register used. */ Elf64_Addr ri_gp_value; /* GP register value. */ } Elf64_RegInfo; /* * Program Header Table (PHDR) entries. */ /* 32 bit PHDR entry. */ typedef struct { Elf32_Word p_type; /* Type of segment. */ Elf32_Off p_offset; /* File offset to segment. */ Elf32_Addr p_vaddr; /* Virtual address in memory. */ Elf32_Addr p_paddr; /* Physical address (if relevant). */ Elf32_Word p_filesz; /* Size of segment in file. */ Elf32_Word p_memsz; /* Size of segment in memory. */ Elf32_Word p_flags; /* Segment flags. */ Elf32_Word p_align; /* Alignment constraints. */ } Elf32_Phdr; /* 64 bit PHDR entry. */ typedef struct { Elf64_Word p_type; /* Type of segment. */ - Elf64_Word p_flags; /* File offset to segment. */ - Elf64_Off p_offset; /* Virtual address in memory. */ - Elf64_Addr p_vaddr; /* Physical address (if relevant). */ - Elf64_Addr p_paddr; /* Size of segment in file. */ - Elf64_Xword p_filesz; /* Size of segment in memory. */ - Elf64_Xword p_memsz; /* Segment flags. */ + Elf64_Word p_flags; /* Segment flags. */ + Elf64_Off p_offset; /* File offset to segment. */ + Elf64_Addr p_vaddr; /* Virtual address in memory. */ + Elf64_Addr p_paddr; /* Physical address (if relevant). */ + Elf64_Xword p_filesz; /* Size of segment in file. */ + Elf64_Xword p_memsz; /* Size of segment in memory. */ Elf64_Xword p_align; /* Alignment constraints. */ } Elf64_Phdr; /* * Move entries, for describing data in COMMON blocks in a compact * manner. */ /* 32-bit move entry. */ typedef struct { Elf32_Lword m_value; /* Initialization value. */ Elf32_Word m_info; /* Encoded size and index. */ Elf32_Word m_poffset; /* Offset relative to symbol. */ Elf32_Half m_repeat; /* Repeat count. */ Elf32_Half m_stride; /* Number of units to skip. */ } Elf32_Move; /* 64-bit move entry. */ typedef struct { Elf64_Lword m_value; /* Initialization value. */ Elf64_Xword m_info; /* Encoded size and index. */ Elf64_Xword m_poffset; /* Offset relative to symbol. */ Elf64_Half m_repeat; /* Repeat count. */ Elf64_Half m_stride; /* Number of units to skip. */ } Elf64_Move; #define ELF32_M_SYM(I) ((I) >> 8) #define ELF32_M_SIZE(I) ((unsigned char) (I)) #define ELF32_M_INFO(M, S) (((M) << 8) + (unsigned char) (S)) #define ELF64_M_SYM(I) ((I) >> 8) #define ELF64_M_SIZE(I) ((unsigned char) (I)) #define ELF64_M_INFO(M, S) (((M) << 8) + (unsigned char) (S)) /* * Section Header Table (SHDR) entries. */ /* 32 bit SHDR */ typedef struct { Elf32_Word sh_name; /* index of section name */ Elf32_Word sh_type; /* section type */ Elf32_Word sh_flags; /* section flags */ Elf32_Addr sh_addr; /* in-memory address of section */ Elf32_Off sh_offset; /* file offset of section */ Elf32_Word sh_size; /* section size in bytes */ Elf32_Word sh_link; /* section header table link */ Elf32_Word sh_info; /* extra information */ Elf32_Word sh_addralign; /* alignment constraint */ Elf32_Word sh_entsize; /* size for fixed-size entries */ } Elf32_Shdr; /* 64 bit SHDR */ typedef struct { Elf64_Word sh_name; /* index of section name */ Elf64_Word sh_type; /* section type */ Elf64_Xword sh_flags; /* section flags */ Elf64_Addr sh_addr; /* in-memory address of section */ Elf64_Off sh_offset; /* file offset of section */ Elf64_Xword sh_size; /* section size in bytes */ Elf64_Word sh_link; /* section header table link */ Elf64_Word sh_info; /* extra information */ Elf64_Xword sh_addralign; /* alignment constraint */ Elf64_Xword sh_entsize; /* size for fixed-size entries */ } Elf64_Shdr; /* * Symbol table entries. */ typedef struct { Elf32_Word st_name; /* index of symbol's name */ Elf32_Addr st_value; /* value for the symbol */ Elf32_Word st_size; /* size of associated data */ unsigned char st_info; /* type and binding attributes */ unsigned char st_other; /* visibility */ Elf32_Half st_shndx; /* index of related section */ } Elf32_Sym; typedef struct { Elf64_Word st_name; /* index of symbol's name */ - unsigned char st_info; /* value for the symbol */ - unsigned char st_other; /* size of associated data */ - Elf64_Half st_shndx; /* type and binding attributes */ - Elf64_Addr st_value; /* visibility */ - Elf64_Xword st_size; /* index of related section */ + unsigned char st_info; /* type and binding attributes */ + unsigned char st_other; /* visibility */ + Elf64_Half st_shndx; /* index of related section */ + Elf64_Addr st_value; /* value for the symbol */ + Elf64_Xword st_size; /* size of associated data */ } Elf64_Sym; #define ELF32_ST_BIND(I) ((I) >> 4) #define ELF32_ST_TYPE(I) ((I) & 0xFU) #define ELF32_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF)) #define ELF64_ST_BIND(I) ((I) >> 4) #define ELF64_ST_TYPE(I) ((I) & 0xFU) #define ELF64_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF)) #define ELF32_ST_VISIBILITY(O) ((O) & 0x3) #define ELF64_ST_VISIBILITY(O) ((O) & 0x3) /* * Syminfo descriptors, containing additional symbol information. */ /* 32-bit entry. */ typedef struct { Elf32_Half si_boundto; /* Entry index with additional flags. */ Elf32_Half si_flags; /* Flags. */ } Elf32_Syminfo; /* 64-bit entry. */ typedef struct { Elf64_Half si_boundto; /* Entry index with additional flags. */ Elf64_Half si_flags; /* Flags. */ } Elf64_Syminfo; /* * Relocation descriptors. */ typedef struct { Elf32_Addr r_offset; /* location to apply relocation to */ Elf32_Word r_info; /* type+section for relocation */ } Elf32_Rel; typedef struct { Elf32_Addr r_offset; /* location to apply relocation to */ Elf32_Word r_info; /* type+section for relocation */ Elf32_Sword r_addend; /* constant addend */ } Elf32_Rela; typedef struct { Elf64_Addr r_offset; /* location to apply relocation to */ Elf64_Xword r_info; /* type+section for relocation */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset; /* location to apply relocation to */ Elf64_Xword r_info; /* type+section for relocation */ Elf64_Sxword r_addend; /* constant addend */ } Elf64_Rela; #define ELF32_R_SYM(I) ((I) >> 8) #define ELF32_R_TYPE(I) ((unsigned char) (I)) #define ELF32_R_INFO(S,T) (((S) << 8) + (unsigned char) (T)) #define ELF64_R_SYM(I) ((I) >> 32) #define ELF64_R_TYPE(I) ((I) & 0xFFFFFFFFUL) #define ELF64_R_INFO(S,T) (((S) << 32) + ((T) & 0xFFFFFFFFUL)) /* * Symbol versioning structures. */ /* 32-bit structures. */ typedef struct { Elf32_Word vda_name; /* Index to name. */ Elf32_Word vda_next; /* Offset to next entry. */ } Elf32_Verdaux; typedef struct { Elf32_Word vna_hash; /* Hash value of dependency name. */ Elf32_Half vna_flags; /* Flags. */ Elf32_Half vna_other; /* Unused. */ Elf32_Word vna_name; /* Offset to dependency name. */ Elf32_Word vna_next; /* Offset to next vernaux entry. */ } Elf32_Vernaux; typedef struct { Elf32_Half vd_version; /* Version information. */ Elf32_Half vd_flags; /* Flags. */ Elf32_Half vd_ndx; /* Index into the versym section. */ Elf32_Half vd_cnt; /* Number of aux entries. */ Elf32_Word vd_hash; /* Hash value of name. */ Elf32_Word vd_aux; /* Offset to aux entries. */ Elf32_Word vd_next; /* Offset to next version definition. */ } Elf32_Verdef; typedef struct { Elf32_Half vn_version; /* Version number. */ Elf32_Half vn_cnt; /* Number of aux entries. */ Elf32_Word vn_file; /* Offset of associated file name. */ Elf32_Word vn_aux; /* Offset of vernaux array. */ Elf32_Word vn_next; /* Offset of next verneed entry. */ } Elf32_Verneed; typedef Elf32_Half Elf32_Versym; /* 64-bit structures. */ typedef struct { Elf64_Word vda_name; /* Index to name. */ Elf64_Word vda_next; /* Offset to next entry. */ } Elf64_Verdaux; typedef struct { Elf64_Word vna_hash; /* Hash value of dependency name. */ Elf64_Half vna_flags; /* Flags. */ Elf64_Half vna_other; /* Unused. */ Elf64_Word vna_name; /* Offset to dependency name. */ Elf64_Word vna_next; /* Offset to next vernaux entry. */ } Elf64_Vernaux; typedef struct { Elf64_Half vd_version; /* Version information. */ Elf64_Half vd_flags; /* Flags. */ Elf64_Half vd_ndx; /* Index into the versym section. */ Elf64_Half vd_cnt; /* Number of aux entries. */ Elf64_Word vd_hash; /* Hash value of name. */ Elf64_Word vd_aux; /* Offset to aux entries. */ Elf64_Word vd_next; /* Offset to next version definition. */ } Elf64_Verdef; typedef struct { Elf64_Half vn_version; /* Version number. */ Elf64_Half vn_cnt; /* Number of aux entries. */ Elf64_Word vn_file; /* Offset of associated file name. */ Elf64_Word vn_aux; /* Offset of vernaux array. */ Elf64_Word vn_next; /* Offset of next verneed entry. */ } Elf64_Verneed; typedef Elf64_Half Elf64_Versym; /* * The header for GNU-style hash sections. */ typedef struct { uint32_t gh_nbuckets; /* Number of hash buckets. */ uint32_t gh_symndx; /* First visible symbol in .dynsym. */ uint32_t gh_maskwords; /* #maskwords used in bloom filter. */ uint32_t gh_shift2; /* Bloom filter shift count. */ } Elf_GNU_Hash_Header; #endif /* _ELFDEFINITIONS_H_ */ diff --git a/elfcopy/archive.c b/elfcopy/archive.c index a4f8017989ba..4735f02296e3 100644 --- a/elfcopy/archive.c +++ b/elfcopy/archive.c @@ -1,528 +1,525 @@ /*- * Copyright (c) 2007-2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #ifndef LIBELF_AR #include #include #endif /* ! LIBELF_AR */ #include "elfcopy.h" -ELFTC_VCSID("$Id: archive.c 2370 2011-12-29 12:48:12Z jkoshy $"); +ELFTC_VCSID("$Id: archive.c 3102 2014-10-29 21:09:01Z jkoshy $"); #define _ARMAG_LEN 8 /* length of ar magic string */ #define _ARHDR_LEN 60 /* length of ar header */ #define _INIT_AS_CAP 128 /* initial archive string table size */ #define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ #define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ #define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ #ifndef LIBELF_AR static void ac_read_objs(struct elfcopy *ecp, int ifd); static void ac_write_cleanup(struct elfcopy *ecp); static void ac_write_data(struct archive *a, const void *buf, size_t s); static void ac_write_objs(struct elfcopy *ecp, int ofd); #endif /* ! LIBELF_AR */ static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name); static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name); static void extract_arsym(struct elfcopy *ecp); static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj); static void sync_ar(struct elfcopy *ecp); static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj) { struct stat sb; char *tempfile; int fd; /* Output to a temporary file. */ create_tempfile(&tempfile, &fd); if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); create_elf(ecp); elf_end(ecp->ein); elf_end(ecp->eout); free(obj->buf); obj->buf = NULL; /* Extract archive symbols. */ if (lseek(fd, 0, SEEK_SET) < 0) err(EXIT_FAILURE, "lseek failed for '%s'", tempfile); if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); extract_arsym(ecp); elf_end(ecp->eout); if (fstat(fd, &sb) == -1) err(EXIT_FAILURE, "fstat %s failed", tempfile); if (lseek(fd, 0, SEEK_SET) < 0) err(EXIT_FAILURE, "lseek %s failed", tempfile); obj->size = sb.st_size; if ((obj->maddr = malloc(obj->size)) == NULL) err(EXIT_FAILURE, "memory allocation failed for '%s'", tempfile); if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) err(EXIT_FAILURE, "read failed for '%s'", tempfile); if (unlink(tempfile)) err(EXIT_FAILURE, "unlink %s failed", tempfile); free(tempfile); close(fd); if (strlen(obj->name) > _MAXNAMELEN_SVR4) add_to_ar_str_table(ecp, obj->name); ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs); } /* * Append to the archive string table buffer. */ static void add_to_ar_str_table(struct elfcopy *ecp, const char *name) { if (ecp->as == NULL) { ecp->as_cap = _INIT_AS_CAP; ecp->as_sz = 0; if ((ecp->as = malloc(ecp->as_cap)) == NULL) err(EXIT_FAILURE, "malloc failed"); } /* * The space required for holding one member name in as table includes: * strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). */ while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) { ecp->as_cap *= 2; ecp->as = realloc(ecp->as, ecp->as_cap); if (ecp->as == NULL) err(EXIT_FAILURE, "realloc failed"); } strncpy(&ecp->as[ecp->as_sz], name, strlen(name)); ecp->as_sz += strlen(name); ecp->as[ecp->as_sz++] = '/'; ecp->as[ecp->as_sz++] = '\n'; } /* * Append to the archive symbol table buffer. */ static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name) { if (ecp->s_so == NULL) { if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL) err(EXIT_FAILURE, "malloc failed"); ecp->s_so_cap = _INIT_SYMOFF_CAP; ecp->s_cnt = 0; } if (ecp->s_sn == NULL) { if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) err(EXIT_FAILURE, "malloc failed"); ecp->s_sn_cap = _INIT_SYMNAME_CAP; ecp->s_sn_sz = 0; } if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) { ecp->s_so_cap *= 2; ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap); if (ecp->s_so == NULL) err(EXIT_FAILURE, "realloc failed"); } ecp->s_so[ecp->s_cnt] = ecp->rela_off; ecp->s_cnt++; /* * The space required for holding one symbol name in sn table includes: * strlen(name) + (1 for '\n') + (possibly 1 for padding). */ while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) { ecp->s_sn_cap *= 2; ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap); if (ecp->s_sn == NULL) err(EXIT_FAILURE, "realloc failed"); } strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name)); ecp->s_sn_sz += strlen(name); ecp->s_sn[ecp->s_sn_sz++] = '\0'; } static void sync_ar(struct elfcopy *ecp) { size_t s_sz; /* size of archive symbol table. */ size_t pm_sz; /* size of pseudo members */ int i; /* * Pad the symbol name string table. It is treated specially because * symbol name table should be padded by a '\0', not the common '\n' * for other members. The size of sn table includes the pad bit. */ if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0) ecp->s_sn[ecp->s_sn_sz++] = '\0'; /* * Archive string table is padded by a "\n" as the normal members. * The difference is that the size of archive string table counts * in the pad bit, while normal members' size fileds do not. */ if (ecp->as != NULL && ecp->as_sz % 2 != 0) ecp->as[ecp->as_sz++] = '\n'; /* * If there is a symbol table, calculate the size of pseudo members, * convert previously stored relative offsets to absolute ones, and * then make them Big Endian. * * absolute_offset = htobe32(relative_offset + size_of_pseudo_members) */ if (ecp->s_cnt != 0) { s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz; pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); if (ecp->as != NULL) pm_sz += _ARHDR_LEN + ecp->as_sz; for (i = 0; (size_t)i < ecp->s_cnt; i++) *(ecp->s_so + i) = htobe32(*(ecp->s_so + i) + pm_sz); } } /* * Extract global symbols from archive members. */ static void extract_arsym(struct elfcopy *ecp) { Elf_Scn *scn; GElf_Shdr shdr; GElf_Sym sym; Elf_Data *data; char *name; size_t n, shstrndx; int elferr, tabndx, len, i; if (elf_kind(ecp->eout) != ELF_K_ELF) { warnx("internal: cannot extract symbols from non-elf object"); return; } if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) { warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); return; } tabndx = -1; scn = NULL; while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { warnx("elf_getshdr failed: %s", elf_errmsg(-1)); continue; } if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) == NULL) { warnx("elf_strptr failed: %s", elf_errmsg(-1)); continue; } if (strcmp(name, ".strtab") == 0) { tabndx = elf_ndxscn(scn); break; } } elferr = elf_errno(); if (elferr != 0) warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); /* Ignore members without symbol table. */ if (tabndx == -1) return; scn = NULL; while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { warnx("elf_getshdr failed: %s", elf_errmsg(-1)); continue; } if (shdr.sh_type != SHT_SYMTAB) continue; data = NULL; n = 0; while (n < shdr.sh_size && (data = elf_getdata(scn, data)) != NULL) { len = data->d_size / shdr.sh_entsize; for (i = 0; i < len; i++) { if (gelf_getsym(data, i, &sym) != &sym) { warnx("gelf_getsym failed: %s", elf_errmsg(-1)); continue; } /* keep only global or weak symbols */ if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && GELF_ST_BIND(sym.st_info) != STB_WEAK) continue; /* keep only defined symbols */ if (sym.st_shndx == SHN_UNDEF) continue; if ((name = elf_strptr(ecp->eout, tabndx, sym.st_name)) == NULL) { warnx("elf_strptr failed: %s", elf_errmsg(-1)); continue; } add_to_ar_sym_table(ecp, name); } } } elferr = elf_errno(); if (elferr != 0) warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); } #ifndef LIBELF_AR /* * Convenient wrapper for general libarchive error handling. */ #define AC(CALL) do { \ if ((CALL)) \ errx(EXIT_FAILURE, "%s", archive_error_string(a)); \ } while (0) /* Earlier versions of libarchive had some functions that returned 'void'. */ #if ARCHIVE_VERSION_NUMBER >= 2000000 #define ACV(CALL) AC(CALL) #else #define ACV(CALL) do { \ (CALL); \ } while (0) #endif int ac_detect_ar(int ifd) { struct archive *a; struct archive_entry *entry; int r; r = -1; if ((a = archive_read_new()) == NULL) return (0); - archive_read_support_compression_none(a); archive_read_support_format_ar(a); if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK) r = archive_read_next_header(a, &entry); archive_read_close(a); - archive_read_finish(a); + archive_read_free(a); return (r == ARCHIVE_OK); } void ac_create_ar(struct elfcopy *ecp, int ifd, int ofd) { ac_read_objs(ecp, ifd); sync_ar(ecp); ac_write_objs(ecp, ofd); ac_write_cleanup(ecp); } static void ac_read_objs(struct elfcopy *ecp, int ifd) { struct archive *a; struct archive_entry *entry; struct ar_obj *obj; const char *name; char *buff; size_t size; int r; ecp->rela_off = 0; if (lseek(ifd, 0, SEEK_SET) == -1) err(EXIT_FAILURE, "lseek failed"); if ((a = archive_read_new()) == NULL) errx(EXIT_FAILURE, "%s", archive_error_string(a)); - archive_read_support_compression_none(a); archive_read_support_format_ar(a); AC(archive_read_open_fd(a, ifd, 10240)); for(;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_FATAL) errx(EXIT_FAILURE, "%s", archive_error_string(a)); if (r == ARCHIVE_EOF) break; if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) warnx("%s", archive_error_string(a)); if (r == ARCHIVE_RETRY) continue; name = archive_entry_pathname(entry); /* skip pseudo members. */ if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) continue; size = archive_entry_size(entry); if (size > 0) { if ((buff = malloc(size)) == NULL) err(EXIT_FAILURE, "malloc failed"); if (archive_read_data(a, buff, size) != (ssize_t)size) { warnx("%s", archive_error_string(a)); free(buff); continue; } if ((obj = malloc(sizeof(*obj))) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((obj->name = strdup(name)) == NULL) err(EXIT_FAILURE, "strdup failed"); obj->buf = buff; obj->uid = archive_entry_uid(entry); obj->gid = archive_entry_gid(entry); obj->md = archive_entry_mode(entry); obj->mtime = archive_entry_mtime(entry); if ((ecp->ein = elf_memory(buff, size)) == NULL) errx(EXIT_FAILURE, "elf_memory() failed: %s", elf_errmsg(-1)); if (elf_kind(ecp->ein) != ELF_K_ELF) errx(EXIT_FAILURE, "file format not recognized"); process_ar_obj(ecp, obj); } } AC(archive_read_close(a)); - ACV(archive_read_finish(a)); + ACV(archive_read_free(a)); } static void ac_write_objs(struct elfcopy *ecp, int ofd) { struct archive *a; struct archive_entry *entry; struct ar_obj *obj; int nr; if ((a = archive_write_new()) == NULL) errx(EXIT_FAILURE, "%s", archive_error_string(a)); archive_write_set_format_ar_svr4(a); - archive_write_set_compression_none(a); AC(archive_write_open_fd(a, ofd)); /* Write the archive symbol table, even if it's empty. */ entry = archive_entry_new(); archive_entry_copy_pathname(entry, "/"); archive_entry_set_mtime(entry, time(NULL), 0); archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz); AC(archive_write_header(a, entry)); nr = htobe32(ecp->s_cnt); ac_write_data(a, &nr, sizeof(uint32_t)); ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt); ac_write_data(a, ecp->s_sn, ecp->s_sn_sz); archive_entry_free(entry); /* Write the archive string table, if exist. */ if (ecp->as != NULL) { entry = archive_entry_new(); archive_entry_copy_pathname(entry, "//"); archive_entry_set_size(entry, ecp->as_sz); AC(archive_write_header(a, entry)); ac_write_data(a, ecp->as, ecp->as_sz); archive_entry_free(entry); } /* Write normal members. */ STAILQ_FOREACH(obj, &ecp->v_arobj, objs) { entry = archive_entry_new(); archive_entry_copy_pathname(entry, obj->name); archive_entry_set_uid(entry, obj->uid); archive_entry_set_gid(entry, obj->gid); archive_entry_set_mode(entry, obj->md); archive_entry_set_size(entry, obj->size); archive_entry_set_mtime(entry, obj->mtime, 0); archive_entry_set_filetype(entry, AE_IFREG); AC(archive_write_header(a, entry)); ac_write_data(a, obj->maddr, obj->size); archive_entry_free(entry); } AC(archive_write_close(a)); - ACV(archive_write_finish(a)); + ACV(archive_write_free(a)); } static void ac_write_cleanup(struct elfcopy *ecp) { struct ar_obj *obj, *obj_temp; STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) { STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs); if (obj->maddr != NULL) free(obj->maddr); free(obj->name); free(obj); } free(ecp->as); free(ecp->s_so); free(ecp->s_sn); ecp->as = NULL; ecp->s_so = NULL; ecp->s_sn = NULL; } /* * Wrapper for archive_write_data(). */ static void ac_write_data(struct archive *a, const void *buf, size_t s) { if (archive_write_data(a, buf, s) != (ssize_t)s) errx(EXIT_FAILURE, "%s", archive_error_string(a)); } #endif /* ! LIBELF_AR */ diff --git a/elfcopy/main.c b/elfcopy/main.c index 3689f355fecd..0ba4e6864c86 100644 --- a/elfcopy/main.c +++ b/elfcopy/main.c @@ -1,1500 +1,1501 @@ /*- * Copyright (c) 2007-2013 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: main.c 2970 2013-12-01 15:22:12Z kaiwang27 $"); +ELFTC_VCSID("$Id: main.c 3111 2014-12-20 08:33:01Z kaiwang27 $"); enum options { ECP_ADD_GNU_DEBUGLINK, ECP_ADD_SECTION, ECP_CHANGE_ADDR, ECP_CHANGE_SEC_ADDR, ECP_CHANGE_SEC_LMA, ECP_CHANGE_SEC_VMA, ECP_CHANGE_START, ECP_CHANGE_WARN, ECP_GAP_FILL, ECP_GLOBALIZE_SYMBOL, ECP_GLOBALIZE_SYMBOLS, ECP_KEEP_SYMBOLS, ECP_KEEP_GLOBAL_SYMBOLS, ECP_LOCALIZE_SYMBOLS, ECP_NO_CHANGE_WARN, ECP_ONLY_DEBUG, ECP_PAD_TO, ECP_PREFIX_ALLOC, ECP_PREFIX_SEC, ECP_PREFIX_SYM, ECP_REDEF_SYMBOL, ECP_REDEF_SYMBOLS, ECP_RENAME_SECTION, ECP_SET_OSABI, ECP_SET_SEC_FLAGS, ECP_SET_START, ECP_SREC_FORCE_S3, ECP_SREC_LEN, ECP_STRIP_SYMBOLS, ECP_STRIP_UNNEEDED, ECP_WEAKEN_ALL, ECP_WEAKEN_SYMBOLS }; static struct option mcs_longopts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; static struct option strip_longopts[] = { {"discard-all", no_argument, NULL, 'x'}, {"discard-locals", no_argument, NULL, 'X'}, {"help", no_argument, NULL, 'h'}, {"input-target", required_argument, NULL, 'I'}, {"keep-symbol", required_argument, NULL, 'K'}, {"only-keep-debug", no_argument, NULL, ECP_ONLY_DEBUG}, {"output-file", required_argument, NULL, 'o'}, {"output-target", required_argument, NULL, 'O'}, {"preserve-dates", no_argument, NULL, 'p'}, {"remove-section", required_argument, NULL, 'R'}, {"strip-all", no_argument, NULL, 's'}, {"strip-debug", no_argument, NULL, 'S'}, {"strip-symbol", required_argument, NULL, 'N'}, {"strip-unneeded", no_argument, NULL, ECP_STRIP_UNNEEDED}, {"version", no_argument, NULL, 'V'}, {"wildcard", no_argument, NULL, 'w'}, {NULL, 0, NULL, 0} }; static struct option elfcopy_longopts[] = { {"add-gnu-debuglink", required_argument, NULL, ECP_ADD_GNU_DEBUGLINK}, {"add-section", required_argument, NULL, ECP_ADD_SECTION}, {"adjust-section-vma", required_argument, NULL, ECP_CHANGE_SEC_ADDR}, {"adjust-vma", required_argument, NULL, ECP_CHANGE_ADDR}, {"adjust-start", required_argument, NULL, ECP_CHANGE_START}, {"adjust-warnings", no_argument, NULL, ECP_CHANGE_WARN}, {"binary-architecture", required_argument, NULL, 'B'}, {"change-addresses", required_argument, NULL, ECP_CHANGE_ADDR}, {"change-section-address", required_argument, NULL, ECP_CHANGE_SEC_ADDR}, {"change-section-lma", required_argument, NULL, ECP_CHANGE_SEC_LMA}, {"change-section-vma", required_argument, NULL, ECP_CHANGE_SEC_VMA}, {"change-start", required_argument, NULL, ECP_CHANGE_START}, {"change-warnings", no_argument, NULL, ECP_CHANGE_WARN}, {"discard-all", no_argument, NULL, 'x'}, {"discard-locals", no_argument, NULL, 'X'}, {"gap-fill", required_argument, NULL, ECP_GAP_FILL}, {"globalize-symbol", required_argument, NULL, ECP_GLOBALIZE_SYMBOL}, {"globalize-symbols", required_argument, NULL, ECP_GLOBALIZE_SYMBOLS}, {"help", no_argument, NULL, 'h'}, {"input-target", required_argument, NULL, 'I'}, {"keep-symbol", required_argument, NULL, 'K'}, {"keep-symbols", required_argument, NULL, ECP_KEEP_SYMBOLS}, {"keep-global-symbol", required_argument, NULL, 'G'}, {"keep-global-symbols", required_argument, NULL, ECP_KEEP_GLOBAL_SYMBOLS}, {"localize-symbol", required_argument, NULL, 'L'}, {"localize-symbols", required_argument, NULL, ECP_LOCALIZE_SYMBOLS}, {"no-adjust-warnings", no_argument, NULL, ECP_NO_CHANGE_WARN}, {"no-change-warnings", no_argument, NULL, ECP_NO_CHANGE_WARN}, {"only-keep-debug", no_argument, NULL, ECP_ONLY_DEBUG}, {"only-section", required_argument, NULL, 'j'}, {"osabi", required_argument, NULL, ECP_SET_OSABI}, {"output-target", required_argument, NULL, 'O'}, {"pad-to", required_argument, NULL, ECP_PAD_TO}, {"preserve-dates", no_argument, NULL, 'p'}, {"prefix-alloc-sections", required_argument, NULL, ECP_PREFIX_ALLOC}, {"prefix-sections", required_argument, NULL, ECP_PREFIX_SEC}, {"prefix-symbols", required_argument, NULL, ECP_PREFIX_SYM}, {"redefine-sym", required_argument, NULL, ECP_REDEF_SYMBOL}, {"redefine-syms", required_argument, NULL, ECP_REDEF_SYMBOLS}, {"remove-section", required_argument, NULL, 'R'}, {"rename-section", required_argument, NULL, ECP_RENAME_SECTION}, {"set-section-flags", required_argument, NULL, ECP_SET_SEC_FLAGS}, {"set-start", required_argument, NULL, ECP_SET_START}, {"srec-forceS3", no_argument, NULL, ECP_SREC_FORCE_S3}, {"srec-len", required_argument, NULL, ECP_SREC_LEN}, {"strip-all", no_argument, NULL, 'S'}, {"strip-debug", no_argument, 0, 'g'}, {"strip-symbol", required_argument, NULL, 'N'}, {"strip-symbols", required_argument, NULL, ECP_STRIP_SYMBOLS}, {"strip-unneeded", no_argument, NULL, ECP_STRIP_UNNEEDED}, {"version", no_argument, NULL, 'V'}, {"weaken", no_argument, NULL, ECP_WEAKEN_ALL}, {"weaken-symbol", required_argument, NULL, 'W'}, {"weaken-symbols", required_argument, NULL, ECP_WEAKEN_SYMBOLS}, {"wildcard", no_argument, NULL, 'w'}, {NULL, 0, NULL, 0} }; static struct { const char *name; int value; } sec_flags[] = { {"alloc", SF_ALLOC}, {"load", SF_LOAD}, {"noload", SF_NOLOAD}, {"readonly", SF_READONLY}, {"debug", SF_DEBUG}, {"code", SF_CODE}, {"data", SF_DATA}, {"rom", SF_ROM}, {"share", SF_SHARED}, {"contents", SF_CONTENTS}, {NULL, 0} }; static struct { const char *name; int abi; } osabis[] = { {"sysv", ELFOSABI_SYSV}, {"hpus", ELFOSABI_HPUX}, {"netbsd", ELFOSABI_NETBSD}, {"linux", ELFOSABI_LINUX}, {"hurd", ELFOSABI_HURD}, {"86open", ELFOSABI_86OPEN}, {"solaris", ELFOSABI_SOLARIS}, {"aix", ELFOSABI_AIX}, {"irix", ELFOSABI_IRIX}, {"freebsd", ELFOSABI_FREEBSD}, {"tru64", ELFOSABI_TRU64}, {"modesto", ELFOSABI_MODESTO}, {"openbsd", ELFOSABI_OPENBSD}, {"openvms", ELFOSABI_OPENVMS}, {"nsk", ELFOSABI_NSK}, {"arm", ELFOSABI_ARM}, {"standalone", ELFOSABI_STANDALONE}, {NULL, 0} }; static int copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd); static void create_file(struct elfcopy *ecp, const char *src, const char *dst); static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv); static void elfcopy_usage(void); static void mcs_main(struct elfcopy *ecp, int argc, char **argv); static void mcs_usage(void); static void parse_sec_address_op(struct elfcopy *ecp, int optnum, const char *optname, char *s); static void parse_sec_flags(struct sec_action *sac, char *s); static void parse_symlist_file(struct elfcopy *ecp, const char *fn, unsigned int op); static void print_version(void); static void set_input_target(struct elfcopy *ecp, const char *target_name); static void set_osabi(struct elfcopy *ecp, const char *abi); static void set_output_target(struct elfcopy *ecp, const char *target_name); static void strip_main(struct elfcopy *ecp, int argc, char **argv); static void strip_usage(void); /* * An ELF object usually has a sturcture described by the * diagram below. * _____________ * | | * | NULL | <- always a SHT_NULL section * |_____________| * | | * | .interp | * |_____________| * | | * | ... | * |_____________| * | | * | .text | * |_____________| * | | * | ... | * |_____________| * | | * | .comment | <- above(include) this: normal sections * |_____________| * | | * | add sections| <- unloadable sections added by --add-section * |_____________| * | | * | .shstrtab | <- section name string table * |_____________| * | | * | shdrs | <- section header table * |_____________| * | | * | .symtab | <- symbol table, if any * |_____________| * | | * | .strtab | <- symbol name string table, if any * |_____________| * | | * | .rel.text | <- relocation info for .o files. * |_____________| */ void create_elf(struct elfcopy *ecp) { struct section *shtab; GElf_Ehdr ieh; GElf_Ehdr oeh; size_t ishnum; ecp->flags |= SYMTAB_INTACT; /* Create EHDR. */ if (gelf_getehdr(ecp->ein, &ieh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); if ((ecp->iec = gelf_getclass(ecp->ein)) == ELFCLASSNONE) errx(EXIT_FAILURE, "getclass() failed: %s", elf_errmsg(-1)); if (ecp->oec == ELFCLASSNONE) ecp->oec = ecp->iec; if (ecp->oed == ELFDATANONE) ecp->oed = ieh.e_ident[EI_DATA]; if (gelf_newehdr(ecp->eout, ecp->oec) == NULL) errx(EXIT_FAILURE, "gelf_newehdr failed: %s", elf_errmsg(-1)); if (gelf_getehdr(ecp->eout, &oeh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); memcpy(oeh.e_ident, ieh.e_ident, sizeof(ieh.e_ident)); oeh.e_ident[EI_CLASS] = ecp->oec; oeh.e_ident[EI_DATA] = ecp->oed; if (ecp->abi != -1) oeh.e_ident[EI_OSABI] = ecp->abi; oeh.e_flags = ieh.e_flags; oeh.e_machine = ieh.e_machine; oeh.e_type = ieh.e_type; oeh.e_entry = ieh.e_entry; oeh.e_version = ieh.e_version; if (ieh.e_type == ET_EXEC) ecp->flags |= EXECUTABLE; else if (ieh.e_type == ET_DYN) ecp->flags |= DYNAMIC; else if (ieh.e_type == ET_REL) ecp->flags |= RELOCATABLE; else errx(EXIT_FAILURE, "unsupported e_type"); if (!elf_getshnum(ecp->ein, &ishnum)) errx(EXIT_FAILURE, "elf_getshnum failed: %s", elf_errmsg(-1)); if (ishnum > 0 && (ecp->secndx = calloc(ishnum, sizeof(*ecp->secndx))) == NULL) err(EXIT_FAILURE, "calloc failed"); /* Read input object program header. */ setup_phdr(ecp); /* * Scan of input sections: we iterate through sections from input * object, skip sections need to be stripped, allot Elf_Scn and * create internal section structure for sections we want. * (i.e., determine output sections) */ create_scn(ecp); /* Apply section address changes, if any. */ adjust_addr(ecp); /* * Determine if the symbol table needs to be changed based on * command line options. */ if (ecp->strip == STRIP_DEBUG || ecp->strip == STRIP_UNNEEDED || ecp->flags & WEAKEN_ALL || ecp->flags & DISCARD_LOCAL || ecp->flags & DISCARD_LLABEL || ecp->prefix_sym != NULL || !STAILQ_EMPTY(&ecp->v_symop)) ecp->flags &= ~SYMTAB_INTACT; /* * Create symbol table. Symbols are filtered or stripped according to * command line args specified by user, and later updated for the new * layout of sections in the output object. */ if ((ecp->flags & SYMTAB_EXIST) != 0) create_symtab(ecp); /* * First processing of output sections: at this stage we copy the * content of each section from input to output object. Section * content will be modified and printed (mcs) if need. Also content of * relocation section probably will be filtered and updated according * to symbol table changes. */ copy_content(ecp); /* * Write the underlying ehdr. Note that it should be called * before elf_setshstrndx() since it will overwrite e->e_shstrndx. */ if (gelf_update_ehdr(ecp->eout, &oeh) == 0) errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", elf_errmsg(-1)); /* Generate section name string table (.shstrtab). */ set_shstrtab(ecp); /* * Second processing of output sections: Update section headers. * At this stage we set name string index, update st_link and st_info * for output sections. */ update_shdr(ecp, 1); /* Renew oeh to get the updated e_shstrndx. */ if (gelf_getehdr(ecp->eout, &oeh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); /* * Insert SHDR table into the internal section list as a "pseudo" * section, so later it will get sorted and resynced just as "normal" * sections. */ shtab = insert_shtab(ecp, 0); /* * Resync section offsets in the output object. This is needed * because probably sections are modified or new sections are added, * as a result overlap/gap might appears. */ resync_sections(ecp); /* Store SHDR offset in EHDR. */ oeh.e_shoff = shtab->off; /* Put program header table immediately after the Elf header. */ if (ecp->ophnum > 0) { oeh.e_phoff = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); if (oeh.e_phoff == 0) errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); } /* * Update ELF object entry point if requested. */ if (ecp->change_addr != 0) oeh.e_entry += ecp->change_addr; if (ecp->flags & SET_START) oeh.e_entry = ecp->set_start; if (ecp->change_start != 0) oeh.e_entry += ecp->change_start; /* * Update ehdr again before we call elf_update(), since we * modified e_shoff and e_phoff. */ if (gelf_update_ehdr(ecp->eout, &oeh) == 0) errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", elf_errmsg(-1)); if (ecp->ophnum > 0) copy_phdr(ecp); /* Write out the output elf object. */ if (elf_update(ecp->eout, ELF_C_WRITE) < 0) errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1)); /* Release allocated resource. */ free_elf(ecp); } void free_elf(struct elfcopy *ecp) { struct segment *seg, *seg_temp; struct section *sec, *sec_temp; /* Free internal segment list. */ if (!STAILQ_EMPTY(&ecp->v_seg)) { STAILQ_FOREACH_SAFE(seg, &ecp->v_seg, seg_list, seg_temp) { STAILQ_REMOVE(&ecp->v_seg, seg, segment, seg_list); free(seg); } } /* Free symbol table buffers. */ free_symtab(ecp); /* Free internal section list. */ if (!TAILQ_EMPTY(&ecp->v_sec)) { TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) { TAILQ_REMOVE(&ecp->v_sec, sec, sec_list); if (sec->buf != NULL) free(sec->buf); if (sec->newname != NULL) free(sec->newname); if (sec->pad != NULL) free(sec->pad); free(sec); } } } /* Create a temporary file. */ void create_tempfile(char **fn, int *fd) { const char *tmpdir; char *cp, *tmpf; size_t tlen, plen; #define _TEMPFILE "ecp.XXXXXXXX" #define _TEMPFILEPATH "/tmp/ecp.XXXXXXXX" if (fn == NULL || fd == NULL) return; /* Repect TMPDIR environment variable. */ tmpdir = getenv("TMPDIR"); if (tmpdir != NULL && *tmpdir != '\0') { tlen = strlen(tmpdir); plen = strlen(_TEMPFILE); tmpf = malloc(tlen + plen + 2); if (tmpf == NULL) err(EXIT_FAILURE, "malloc failed"); strncpy(tmpf, tmpdir, tlen); cp = &tmpf[tlen - 1]; if (*cp++ != '/') *cp++ = '/'; strncpy(cp, _TEMPFILE, plen); cp[plen] = '\0'; } else { tmpf = strdup(_TEMPFILEPATH); if (tmpf == NULL) err(EXIT_FAILURE, "strdup failed"); } if ((*fd = mkstemp(tmpf)) == -1) err(EXIT_FAILURE, "mkstemp %s failed", tmpf); if (fchmod(*fd, 0644) == -1) err(EXIT_FAILURE, "fchmod %s failed", tmpf); *fn = tmpf; #undef _TEMPFILE #undef _TEMPFILEPATH } static int copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd) { int tmpfd; /* * First, check if we can use rename(). */ if (rename(src, dst) >= 0) { *outfd = infd; return (0); } else if (errno != EXDEV) return (-1); /* * If the rename() failed due to 'src' and 'dst' residing in * two different file systems, invoke a helper function in * libelftc to do the copy. */ if (unlink(dst) < 0) return (-1); if ((tmpfd = open(dst, O_CREAT | O_WRONLY, 0755)) < 0) return (-1); if (lseek(infd, 0, SEEK_SET) < 0) return (-1); if (elftc_copyfile(infd, tmpfd) < 0) return (-1); /* * Remove the temporary file from the file system * namespace, and close its file descriptor. */ if (unlink(src) < 0) return (-1); (void) close(infd); /* * Return the file descriptor for the destination. */ *outfd = tmpfd; return (0); } static void create_file(struct elfcopy *ecp, const char *src, const char *dst) { struct stat sb; char *tempfile, *elftemp; int efd, ifd, ofd, ofd0, tfd; tempfile = NULL; if (src == NULL) errx(EXIT_FAILURE, "internal: src == NULL"); if ((ifd = open(src, O_RDONLY)) == -1) err(EXIT_FAILURE, "open %s failed", src); if (fstat(ifd, &sb) == -1) err(EXIT_FAILURE, "fstat %s failed", src); if (dst == NULL) create_tempfile(&tempfile, &ofd); else if ((ofd = open(dst, O_RDWR|O_CREAT, 0755)) == -1) err(EXIT_FAILURE, "open %s failed", dst); #ifndef LIBELF_AR /* Detect and process ar(1) archive using libarchive. */ if (ac_detect_ar(ifd)) { ac_create_ar(ecp, ifd, ofd); goto copy_done; } #endif if (lseek(ifd, 0, SEEK_SET) < 0) err(EXIT_FAILURE, "lseek failed"); /* * If input object is not ELF file, convert it to an intermediate * ELF object before processing. */ if (ecp->itf != ETF_ELF) { create_tempfile(&elftemp, &efd); if ((ecp->eout = elf_begin(efd, ELF_C_WRITE, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); if (ecp->itf == ETF_BINARY) create_elf_from_binary(ecp, ifd, src); else if (ecp->itf == ETF_IHEX) create_elf_from_ihex(ecp, ifd); else if (ecp->itf == ETF_SREC) create_elf_from_srec(ecp, ifd); else errx(EXIT_FAILURE, "Internal: invalid target flavour"); elf_end(ecp->eout); /* Open intermediate ELF object as new input object. */ close(ifd); if ((ifd = open(elftemp, O_RDONLY)) == -1) err(EXIT_FAILURE, "open %s failed", src); close(efd); free(elftemp); } if ((ecp->ein = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); switch (elf_kind(ecp->ein)) { case ELF_K_NONE: errx(EXIT_FAILURE, "file format not recognized"); case ELF_K_ELF: if ((ecp->eout = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); /* elfcopy(1) manage ELF layout by itself. */ elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); /* * Create output ELF object. */ create_elf(ecp); elf_end(ecp->eout); /* * Convert the output ELF object to binary/srec/ihex if need. */ if (ecp->otf != ETF_ELF) { /* * Create (another) tempfile for binary/srec/ihex * output object. */ if (tempfile != NULL) { if (unlink(tempfile) < 0) err(EXIT_FAILURE, "unlink %s failed", tempfile); free(tempfile); } create_tempfile(&tempfile, &ofd0); /* * Rewind the file descriptor being processed. */ if (lseek(ofd, 0, SEEK_SET) < 0) err(EXIT_FAILURE, "lseek failed for the output object"); /* * Call flavour-specific conversion routine. */ switch (ecp->otf) { case ETF_BINARY: create_binary(ofd, ofd0); break; case ETF_IHEX: create_ihex(ofd, ofd0); break; case ETF_SREC: create_srec(ecp, ofd, ofd0, dst != NULL ? dst : src); break; default: errx(EXIT_FAILURE, "Internal: unsupported" " output flavour %d", ecp->oec); } close(ofd); ofd = ofd0; } break; case ELF_K_AR: /* XXX: Not yet supported. */ break; default: errx(EXIT_FAILURE, "file format not supported"); } elf_end(ecp->ein); #ifndef LIBELF_AR copy_done: #endif if (tempfile != NULL) { if (dst == NULL) dst = src; if (copy_from_tempfile(tempfile, dst, ofd, &tfd) < 0) err(EXIT_FAILURE, "creation of %s failed", dst); free(tempfile); tempfile = NULL; ofd = tfd; } if (strcmp(dst, "/dev/null") && fchmod(ofd, sb.st_mode) == -1) err(EXIT_FAILURE, "fchmod %s failed", dst); if ((ecp->flags & PRESERVE_DATE) && elftc_set_timestamps(dst, &sb) < 0) err(EXIT_FAILURE, "setting timestamps failed"); close(ifd); close(ofd); } static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv) { struct sec_action *sac; const char *infile, *outfile; char *fn, *s; int opt; while ((opt = getopt_long(argc, argv, "dB:gG:I:j:K:L:N:O:pR:s:SwW:xXV", elfcopy_longopts, NULL)) != -1) { switch(opt) { case 'B': /* ignored */ break; case 'R': sac = lookup_sec_act(ecp, optarg, 1); if (sac->copy != 0) errx(EXIT_FAILURE, "both copy and remove specified"); sac->remove = 1; ecp->flags |= SEC_REMOVE; break; case 'S': ecp->strip = STRIP_ALL; break; case 'g': ecp->strip = STRIP_DEBUG; break; case 'G': ecp->flags |= KEEP_GLOBAL; add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEPG); break; case 'I': case 's': set_input_target(ecp, optarg); break; case 'j': sac = lookup_sec_act(ecp, optarg, 1); if (sac->remove != 0) errx(EXIT_FAILURE, "both copy and remove specified"); sac->copy = 1; ecp->flags |= SEC_COPY; break; case 'K': add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEP); break; case 'L': add_to_symop_list(ecp, optarg, NULL, SYMOP_LOCALIZE); break; case 'N': add_to_symop_list(ecp, optarg, NULL, SYMOP_STRIP); break; case 'O': set_output_target(ecp, optarg); break; case 'p': ecp->flags |= PRESERVE_DATE; break; case 'V': print_version(); break; case 'w': ecp->flags |= WILDCARD; break; case 'W': add_to_symop_list(ecp, optarg, NULL, SYMOP_WEAKEN); break; case 'x': ecp->flags |= DISCARD_LOCAL; break; case 'X': ecp->flags |= DISCARD_LLABEL; break; case ECP_ADD_GNU_DEBUGLINK: ecp->debuglink = optarg; break; case ECP_ADD_SECTION: add_section(ecp, optarg); break; case ECP_CHANGE_ADDR: ecp->change_addr = (int64_t) strtoll(optarg, NULL, 0); break; case ECP_CHANGE_SEC_ADDR: parse_sec_address_op(ecp, opt, "--change-section-addr", optarg); break; case ECP_CHANGE_SEC_LMA: parse_sec_address_op(ecp, opt, "--change-section-lma", optarg); break; case ECP_CHANGE_SEC_VMA: parse_sec_address_op(ecp, opt, "--change-section-vma", optarg); break; case ECP_CHANGE_START: ecp->change_start = (int64_t) strtoll(optarg, NULL, 0); break; case ECP_CHANGE_WARN: /* default */ break; case ECP_GAP_FILL: ecp->fill = (uint8_t) strtoul(optarg, NULL, 0); ecp->flags |= GAP_FILL; break; case ECP_GLOBALIZE_SYMBOL: add_to_symop_list(ecp, optarg, NULL, SYMOP_GLOBALIZE); break; case ECP_GLOBALIZE_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_GLOBALIZE); break; case ECP_KEEP_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_KEEP); break; case ECP_KEEP_GLOBAL_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_KEEPG); break; case ECP_LOCALIZE_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_LOCALIZE); break; case ECP_NO_CHANGE_WARN: ecp->flags |= NO_CHANGE_WARN; break; case ECP_ONLY_DEBUG: ecp->strip = STRIP_NONDEBUG; break; case ECP_PAD_TO: ecp->pad_to = (uint64_t) strtoull(optarg, NULL, 0); break; case ECP_PREFIX_ALLOC: ecp->prefix_alloc = optarg; break; case ECP_PREFIX_SEC: ecp->prefix_sec = optarg; break; case ECP_PREFIX_SYM: ecp->prefix_sym = optarg; break; case ECP_REDEF_SYMBOL: if ((s = strchr(optarg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --redefine-sym"); *s++ = '\0'; add_to_symop_list(ecp, optarg, s, SYMOP_REDEF); break; case ECP_REDEF_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_REDEF); break; case ECP_RENAME_SECTION: if ((fn = strchr(optarg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --rename-section"); *fn++ = '\0'; /* Check for optional flags. */ if ((s = strchr(fn, ',')) != NULL) *s++ = '\0'; sac = lookup_sec_act(ecp, optarg, 1); sac->rename = 1; sac->newname = fn; if (s != NULL) parse_sec_flags(sac, s); break; case ECP_SET_OSABI: set_osabi(ecp, optarg); break; case ECP_SET_SEC_FLAGS: if ((s = strchr(optarg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --set-section-flags"); *s++ = '\0'; sac = lookup_sec_act(ecp, optarg, 1); parse_sec_flags(sac, s); break; case ECP_SET_START: ecp->flags |= SET_START; ecp->set_start = (uint64_t) strtoull(optarg, NULL, 0); break; case ECP_SREC_FORCE_S3: ecp->flags |= SREC_FORCE_S3; break; case ECP_SREC_LEN: ecp->flags |= SREC_FORCE_LEN; ecp->srec_len = strtoul(optarg, NULL, 0); break; case ECP_STRIP_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_STRIP); break; case ECP_STRIP_UNNEEDED: ecp->strip = STRIP_UNNEEDED; break; case ECP_WEAKEN_ALL: ecp->flags |= WEAKEN_ALL; break; case ECP_WEAKEN_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_WEAKEN); break; default: elfcopy_usage(); } } if (optind == argc || optind + 2 < argc) elfcopy_usage(); infile = argv[optind]; outfile = NULL; if (optind + 1 < argc) outfile = argv[optind + 1]; create_file(ecp, infile, outfile); } static void mcs_main(struct elfcopy *ecp, int argc, char **argv) { struct sec_action *sac; const char *string; int append, delete, compress, name, print; int opt, i; append = delete = compress = name = print = 0; string = NULL; while ((opt = getopt_long(argc, argv, "a:cdhn:pV", mcs_longopts, NULL)) != -1) { switch(opt) { case 'a': append = 1; string = optarg; /* XXX multiple -a not supported */ break; case 'c': compress = 1; break; case 'd': delete = 1; break; case 'n': name = 1; (void)lookup_sec_act(ecp, optarg, 1); break; case 'p': print = 1; break; case 'V': print_version(); break; case 'h': default: mcs_usage(); } } if (optind == argc) mcs_usage(); /* Must specify one operation at least. */ if (!append && !compress && !delete && !print) mcs_usage(); /* * If we are going to delete, ignore other operations. This is * different from the Solaris implementation, which can print * and delete a section at the same time, for example. Also, this * implementation do not respect the order between operations that * user specified, i.e., "mcs -pc a.out" equals to "mcs -cp a.out". */ if (delete) { append = compress = print = 0; ecp->flags |= SEC_REMOVE; } if (append) ecp->flags |= SEC_APPEND; if (compress) ecp->flags |= SEC_COMPRESS; if (print) ecp->flags |= SEC_PRINT; /* .comment is the default section to operate on. */ if (!name) (void)lookup_sec_act(ecp, ".comment", 1); STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { sac->append = append; sac->compress = compress; sac->print = print; sac->remove = delete; sac->string = string; } for (i = optind; i < argc; i++) { /* If only -p is specified, output to /dev/null */ if (print && !append && !compress && !delete) create_file(ecp, argv[i], "/dev/null"); else create_file(ecp, argv[i], NULL); } } static void strip_main(struct elfcopy *ecp, int argc, char **argv) { struct sec_action *sac; const char *outfile; int opt; int i; outfile = NULL; while ((opt = getopt_long(argc, argv, "hI:K:N:o:O:pR:sSdgVxXw", strip_longopts, NULL)) != -1) { switch(opt) { case 'R': sac = lookup_sec_act(ecp, optarg, 1); sac->remove = 1; ecp->flags |= SEC_REMOVE; break; case 's': ecp->strip = STRIP_ALL; break; case 'S': case 'g': case 'd': ecp->strip = STRIP_DEBUG; break; case 'I': /* ignored */ break; case 'K': add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEP); break; case 'N': add_to_symop_list(ecp, optarg, NULL, SYMOP_STRIP); break; case 'o': outfile = optarg; break; case 'O': set_output_target(ecp, optarg); break; case 'p': ecp->flags |= PRESERVE_DATE; break; case 'V': print_version(); break; case 'w': ecp->flags |= WILDCARD; break; case 'x': ecp->flags |= DISCARD_LOCAL; break; case 'X': ecp->flags |= DISCARD_LLABEL; break; case ECP_ONLY_DEBUG: ecp->strip = STRIP_NONDEBUG; break; case ECP_STRIP_UNNEEDED: ecp->strip = STRIP_UNNEEDED; break; case 'h': default: strip_usage(); } } if (ecp->strip == 0 && ((ecp->flags & DISCARD_LOCAL) == 0) && - ((ecp->flags & DISCARD_LLABEL) == 0)) + ((ecp->flags & DISCARD_LLABEL) == 0) && + lookup_symop_list(ecp, NULL, SYMOP_STRIP) == NULL) ecp->strip = STRIP_ALL; if (optind == argc) strip_usage(); for (i = optind; i < argc; i++) create_file(ecp, argv[i], outfile); } static void parse_sec_flags(struct sec_action *sac, char *s) { const char *flag; int found, i; for (flag = strtok(s, ","); flag; flag = strtok(NULL, ",")) { found = 0; for (i = 0; sec_flags[i].name != NULL; i++) if (strcasecmp(sec_flags[i].name, flag) == 0) { sac->flags |= sec_flags[i].value; found = 1; break; } if (!found) errx(EXIT_FAILURE, "unrecognized section flag %s", flag); } } static void parse_sec_address_op(struct elfcopy *ecp, int optnum, const char *optname, char *s) { struct sec_action *sac; const char *name; char *v; char op; name = v = s; do { v++; } while (*v != '\0' && *v != '=' && *v != '+' && *v != '-'); if (*v == '\0' || *(v + 1) == '\0') errx(EXIT_FAILURE, "invalid format for %s", optname); op = *v; *v++ = '\0'; sac = lookup_sec_act(ecp, name, 1); switch (op) { case '=': if (optnum == ECP_CHANGE_SEC_LMA || optnum == ECP_CHANGE_SEC_ADDR) { sac->setlma = 1; sac->lma = (uint64_t) strtoull(v, NULL, 0); } if (optnum == ECP_CHANGE_SEC_VMA || optnum == ECP_CHANGE_SEC_ADDR) { sac->setvma = 1; sac->vma = (uint64_t) strtoull(v, NULL, 0); } break; case '+': if (optnum == ECP_CHANGE_SEC_LMA || optnum == ECP_CHANGE_SEC_ADDR) sac->lma_adjust = (int64_t) strtoll(v, NULL, 0); if (optnum == ECP_CHANGE_SEC_VMA || optnum == ECP_CHANGE_SEC_ADDR) sac->vma_adjust = (int64_t) strtoll(v, NULL, 0); break; case '-': if (optnum == ECP_CHANGE_SEC_LMA || optnum == ECP_CHANGE_SEC_ADDR) sac->lma_adjust = (int64_t) -strtoll(v, NULL, 0); if (optnum == ECP_CHANGE_SEC_VMA || optnum == ECP_CHANGE_SEC_ADDR) sac->vma_adjust = (int64_t) -strtoll(v, NULL, 0); break; default: break; } } static void parse_symlist_file(struct elfcopy *ecp, const char *fn, unsigned int op) { struct symfile *sf; struct stat sb; FILE *fp; char *data, *p, *line, *end, *e, *n; if (stat(fn, &sb) == -1) err(EXIT_FAILURE, "stat %s failed", fn); /* Check if we already read and processed this file. */ STAILQ_FOREACH(sf, &ecp->v_symfile, symfile_list) { if (sf->dev == sb.st_dev && sf->ino == sb.st_ino) goto process_symfile; } if ((fp = fopen(fn, "r")) == NULL) err(EXIT_FAILURE, "can not open %s", fn); if ((data = malloc(sb.st_size + 1)) == NULL) err(EXIT_FAILURE, "malloc failed"); if (fread(data, 1, sb.st_size, fp) == 0 || ferror(fp)) err(EXIT_FAILURE, "fread failed"); fclose(fp); data[sb.st_size] = '\0'; if ((sf = calloc(1, sizeof(*sf))) == NULL) err(EXIT_FAILURE, "malloc failed"); sf->dev = sb.st_dev; sf->ino = sb.st_ino; sf->size = sb.st_size + 1; sf->data = data; process_symfile: /* * Basically what we do here is to convert EOL to '\0', and remove * leading and trailing whitespaces for each line. */ end = sf->data + sf->size; line = NULL; for(p = sf->data; p < end; p++) { if ((*p == '\t' || *p == ' ') && line == NULL) continue; if (*p == '\r' || *p == '\n' || *p == '\0') { *p = '\0'; if (line == NULL) continue; /* Skip comment. */ if (*line == '#') { line = NULL; continue; } e = p - 1; while(e != line && (*e == '\t' || *e == ' ')) *e-- = '\0'; if (op != SYMOP_REDEF) add_to_symop_list(ecp, line, NULL, op); else { if (strlen(line) < 3) errx(EXIT_FAILURE, "illegal format for" " --redefine-sym"); for(n = line + 1; n < e; n++) { if (*n == ' ' || *n == '\t') { while(*n == ' ' || *n == '\t') *n++ = '\0'; break; } } if (n >= e) errx(EXIT_FAILURE, "illegal format for" " --redefine-sym"); add_to_symop_list(ecp, line, n, op); } line = NULL; continue; } if (line == NULL) line = p; } } static void set_input_target(struct elfcopy *ecp, const char *target_name) { Elftc_Bfd_Target *tgt; if ((tgt = elftc_bfd_find_target(target_name)) == NULL) errx(EXIT_FAILURE, "%s: invalid target name", target_name); ecp->itf = elftc_bfd_target_flavor(tgt); } static void set_output_target(struct elfcopy *ecp, const char *target_name) { Elftc_Bfd_Target *tgt; if ((tgt = elftc_bfd_find_target(target_name)) == NULL) errx(EXIT_FAILURE, "%s: invalid target name", target_name); ecp->otf = elftc_bfd_target_flavor(tgt); if (ecp->otf == ETF_ELF) { ecp->oec = elftc_bfd_target_class(tgt); ecp->oed = elftc_bfd_target_byteorder(tgt); ecp->oem = elftc_bfd_target_machine(tgt); } ecp->otgt = target_name; } static void set_osabi(struct elfcopy *ecp, const char *abi) { int i, found; found = 0; for (i = 0; osabis[i].name != NULL; i++) if (strcasecmp(osabis[i].name, abi) == 0) { ecp->abi = osabis[i].abi; found = 1; break; } if (!found) errx(EXIT_FAILURE, "unrecognized OSABI %s", abi); } #define ELFCOPY_USAGE_MESSAGE "\ Usage: %s [options] infile [outfile]\n\ Transform an ELF object.\n\n\ Options:\n\ -d | -g | --strip-debug Remove debugging information from the output.\n\ -j SECTION | --only-section=SECTION\n\ Copy only the named section to the output.\n\ -p | --preserve-dates Preserve access and modification times.\n\ -w | --wildcard Use shell-style patterns to name symbols.\n\ -x | --discard-all Do not copy non-globals to the output.\n\ -I FORMAT | --input-target=FORMAT\n\ (Accepted but ignored).\n\ -K SYM | --keep-symbol=SYM Copy symbol SYM to the output.\n\ -L SYM | --localize-symbol=SYM\n\ Make symbol SYM local to the output file.\n\ -N SYM | --strip-symbol=SYM Do not copy symbol SYM to the output.\n\ -R NAME | --remove-section=NAME\n\ Remove the named section.\n\ -S | --strip-all Remove all symbol and relocation information\n\ from the output.\n\ -V | --version Print a version identifier and exit.\n\ -W SYM | --weaken-symbol=SYM Mark symbol SYM as weak in the output.\n\ -X | --discard-locals Do not copy compiler generated symbols to\n\ the output.\n\ --add-section NAME=FILE Add the contents of FILE to the ELF object as\n\ a new section named NAME.\n\ --adjust-section-vma SECTION{=,+,-}VAL | \\\n\ --change-section-address SECTION{=,+,-}VAL\n\ Set or adjust the VMA and the LMA of the\n\ named section by VAL.\n\ --adjust-start=INCR | --change-start=INCR\n\ Add INCR to the start address for the ELF\n\ object.\n\ --adjust-vma=INCR | --change-addresses=INCR\n\ Increase the VMA and LMA of all sections by\n\ INCR.\n\ --adjust-warning | --change-warnings\n\ Issue warnings for non-existent sections.\n\ --change-section-lma SECTION{=,+,-}VAL\n\ Set or adjust the LMA address of the named\n\ section by VAL.\n\ --change-section-vma SECTION{=,+,-}VAL\n\ Set or adjust the VMA address of the named\n\ section by VAL.\n\ --gap-fill=VAL Fill the gaps between sections with bytes\n\ of value VAL.\n\ --no-adjust-warning| --no-change-warnings\n\ Do not issue warnings for non-existent\n\ sections.\n\ --only-keep-debug Copy only debugging information.\n\ --output-target=FORMAT Use the specified format for the output.\n\ --pad-to=ADDRESS Pad the output object upto the given address.\n\ --prefix-alloc-sections=STRING\n\ Prefix the section names of all the allocated\n\ sections with STRING.\n\ --prefix-sections=STRING Prefix the section names of all the sections\n\ with STRING.\n\ --prefix-symbols=STRING Prefix the symbol names of all the symbols\n\ with STRING.\n\ --rename-section OLDNAME=NEWNAME[,FLAGS]\n\ Rename and optionally change section flags.\n\ --set-section-flags SECTION=FLAGS\n\ Set section flags for the named section.\n\ Supported flags are: 'alloc', 'code',\n\ 'contents', 'data', 'debug', 'load',\n\ 'noload', 'readonly', 'rom', and 'shared'.\n\ --set-start=ADDRESS Set the start address of the ELF object.\n\ --srec-forceS3 Only generate S3 S-Records.\n\ --srec-len=LEN Set the maximum length of a S-Record line.\n\ --strip-unneeded Do not copy relocation information.\n" static void elfcopy_usage(void) { (void) fprintf(stderr, ELFCOPY_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } #define MCS_USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Manipulate the comment section in an ELF object.\n\n\ Options:\n\ -a STRING Append 'STRING' to the comment section.\n\ -c Remove duplicate entries from the comment section.\n\ -d Delete the comment section.\n\ -h | --help Print a help message and exit.\n\ -n NAME Operate on the ELF section with name 'NAME'.\n\ -p Print the contents of the comment section.\n\ -V | --version Print a version identifier and exit.\n" static void mcs_usage(void) { (void) fprintf(stderr, MCS_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } #define STRIP_USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Discard information from ELF objects.\n\n\ Options:\n\ -d | -g | -S | --strip-debug Remove debugging symbols.\n\ -h | --help Print a help message.\n\ --only-keep-debug Keep debugging information only.\n\ -p | --preserve-dates Preserve access and modification times.\n\ -s | --strip-all Remove all symbols.\n\ --strip-unneeded Remove symbols not needed for relocation\n\ processing.\n\ -w | --wildcard Use shell-style patterns to name symbols.\n\ -x | --discard-all Discard all non-global symbols.\n\ -I TGT| --input-target=TGT (Accepted, but ignored).\n\ -K SYM | --keep-symbol=SYM Keep symbol 'SYM' in the output.\n\ -N SYM | --strip-symbol=SYM Remove symbol 'SYM' from the output.\n\ -O TGT | --output-target=TGT Set the output file format to 'TGT'.\n\ -R SEC | --remove-section=SEC Remove the section named 'SEC'.\n\ -V | --version Print a version identifier and exit.\n\ -X | --discard-locals Remove compiler-generated local symbols.\n" static void strip_usage(void) { (void) fprintf(stderr, STRIP_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } static void print_version(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } int main(int argc, char **argv) { struct elfcopy *ecp; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); ecp = calloc(1, sizeof(*ecp)); if (ecp == NULL) err(EXIT_FAILURE, "calloc failed"); memset(ecp, 0, sizeof(*ecp)); ecp->itf = ecp->otf = ETF_ELF; ecp->iec = ecp->oec = ELFCLASSNONE; ecp->oed = ELFDATANONE; ecp->abi = -1; /* There is always an empty section. */ ecp->nos = 1; ecp->fill = 0; STAILQ_INIT(&ecp->v_seg); STAILQ_INIT(&ecp->v_sac); STAILQ_INIT(&ecp->v_sadd); STAILQ_INIT(&ecp->v_symop); STAILQ_INIT(&ecp->v_symfile); STAILQ_INIT(&ecp->v_arobj); TAILQ_INIT(&ecp->v_sec); if ((ecp->progname = ELFTC_GETPROGNAME()) == NULL) ecp->progname = "elfcopy"; if (strcmp(ecp->progname, "strip") == 0) strip_main(ecp, argc, argv); else if (strcmp(ecp->progname, "mcs") == 0) mcs_main(ecp, argc, argv); else elfcopy_main(ecp, argc, argv); free_sec_add(ecp); free_sec_act(ecp); free(ecp); exit(EXIT_SUCCESS); } diff --git a/elfcopy/sections.c b/elfcopy/sections.c index d01659a935ee..c503666c8948 100644 --- a/elfcopy/sections.c +++ b/elfcopy/sections.c @@ -1,1518 +1,1525 @@ /*- * Copyright (c) 2007-2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: sections.c 2358 2011-12-19 18:22:32Z kaiwang27 $"); +ELFTC_VCSID("$Id: sections.c 3126 2014-12-21 08:03:31Z kaiwang27 $"); static void add_gnu_debuglink(struct elfcopy *ecp); static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); static void check_section_rename(struct elfcopy *ecp, struct section *s); static void filter_reloc(struct elfcopy *ecp, struct section *s); static int get_section_flags(struct elfcopy *ecp, const char *name); static void insert_sections(struct elfcopy *ecp); static void insert_to_strtab(struct section *t, const char *s); static int is_append_section(struct elfcopy *ecp, const char *name); static int is_compress_section(struct elfcopy *ecp, const char *name); static int is_debug_section(const char *name); static int is_modify_section(struct elfcopy *ecp, const char *name); static int is_print_section(struct elfcopy *ecp, const char *name); static int lookup_string(struct section *t, const char *s); static void modify_section(struct elfcopy *ecp, struct section *s); static void pad_section(struct elfcopy *ecp, struct section *s); static void print_data(const char *d, size_t sz); static void print_section(struct section *s); static void *read_section(struct section *s, size_t *size); static void update_reloc(struct elfcopy *ecp, struct section *s); int is_remove_section(struct elfcopy *ecp, const char *name) { /* Always keep section name table */ if (strcmp(name, ".shstrtab") == 0) return 0; if (strcmp(name, ".symtab") == 0 || strcmp(name, ".strtab") == 0) { if (ecp->strip == STRIP_ALL && lookup_symop_list( ecp, NULL, SYMOP_KEEP) == NULL) return (1); else return (0); } if (is_debug_section(name)) { if (ecp->strip == STRIP_ALL || ecp->strip == STRIP_DEBUG || ecp->strip == STRIP_UNNEEDED || (ecp->flags & DISCARD_LOCAL)) return (1); if (ecp->strip == STRIP_NONDEBUG) return (0); } if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove) return (1); if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy)) return (1); } return (0); } /* * Relocation section needs to be removed if the section it applies to * will be removed. */ int is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info) { const char *name; GElf_Shdr ish; Elf_Scn *is; size_t indx; int elferr; if (elf_getshstrndx(ecp->ein, &indx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", elf_errmsg(-1)); is = NULL; while ((is = elf_nextscn(ecp->ein, is)) != NULL) { if (sh_info == elf_ndxscn(is)) { if (gelf_getshdr(is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (is_remove_section(ecp, name)) return (1); else return (0); } } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); /* Remove reloc section if we can't find the target section. */ return (1); } static int is_append_section(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->append != 0 && sac->string != NULL) return (1); return (0); } static int is_compress_section(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->compress != 0) return (1); return (0); } static void check_section_rename(struct elfcopy *ecp, struct section *s) { struct sec_action *sac; char *prefix; size_t namelen; if (s->pseudo) return; sac = lookup_sec_act(ecp, s->name, 0); if (sac != NULL && sac->rename) s->name = sac->newname; if (!strcmp(s->name, ".symtab") || !strcmp(s->name, ".strtab") || !strcmp(s->name, ".shstrtab")) return; prefix = NULL; if (s->loadable && ecp->prefix_alloc != NULL) prefix = ecp->prefix_alloc; else if (ecp->prefix_sec != NULL) prefix = ecp->prefix_sec; if (prefix != NULL) { namelen = strlen(s->name) + strlen(prefix) + 1; if ((s->newname = malloc(namelen)) == NULL) err(EXIT_FAILURE, "malloc failed"); snprintf(s->newname, namelen, "%s%s", prefix, s->name); s->name = s->newname; } } static int get_section_flags(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->flags) return sac->flags; return (0); } /* * Determine whether the section are debugging section. * According to libbfd, debugging sections are recognized * only by name. */ static int is_debug_section(const char *name) { const char *dbg_sec[] = { ".debug", ".gnu.linkonce.wi.", ".line", ".stab", NULL }; const char **p; for(p = dbg_sec; *p; p++) { if (strncmp(name, *p, strlen(*p)) == 0) return (1); } return (0); } static int is_print_section(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->print != 0) return (1); return (0); } static int is_modify_section(struct elfcopy *ecp, const char *name) { if (is_append_section(ecp, name) || is_compress_section(ecp, name)) return (1); return (0); } struct sec_action* lookup_sec_act(struct elfcopy *ecp, const char *name, int add) { struct sec_action *sac; if (name == NULL) return NULL; STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { if (strcmp(name, sac->name) == 0) return sac; } if (add == 0) return NULL; if ((sac = malloc(sizeof(*sac))) == NULL) errx(EXIT_FAILURE, "not enough memory"); memset(sac, 0, sizeof(*sac)); sac->name = name; STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list); return (sac); } void free_sec_act(struct elfcopy *ecp) { struct sec_action *sac, *sac_temp; STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) { STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list); free(sac); } } void insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail) { struct section *s; if (!tail) { TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (sec->off < s->off) { TAILQ_INSERT_BEFORE(s, sec, sec_list); goto inc_nos; } } } TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list); inc_nos: if (sec->pseudo == 0) ecp->nos++; } /* * First step of section creation: create scn and internal section * structure, discard sections to be removed. */ void create_scn(struct elfcopy *ecp) { struct section *s; const char *name; Elf_Scn *is; GElf_Shdr ish; size_t indx; uint64_t oldndx, newndx; int elferr, sec_flags; /* * Insert a pseudo section that contains the ELF header * and program header. Used as reference for section offset * or load address adjustment. */ if ((s = calloc(1, sizeof(*s))) == NULL) err(EXIT_FAILURE, "calloc failed"); s->off = 0; s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) + gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT); s->align = 1; s->pseudo = 1; s->loadable = add_to_inseg_list(ecp, s); insert_to_sec_list(ecp, s, 0); /* Create internal .shstrtab section. */ init_shstrtab(ecp); if (elf_getshstrndx(ecp->ein, &indx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", elf_errmsg(-1)); is = NULL; while ((is = elf_nextscn(ecp->ein, is)) != NULL) { if (gelf_getshdr(is, &ish) == NULL) errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); /* Skip sections to be removed. */ if (is_remove_section(ecp, name)) continue; /* * Relocation section need to be remove if the section * it applies will be removed. */ if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) if (ish.sh_info != 0 && is_remove_reloc_sec(ecp, ish.sh_info)) continue; + /* + * Section groups should be removed if symbol table will + * be removed. (section group's signature stored in symbol + * table) + */ + if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL) + continue; + /* Get section flags set by user. */ sec_flags = get_section_flags(ecp, name); /* Create internal section object. */ if (strcmp(name, ".shstrtab") != 0) { if ((s = calloc(1, sizeof(*s))) == NULL) err(EXIT_FAILURE, "calloc failed"); s->name = name; s->is = is; s->off = ish.sh_offset; s->sz = ish.sh_size; s->align = ish.sh_addralign; s->type = ish.sh_type; s->vma = ish.sh_addr; /* * Search program headers to determine whether section * is loadable, but if user explicitly set section flags * while neither "load" nor "alloc" is set, we make the * section unloadable. */ if (sec_flags && (sec_flags & (SF_LOAD | SF_ALLOC)) == 0) s->loadable = 0; else s->loadable = add_to_inseg_list(ecp, s); } else { /* Assuming .shstrtab is "unloadable". */ s = ecp->shstrtab; s->off = ish.sh_offset; } oldndx = newndx = SHN_UNDEF; if (strcmp(name, ".symtab") != 0 && strcmp(name, ".strtab") != 0) { if (!strcmp(name, ".shstrtab")) { /* * Add sections specified by --add-section and * gnu debuglink. we want these sections have * smaller index than .shstrtab section. */ if (ecp->debuglink != NULL) add_gnu_debuglink(ecp); if (ecp->flags & SEC_ADD) insert_sections(ecp); } if ((s->os = elf_newscn(ecp->eout)) == NULL) errx(EXIT_FAILURE, "elf_newscn failed: %s", elf_errmsg(-1)); if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF) errx(EXIT_FAILURE, "elf_ndxscn failed: %s", elf_errmsg(-1)); } if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF) errx(EXIT_FAILURE, "elf_ndxscn failed: %s", elf_errmsg(-1)); if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF) ecp->secndx[oldndx] = newndx; /* * If strip action is STRIP_NONDEBUG(only keep debug), * change sections flags of loadable sections to SHF_NOBITS, * and the content of those sections will be ignored. */ if (ecp->strip == STRIP_NONDEBUG && (ish.sh_flags & SHF_ALLOC)) s->type = SHT_NOBITS; check_section_rename(ecp, s); /* create section header based on input object. */ if (strcmp(name, ".symtab") != 0 && strcmp(name, ".strtab") != 0 && strcmp(name, ".shstrtab") != 0) copy_shdr(ecp, s, NULL, 0, sec_flags); if (strcmp(name, ".symtab") == 0) { ecp->flags |= SYMTAB_EXIST; ecp->symtab = s; } if (strcmp(name, ".strtab") == 0) ecp->strtab = s; insert_to_sec_list(ecp, s, 0); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); } struct section * insert_shtab(struct elfcopy *ecp, int tail) { struct section *s, *shtab; GElf_Ehdr ieh; int nsecs; /* * Treat section header table as a "pseudo" section, insert it * into section list, so later it will get sorted and resynced * just as normal sections. */ if ((shtab = calloc(1, sizeof(*shtab))) == NULL) errx(EXIT_FAILURE, "calloc failed"); if (!tail) { /* shoff of input object is used as a hint. */ if (gelf_getehdr(ecp->ein, &ieh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); shtab->off = ieh.e_shoff; } else shtab->off = 0; /* Calculate number of sections in the output object. */ nsecs = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (!s->pseudo) nsecs++; } /* Remember there is always a null section, so we +1 here. */ shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT); if (shtab->sz == 0) errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8); shtab->loadable = 0; shtab->pseudo = 1; insert_to_sec_list(ecp, shtab, tail); return (shtab); } void copy_content(struct elfcopy *ecp) { struct section *s; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { /* Skip pseudo section. */ if (s->pseudo) continue; /* Skip special sections. */ if (strcmp(s->name, ".symtab") == 0 || strcmp(s->name, ".strtab") == 0 || strcmp(s->name, ".shstrtab") == 0) continue; /* * If strip action is STRIP_ALL, relocation info need * to be stripped. Skip filtering otherwisw. */ if (ecp->strip == STRIP_ALL && (s->type == SHT_REL || s->type == SHT_RELA)) filter_reloc(ecp, s); if (is_modify_section(ecp, s->name)) modify_section(ecp, s); copy_data(s); /* * If symbol table is modified, relocation info might * need update, as symbol index may have changed. */ if ((ecp->flags & SYMTAB_INTACT) == 0 && (ecp->flags & SYMTAB_EXIST) && (s->type == SHT_REL || s->type == SHT_RELA)) update_reloc(ecp, s); if (is_print_section(ecp, s->name)) print_section(s); } } /* * Filter relocation entries, only keep those entries whose * symbol is in the keep list. */ static void filter_reloc(struct elfcopy *ecp, struct section *s) { const char *name; GElf_Shdr ish; GElf_Rel rel; GElf_Rela rela; Elf32_Rel *rel32; Elf64_Rel *rel64; Elf32_Rela *rela32; Elf64_Rela *rela64; Elf_Data *id; uint64_t cap, n, nrels; int elferr, i; if (gelf_getshdr(s->is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); /* We don't want to touch relocation info for dynamic symbols. */ if ((ecp->flags & SYMTAB_EXIST) == 0) { if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) { /* * This reloc section applies to the symbol table * that was stripped, so discard whole section. */ s->nocopy = 1; s->sz = 0; } return; } else { /* Symbol table exist, check if index equals. */ if (ish.sh_link != elf_ndxscn(ecp->symtab->is)) return; } #define COPYREL(REL, SZ) do { \ if (nrels == 0) { \ if ((REL##SZ = malloc(cap * \ sizeof(Elf##SZ##_Rel))) == NULL) \ err(EXIT_FAILURE, "malloc failed"); \ } \ if (nrels >= cap) { \ cap *= 2; \ if ((REL##SZ = realloc(REL##SZ, cap * \ sizeof(Elf##SZ##_Rel))) == NULL) \ err(EXIT_FAILURE, "realloc failed"); \ } \ REL##SZ[nrels].r_offset = REL.r_offset; \ REL##SZ[nrels].r_info = REL.r_info; \ if (s->type == SHT_RELA) \ rela##SZ[nrels].r_addend = rela.r_addend; \ nrels++; \ } while (0) nrels = 0; cap = 4; /* keep list is usually small. */ rel32 = NULL; rel64 = NULL; rela32 = NULL; rela64 = NULL; if ((id = elf_getdata(s->is, NULL)) == NULL) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(-1)); n = ish.sh_size / ish.sh_entsize; for(i = 0; (uint64_t)i < n; i++) { if (s->type == SHT_REL) { if (gelf_getrel(id, i, &rel) != &rel) errx(EXIT_FAILURE, "gelf_getrel failed: %s", elf_errmsg(-1)); } else { if (gelf_getrela(id, i, &rela) != &rela) errx(EXIT_FAILURE, "gelf_getrel failed: %s", elf_errmsg(-1)); } name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is), GELF_R_SYM(rel.r_info)); if (name == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) { if (ecp->oec == ELFCLASS32) { if (s->type == SHT_REL) COPYREL(rel, 32); else COPYREL(rela, 32); } else { if (s->type == SHT_REL) COPYREL(rel, 64); else COPYREL(rela, 64); } } } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); if (ecp->oec == ELFCLASS32) { if (s->type == SHT_REL) s->buf = rel32; else s->buf = rela32; } else { if (s->type == SHT_REL) s->buf = rel64; else s->buf = rela64; } s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL : ELF_T_RELA), nrels, EV_CURRENT); s->nocopy = 1; } static void update_reloc(struct elfcopy *ecp, struct section *s) { GElf_Shdr osh; GElf_Rel rel; GElf_Rela rela; Elf_Data *od; uint64_t n; int i; #define UPDATEREL(REL) do { \ if (gelf_get##REL(od, i, &REL) != &REL) \ errx(EXIT_FAILURE, "gelf_get##REL failed: %s", \ elf_errmsg(-1)); \ REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)], \ GELF_R_TYPE(REL.r_info)); \ if (!gelf_update_##REL(od, i, &REL)) \ errx(EXIT_FAILURE, "gelf_update_##REL failed: %s", \ elf_errmsg(-1)); \ } while(0) if (s->sz == 0) return; if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); /* Only process .symtab reloc info. */ if (osh.sh_link != elf_ndxscn(ecp->symtab->is)) return; if ((od = elf_getdata(s->os, NULL)) == NULL) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(-1)); n = osh.sh_size / osh.sh_entsize; for(i = 0; (uint64_t)i < n; i++) { if (s->type == SHT_REL) UPDATEREL(rel); else UPDATEREL(rela); } } static void pad_section(struct elfcopy *ecp, struct section *s) { GElf_Shdr osh; Elf_Data *od; if (s == NULL || s->pad_sz == 0) return; if ((s->pad = malloc(s->pad_sz)) == NULL) err(EXIT_FAILURE, "malloc failed"); memset(s->pad, ecp->fill, s->pad_sz); /* Create a new Elf_Data to contain the padding bytes. */ if ((od = elf_newdata(s->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); od->d_align = 1; od->d_off = s->sz; od->d_buf = s->pad; od->d_type = ELF_T_BYTE; od->d_size = s->pad_sz; od->d_version = EV_CURRENT; /* Update section header. */ if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); osh.sh_size = s->sz + s->pad_sz; if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "elf_update_shdr failed: %s", elf_errmsg(-1)); } void resync_sections(struct elfcopy *ecp) { struct section *s, *ps; GElf_Shdr osh; uint64_t off; int first; ps = NULL; first = 1; off = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (first) { off = s->off; first = 0; } /* Align section offset. */ if (off <= s->off) { if (!s->loadable) s->off = roundup(off, s->align); } else { if (s->loadable) - warnx("moving loadable section," - "is this intentional?"); + warnx("moving loadable section %s, " + "is this intentional?", s->name); s->off = roundup(off, s->align); } /* Calculate next section offset. */ off = s->off; if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL)) off += s->sz; if (s->pseudo) { ps = NULL; continue; } /* Count padding bytes added through --pad-to. */ if (s->pad_sz > 0) off += s->pad_sz; /* Update section header accordingly. */ if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); osh.sh_addr = s->vma; osh.sh_offset = s->off; osh.sh_size = s->sz; if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "elf_update_shdr failed: %s", elf_errmsg(-1)); /* Add padding for previous section, if need. */ if (ps != NULL) { if (ps->pad_sz > 0) { /* Apply padding added by --pad-to. */ pad_section(ecp, ps); } else if ((ecp->flags & GAP_FILL) && (ps->off + ps->sz < s->off)) { /* * Fill the gap between sections by padding * the section with lower address. */ ps->pad_sz = s->off - (ps->off + ps->sz); pad_section(ecp, ps); } } ps = s; } /* Pad the last section, if need. */ if (ps != NULL && ps->pad_sz > 0) pad_section(ecp, ps); } static void modify_section(struct elfcopy *ecp, struct section *s) { struct sec_action *sac; size_t srcsz, dstsz, p, len; char *b, *c, *d, *src, *end; int dupe; src = read_section(s, &srcsz); if (src == NULL || srcsz == 0) { /* For empty section, we proceed if we need to append. */ if (!is_append_section(ecp, s->name)) return; } /* Allocate buffer needed for new section data. */ dstsz = srcsz; if (is_append_section(ecp, s->name)) { sac = lookup_sec_act(ecp, s->name, 0); dstsz += strlen(sac->string) + 1; } if ((b = malloc(dstsz)) == NULL) err(EXIT_FAILURE, "malloc failed"); s->buf = b; /* Compress section. */ p = 0; if (is_compress_section(ecp, s->name)) { end = src + srcsz; for(c = src; c < end;) { len = 0; while(c + len < end && c[len] != '\0') len++; if (c + len == end) { /* XXX should we warn here? */ strncpy(&b[p], c, len); p += len; break; } dupe = 0; for (d = b; d < b + p; ) { if (strcmp(d, c) == 0) { dupe = 1; break; } d += strlen(d) + 1; } if (!dupe) { strncpy(&b[p], c, len); b[p + len] = '\0'; p += len + 1; } c += len + 1; } } else { memcpy(b, src, srcsz); p += srcsz; } /* Append section. */ if (is_append_section(ecp, s->name)) { sac = lookup_sec_act(ecp, s->name, 0); len = strlen(sac->string); strncpy(&b[p], sac->string, len); b[p + len] = '\0'; p += len + 1; } s->sz = p; s->nocopy = 1; } static void print_data(const char *d, size_t sz) { const char *c; for (c = d; c < d + sz; c++) { if (*c == '\0') putchar('\n'); else putchar(*c); } } static void print_section(struct section *s) { Elf_Data *id; int elferr; if (s->buf != NULL && s->sz > 0) { print_data(s->buf, s->sz); } else { id = NULL; while ((id = elf_getdata(s->is, id)) != NULL) print_data(id->d_buf, id->d_size); elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); } putchar('\n'); } static void * read_section(struct section *s, size_t *size) { Elf_Data *id; char *b; size_t sz; int elferr; sz = 0; b = NULL; id = NULL; while ((id = elf_getdata(s->is, id)) != NULL) { if (b == NULL) b = malloc(id->d_size); else b = malloc(sz + id->d_size); if (b == NULL) err(EXIT_FAILURE, "malloc or realloc failed"); memcpy(&b[sz], id->d_buf, id->d_size); sz += id->d_size; } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); *size = sz; return (b); } void copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, int sec_flags) { GElf_Shdr ish, osh; if (gelf_getshdr(s->is, &ish) == NULL) errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s", elf_errmsg(-1)); if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s", elf_errmsg(-1)); if (copy) (void) memcpy(&osh, &ish, sizeof(ish)); else { osh.sh_type = s->type; osh.sh_addr = s->vma; osh.sh_offset = s->off; osh.sh_size = s->sz; osh.sh_link = ish.sh_link; osh.sh_info = ish.sh_info; osh.sh_addralign = s->align; osh.sh_entsize = ish.sh_entsize; if (sec_flags) { osh.sh_flags = 0; if (sec_flags & SF_ALLOC) { osh.sh_flags |= SHF_ALLOC; if (!s->loadable) warnx("set SHF_ALLOC flag for " "unloadable section %s", s->name); } if ((sec_flags & SF_READONLY) == 0) osh.sh_flags |= SHF_WRITE; if (sec_flags & SF_CODE) osh.sh_flags |= SHF_EXECINSTR; } else osh.sh_flags = ish.sh_flags; } if (name == NULL) add_to_shstrtab(ecp, s->name); else add_to_shstrtab(ecp, name); if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "elf_update_shdr failed: %s", elf_errmsg(-1)); } void copy_data(struct section *s) { Elf_Data *id, *od; int elferr; if (s->nocopy && s->buf == NULL) return; if ((id = elf_getdata(s->is, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); return; } if ((od = elf_newdata(s->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); if (s->nocopy) { /* Use s->buf as content if s->nocopy is set. */ od->d_align = id->d_align; od->d_off = 0; od->d_buf = s->buf; od->d_type = id->d_type; od->d_size = s->sz; od->d_version = id->d_version; } else { od->d_align = id->d_align; od->d_off = id->d_off; od->d_buf = id->d_buf; od->d_type = id->d_type; od->d_size = id->d_size; od->d_version = id->d_version; } } struct section * create_external_section(struct elfcopy *ecp, const char *name, char *newname, void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype, uint64_t flags, uint64_t align, uint64_t vma, int loadable) { struct section *s; Elf_Scn *os; Elf_Data *od; GElf_Shdr osh; if ((os = elf_newscn(ecp->eout)) == NULL) errx(EXIT_FAILURE, "elf_newscn() failed: %s", elf_errmsg(-1)); if ((s = calloc(1, sizeof(*s))) == NULL) err(EXIT_FAILURE, "calloc failed"); s->name = name; s->newname = newname; /* needs to be free()'ed */ s->off = off; s->sz = size; s->vma = vma; s->align = align; s->loadable = loadable; s->is = NULL; s->os = os; s->type = stype; s->nocopy = 1; insert_to_sec_list(ecp, s, 1); if (gelf_getshdr(os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); osh.sh_flags = flags; osh.sh_type = s->type; osh.sh_addr = s->vma; osh.sh_addralign = s->align; if (!gelf_update_shdr(os, &osh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); add_to_shstrtab(ecp, name); if (buf != NULL && size != 0) { if ((od = elf_newdata(os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); od->d_align = align; od->d_off = 0; od->d_buf = buf; od->d_size = size; od->d_type = dtype; od->d_version = EV_CURRENT; } /* * Clear SYMTAB_INTACT, as we probably need to update/add new * STT_SECTION symbols into the symbol table. */ ecp->flags &= ~SYMTAB_INTACT; return (s); } /* * Insert sections specified by --add-section to the end of section list. */ static void insert_sections(struct elfcopy *ecp) { struct sec_add *sa; struct section *s; size_t off; /* Put these sections in the end of current list. */ off = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->type != SHT_NOBITS && s->type != SHT_NULL) off = s->off + s->sz; else off = s->off; } STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) { /* TODO: Add section header vma/lma, flag changes here */ (void) create_external_section(ecp, sa->name, NULL, sa->content, sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0); } } void add_to_shstrtab(struct elfcopy *ecp, const char *name) { struct section *s; s = ecp->shstrtab; - if (s->buf == NULL) { - insert_to_strtab(s, ""); - insert_to_strtab(s, ".symtab"); - insert_to_strtab(s, ".strtab"); - insert_to_strtab(s, ".shstrtab"); - } insert_to_strtab(s, name); } void update_shdr(struct elfcopy *ecp, int update_link) { struct section *s; GElf_Shdr osh; int elferr; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->pseudo) continue; if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s", elf_errmsg(-1)); /* Find section name in string table and set sh_name. */ osh.sh_name = lookup_string(ecp->shstrtab, s->name); /* * sh_link needs to be updated, since the index of the * linked section might have changed. */ if (update_link && osh.sh_link != 0) osh.sh_link = ecp->secndx[osh.sh_link]; /* * sh_info of relocation section links to the section to which * its relocation info applies. So it may need update as well. */ if ((s->type == SHT_REL || s->type == SHT_RELA) && osh.sh_info != 0) osh.sh_info = ecp->secndx[osh.sh_info]; if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); } void init_shstrtab(struct elfcopy *ecp) { struct section *s; if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL) err(EXIT_FAILURE, "calloc failed"); s = ecp->shstrtab; s->name = ".shstrtab"; s->is = NULL; s->sz = 0; s->align = 1; s->loadable = 0; s->type = SHT_STRTAB; s->vma = 0; + + insert_to_strtab(s, ""); + insert_to_strtab(s, ".symtab"); + insert_to_strtab(s, ".strtab"); + insert_to_strtab(s, ".shstrtab"); } void set_shstrtab(struct elfcopy *ecp) { struct section *s; Elf_Data *data; GElf_Shdr sh; s = ecp->shstrtab; if (gelf_getshdr(s->os, &sh) == NULL) errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s", elf_errmsg(-1)); sh.sh_addr = 0; sh.sh_addralign = 1; sh.sh_offset = s->off; sh.sh_type = SHT_STRTAB; sh.sh_flags = 0; sh.sh_entsize = 0; sh.sh_info = 0; sh.sh_link = 0; if ((data = elf_newdata(s->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); /* * If we don't have a symbol table, skip those a few bytes * which are reserved for this in the beginning of shstrtab. */ if (!(ecp->flags & SYMTAB_EXIST)) { s->sz -= sizeof(".symtab\0.strtab"); memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"), s->sz); } sh.sh_size = s->sz; if (!gelf_update_shdr(s->os, &sh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); data->d_align = 1; data->d_buf = s->buf; data->d_size = s->sz; data->d_off = 0; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os))) errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s", elf_errmsg(-1)); } void add_section(struct elfcopy *ecp, const char *arg) { struct sec_add *sa; struct stat sb; const char *s, *fn; FILE *fp; int len; if ((s = strchr(arg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --add-section option"); if ((sa = malloc(sizeof(*sa))) == NULL) err(EXIT_FAILURE, "malloc failed"); len = s - arg; if ((sa->name = malloc(len + 1)) == NULL) err(EXIT_FAILURE, "malloc failed"); strncpy(sa->name, arg, len); sa->name[len] = '\0'; fn = s + 1; if (stat(fn, &sb) == -1) err(EXIT_FAILURE, "stat failed"); sa->size = sb.st_size; if ((sa->content = malloc(sa->size)) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((fp = fopen(fn, "r")) == NULL) err(EXIT_FAILURE, "can not open %s", fn); if (fread(sa->content, 1, sa->size, fp) == 0 || ferror(fp)) err(EXIT_FAILURE, "fread failed"); fclose(fp); STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); ecp->flags |= SEC_ADD; } void free_sec_add(struct elfcopy *ecp) { struct sec_add *sa, *sa_temp; STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) { STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list); free(sa->name); free(sa->content); free(sa); } } static void add_gnu_debuglink(struct elfcopy *ecp) { struct sec_add *sa; struct stat sb; FILE *fp; char *fnbase, *buf; int crc_off; int crc; if (ecp->debuglink == NULL) return; /* Read debug file content. */ if ((sa = malloc(sizeof(*sa))) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((sa->name = strdup(".gnu_debuglink")) == NULL) err(EXIT_FAILURE, "strdup failed"); if (stat(ecp->debuglink, &sb) == -1) err(EXIT_FAILURE, "stat failed"); if ((buf = malloc(sb.st_size)) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((fp = fopen(ecp->debuglink, "r")) == NULL) err(EXIT_FAILURE, "can not open %s", ecp->debuglink); if (fread(buf, 1, sb.st_size, fp) == 0 || ferror(fp)) err(EXIT_FAILURE, "fread failed"); fclose(fp); /* Calculate crc checksum. */ crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF); free(buf); /* Calculate section size and the offset to store crc checksum. */ if ((fnbase = basename(ecp->debuglink)) == NULL) err(EXIT_FAILURE, "basename failed"); crc_off = roundup(strlen(fnbase) + 1, 4); sa->size = crc_off + 4; /* Section content. */ if ((sa->content = calloc(1, sa->size)) == NULL) err(EXIT_FAILURE, "malloc failed"); strncpy(sa->content, fnbase, strlen(fnbase)); if (ecp->oed == ELFDATA2LSB) { sa->content[crc_off] = crc & 0xFF; sa->content[crc_off + 1] = (crc >> 8) & 0xFF; sa->content[crc_off + 2] = (crc >> 16) & 0xFF; sa->content[crc_off + 3] = crc >> 24; } else { sa->content[crc_off] = crc >> 24; sa->content[crc_off + 1] = (crc >> 16) & 0xFF; sa->content[crc_off + 2] = (crc >> 8) & 0xFF; sa->content[crc_off + 3] = crc & 0xFF; } STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); ecp->flags |= SEC_ADD; } static void insert_to_strtab(struct section *t, const char *s) { const char *r; char *b, *c; size_t len, slen; int append; if (t->sz == 0) { t->cap = 512; if ((t->buf = malloc(t->cap)) == NULL) err(EXIT_FAILURE, "malloc failed"); } slen = strlen(s); append = 0; b = t->buf; for (c = b; c < b + t->sz;) { len = strlen(c); if (!append && len >= slen) { r = c + (len - slen); if (strcmp(r, s) == 0) return; } else if (len < slen && len != 0) { r = s + (slen - len); if (strcmp(c, r) == 0) { t->sz -= len + 1; memmove(c, c + len + 1, t->sz - (c - b)); append = 1; continue; } } c += len + 1; } while (t->sz + slen + 1 >= t->cap) { t->cap *= 2; if ((t->buf = realloc(t->buf, t->cap)) == NULL) err(EXIT_FAILURE, "realloc failed"); } b = t->buf; strncpy(&b[t->sz], s, slen); b[t->sz + slen] = '\0'; t->sz += slen + 1; } static int lookup_string(struct section *t, const char *s) { const char *b, *c, *r; size_t len, slen; slen = strlen(s); b = t->buf; for (c = b; c < b + t->sz;) { len = strlen(c); if (len >= slen) { r = c + (len - slen); if (strcmp(r, s) == 0) return (r - b); } c += len + 1; } return (-1); } static uint32_t crctable[256] = { 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL }; static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc) { uint32_t i; for (i = 0; i < len; i++) { crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8); } return (crc ^ 0xFFFFFFFF); } diff --git a/elfcopy/segments.c b/elfcopy/segments.c index c54cbfcbb07a..e48ad127bfd0 100644 --- a/elfcopy/segments.c +++ b/elfcopy/segments.c @@ -1,493 +1,493 @@ /*- * Copyright (c) 2007-2010,2012 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: segments.c 2542 2012-08-12 16:14:15Z kaiwang27 $"); +ELFTC_VCSID("$Id: segments.c 3113 2014-12-20 08:33:29Z kaiwang27 $"); static void insert_to_inseg_list(struct segment *seg, struct section *sec); /* * elfcopy's segment handling is relatively simpler and less powerful than * libbfd. Program headers are modified or copied from input to output objects, * but never re-generated. As a result, if the input object has incorrect * program headers, the output object's program headers will remain incorrect * or become even worse. */ /* * Check whether a section is "loadable". If so, add it to the * corresponding segment list(s) and return 1. */ int add_to_inseg_list(struct elfcopy *ecp, struct section *s) { struct segment *seg; int loadable; if (ecp->ophnum == 0) return (0); /* * Segment is a different view of an ELF object. One segment can * contain one or more sections, and one section can be included * in one or more segments, or not included in any segment at all. * We call those sections which can be found in one or more segments * "loadable" sections, and call the rest "unloadable" sections. * We keep track of "loadable" sections in their containing * segment(s)' v_sec queue. These information are later used to * recalculate the extents of segments, when sections are removed, * for example. */ loadable = 0; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { - if (s->off < seg->off) + if (s->off < seg->off || (s->vma < seg->addr && !s->pseudo)) continue; if (s->off + s->sz > seg->off + seg->fsz && s->type != SHT_NOBITS) continue; if (s->off + s->sz > seg->off + seg->msz) continue; + if (s->vma + s->sz > seg->addr + seg->msz) + continue; insert_to_inseg_list(seg, s); if (seg->type == PT_LOAD) s->seg = seg; s->lma = seg->addr + (s->off - seg->off); loadable = 1; } return (loadable); } void adjust_addr(struct elfcopy *ecp) { struct section *s, *s0; struct segment *seg; struct sec_action *sac; - uint64_t dl, lma, old_vma, start, end; + uint64_t dl, lma, start, end; int found, i; /* * Apply VMA and global LMA changes in the first iteration. */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { /* Only adjust loadable section's address. */ if (!s->loadable || s->seg == NULL) continue; /* Apply global LMA adjustment. */ if (ecp->change_addr != 0) s->lma += ecp->change_addr; if (!s->pseudo) { - old_vma = s->vma; - /* Apply global VMA adjustment. */ if (ecp->change_addr != 0) s->vma += ecp->change_addr; /* Apply section VMA adjustment. */ sac = lookup_sec_act(ecp, s->name, 0); if (sac == NULL) continue; if (sac->setvma) s->vma = sac->vma; if (sac->vma_adjust != 0) s->vma += sac->vma_adjust; } } /* * Apply sections LMA change in the second iteration. */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { /* Only adjust loadable section's LMA. */ if (!s->loadable || s->seg == NULL) continue; /* * Check if there is a LMA change request for this * section. */ sac = lookup_sec_act(ecp, s->name, 0); if (sac == NULL) continue; if (!sac->setlma && sac->lma_adjust == 0) continue; lma = s->lma; if (sac->setlma) lma = sac->lma; if (sac->lma_adjust != 0) lma += sac->lma_adjust; if (lma == s->lma) continue; /* * Check if the LMA change is viable. * * 1. Check if the new LMA is properly aligned accroding to * section alignment. * * 2. Compute the new extent of segment that contains this * section, make sure it doesn't overlap with other * segments. */ #ifdef DEBUG printf("LMA for section %s: %#jx\n", s->name, lma); #endif if (lma % s->align != 0) errx(EXIT_FAILURE, "The load address %#jx for " "section %s is not aligned to %ju", (uintmax_t) lma, s->name, s->align); if (lma < s->lma) { /* Move section to lower address. */ if (lma < s->lma - s->seg->addr) errx(EXIT_FAILURE, "Not enough space to move " "section %s load address to %#jx", s->name, (uintmax_t) lma); start = lma - (s->lma - s->seg->addr); if (s == s->seg->v_sec[s->seg->nsec - 1]) end = start + s->seg->msz; else end = s->seg->addr + s->seg->msz; } else { /* Move section to upper address. */ if (s == s->seg->v_sec[0]) start = lma; else start = s->seg->addr; end = lma + (s->seg->addr + s->seg->msz - s->lma); if (end < start) errx(EXIT_FAILURE, "Not enough space to move " "section %s load address to %#jx", s->name, (uintmax_t) lma); } #ifdef DEBUG printf("new extent for segment containing %s: (%#jx,%#jx)\n", s->name, start, end); #endif STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (seg == s->seg || seg->type != PT_LOAD) continue; if (start > seg->addr + seg->msz) continue; if (end < seg->addr) continue; errx(EXIT_FAILURE, "The extent of segment containing " "section %s overlaps with segment(%#jx,%#jx)", s->name, seg->addr, seg->addr + seg->msz); } /* * Update section LMA and file offset. */ if (lma < s->lma) { /* * To move a section to lower load address, we decrease * the load addresses of the section and all the * sections that are before it, and we increase the * file offsets of all the sections that are after it. */ dl = s->lma - lma; for (i = 0; i < s->seg->nsec; i++) { s0 = s->seg->v_sec[i]; s0->lma -= dl; #ifdef DEBUG printf("section %s LMA set to %#jx\n", s0->name, (uintmax_t) s0->lma); #endif if (s0 == s) break; } for (i = i + 1; i < s->seg->nsec; i++) { s0 = s->seg->v_sec[i]; s0->off += dl; #ifdef DEBUG printf("section %s offset set to %#jx\n", s0->name, (uintmax_t) s0->off); #endif } } else { /* * To move a section to upper load address, we increase * the load addresses of the section and all the * sections that are after it, and we increase the * their file offsets too unless the section in question * is the first in its containing segment. */ dl = lma - s->lma; for (i = 0; i < s->seg->nsec; i++) if (s->seg->v_sec[i] == s) break; if (i >= s->seg->nsec) errx(EXIT_FAILURE, "Internal: section `%s' not" " found in its containing segement", s->name); for (; i < s->seg->nsec; i++) { s0 = s->seg->v_sec[i]; s0->lma += dl; #ifdef DEBUG printf("section %s LMA set to %#jx\n", s0->name, (uintmax_t) s0->lma); #endif if (s != s->seg->v_sec[0]) { s0->off += dl; #ifdef DEBUG printf("section %s offset set to %#jx\n", s0->name, (uintmax_t) s0->off); #endif } } } } /* * Apply load address padding. */ if (ecp->pad_to != 0) { /* * Find the section with highest load address. */ s = NULL; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (seg->type != PT_LOAD) continue; for (i = seg->nsec - 1; i >= 0; i--) if (seg->v_sec[i]->type != SHT_NOBITS) break; if (i < 0) continue; if (s == NULL) s = seg->v_sec[i]; else { s0 = seg->v_sec[i]; if (s0->lma > s->lma) s = s0; } } if (s == NULL) goto issue_warn; /* No need to pad if the pad_to address is lower. */ if (ecp->pad_to <= s->lma + s->sz) goto issue_warn; s->pad_sz = ecp->pad_to - (s->lma + s->sz); #ifdef DEBUG printf("pad section %s load to address %#jx by %#jx\n", s->name, (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz); #endif } issue_warn: /* * Issue a warning if there are VMA/LMA adjust requests for * some nonexistent sections. */ if ((ecp->flags & NO_CHANGE_WARN) == 0) { STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { if (!sac->setvma && !sac->setlma && !sac->vma_adjust && !sac->lma_adjust) continue; found = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->pseudo || s->name == NULL) continue; if (!strcmp(s->name, sac->name)) { found = 1; break; } } if (!found) warnx("cannot find section `%s'", sac->name); } } } static void insert_to_inseg_list(struct segment *seg, struct section *sec) { struct section *s; int i; seg->nsec++; seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec)); if (seg->v_sec == NULL) err(EXIT_FAILURE, "realloc failed"); /* * Sort the section in order of offset. */ for (i = seg->nsec - 1; i > 0; i--) { s = seg->v_sec[i - 1]; if (sec->off >= s->off) { seg->v_sec[i] = sec; break; } else seg->v_sec[i] = s; } if (i == 0) seg->v_sec[0] = sec; } void setup_phdr(struct elfcopy *ecp) { struct segment *seg; GElf_Phdr iphdr; size_t iphnum; int i; if (elf_getphnum(ecp->ein, &iphnum) == 0) errx(EXIT_FAILURE, "elf_getphnum failed: %s", elf_errmsg(-1)); ecp->ophnum = ecp->iphnum = iphnum; if (iphnum == 0) return; /* If --only-keep-debug is specified, discard all program headers. */ if (ecp->strip == STRIP_NONDEBUG) { ecp->ophnum = 0; return; } for (i = 0; (size_t)i < iphnum; i++) { if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) errx(EXIT_FAILURE, "gelf_getphdr failed: %s", elf_errmsg(-1)); if ((seg = calloc(1, sizeof(*seg))) == NULL) err(EXIT_FAILURE, "calloc failed"); seg->addr = iphdr.p_vaddr; seg->off = iphdr.p_offset; seg->fsz = iphdr.p_filesz; seg->msz = iphdr.p_memsz; seg->type = iphdr.p_type; STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list); } } void copy_phdr(struct elfcopy *ecp) { struct segment *seg; struct section *s; GElf_Phdr iphdr, ophdr; int i; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (seg->type == PT_PHDR) { if (!TAILQ_EMPTY(&ecp->v_sec)) { s = TAILQ_FIRST(&ecp->v_sec); if (s->pseudo) seg->addr = s->lma + gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); } seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT); continue; } seg->fsz = seg->msz = 0; for (i = 0; i < seg->nsec; i++) { s = seg->v_sec[i]; - seg->msz = s->off + s->sz - seg->off; + seg->msz = s->vma + s->sz - seg->addr; if (s->type != SHT_NOBITS) seg->fsz = seg->msz; } } /* * Allocate space for program headers, note that libelf keep * track of the number in internal variable, and a call to * elf_update is needed to update e_phnum of ehdr. */ if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL) errx(EXIT_FAILURE, "gelf_newphdr() failed: %s", elf_errmsg(-1)); /* * This elf_update() call is to update the e_phnum field in * ehdr. It's necessary because later we will call gelf_getphdr(), * which does sanity check by comparing ndx argument with e_phnum. */ if (elf_update(ecp->eout, ELF_C_NULL) < 0) errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1)); /* * iphnum == ophnum, since we don't remove program headers even if * they no longer contain sections. */ i = 0; STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { if (i >= ecp->iphnum) break; if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) errx(EXIT_FAILURE, "gelf_getphdr failed: %s", elf_errmsg(-1)); if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr) errx(EXIT_FAILURE, "gelf_getphdr failed: %s", elf_errmsg(-1)); ophdr.p_type = iphdr.p_type; ophdr.p_vaddr = seg->addr; ophdr.p_paddr = seg->addr; ophdr.p_flags = iphdr.p_flags; ophdr.p_align = iphdr.p_align; ophdr.p_offset = seg->off; ophdr.p_filesz = seg->fsz; ophdr.p_memsz = seg->msz; if (!gelf_update_phdr(ecp->eout, i, &ophdr)) err(EXIT_FAILURE, "gelf_update_phdr failed :%s", elf_errmsg(-1)); i++; } } diff --git a/elfcopy/symbols.c b/elfcopy/symbols.c index f2a722736c83..573a18f25e79 100644 --- a/elfcopy/symbols.c +++ b/elfcopy/symbols.c @@ -1,1040 +1,1039 @@ /*- * Copyright (c) 2007-2013 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: symbols.c 2971 2013-12-01 15:22:21Z kaiwang27 $"); +ELFTC_VCSID("$Id: symbols.c 3019 2014-04-17 14:53:40Z jkoshy $"); /* Symbol table buffer structure. */ struct symbuf { Elf32_Sym *l32; /* 32bit local symbol */ Elf32_Sym *g32; /* 32bit global symbol */ Elf64_Sym *l64; /* 64bit local symbol */ Elf64_Sym *g64; /* 64bit global symbol */ size_t ngs, nls; /* number of each kind */ size_t gcap, lcap; /* buffer capacities. */ }; /* String table buffer structure. */ struct strbuf { char *l; /* local symbol string table */ char *g; /* global symbol string table */ size_t lsz, gsz; /* size of each kind */ size_t gcap, lcap; /* buffer capacities. */ }; static int is_debug_symbol(unsigned char st_info); static int is_global_symbol(unsigned char st_info); static int is_local_symbol(unsigned char st_info); static int is_local_label(const char *name); static int is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s); static int is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, const char *name); static int is_weak_symbol(unsigned char st_info); static int lookup_exact_string(const char *buf, size_t sz, const char *s); static int generate_symbols(struct elfcopy *ecp); static void mark_symbols(struct elfcopy *ecp, size_t sc); static int match_wildcard(const char *name, const char *pattern); /* Convenient bit vector operation macros. */ #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7)) #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7))) #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7))) static int is_debug_symbol(unsigned char st_info) { if (GELF_ST_TYPE(st_info) == STT_SECTION || GELF_ST_TYPE(st_info) == STT_FILE) return (1); return (0); } static int is_global_symbol(unsigned char st_info) { if (GELF_ST_BIND(st_info) == STB_GLOBAL) return (1); return (0); } static int is_weak_symbol(unsigned char st_info) { if (GELF_ST_BIND(st_info) == STB_WEAK) return (1); return (0); } static int is_local_symbol(unsigned char st_info) { if (GELF_ST_BIND(st_info) == STB_LOCAL) return (1); return (0); } static int is_local_label(const char *name) { /* Compiler generated local symbols that start with .L */ if (name[0] == '.' && name[1] == 'L') return (1); return (0); } /* * Symbols related to relocation are needed. */ static int is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s) { /* If symbol involves relocation, it is needed. */ if (BIT_ISSET(ecp->v_rel, i)) return (1); /* * For relocatable files (.o files), global and weak symbols * are needed. */ if (ecp->flags & RELOCATABLE) { if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info)) return (1); } return (0); } static int is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, const char *name) { GElf_Sym sym0 = { 0, /* st_name */ 0, /* st_value */ 0, /* st_size */ 0, /* st_info */ 0, /* st_other */ SHN_UNDEF, /* st_shndx */ }; if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) return (0); if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) return (1); /* * Keep the first symbol if it is the special reserved symbol. * XXX Should we generate one if it's missing? */ if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym))) return (0); /* Remove the symbol if the section it refers to was removed. */ if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE && ecp->secndx[s->st_shndx] == 0) return (1); if (ecp->strip == STRIP_ALL) return (1); if (ecp->v_rel == NULL) mark_symbols(ecp, sc); if (is_needed_symbol(ecp, i, s)) return (0); if (ecp->strip == STRIP_UNNEEDED) return (1); if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) && !is_debug_symbol(s->st_info)) return (1); if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) && !is_debug_symbol(s->st_info) && is_local_label(name)) return (1); if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info)) return (1); return (0); } /* * Mark symbols refered by relocation entries. */ static void mark_symbols(struct elfcopy *ecp, size_t sc) { const char *name; Elf_Data *d; Elf_Scn *s; GElf_Rel r; GElf_Rela ra; GElf_Shdr sh; size_t n, indx; int elferr, i, len; ecp->v_rel = calloc((sc + 7) / 8, 1); if (ecp->v_rel == NULL) err(EXIT_FAILURE, "calloc failed"); if (elf_getshstrndx(ecp->ein, &indx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", elf_errmsg(-1)); s = NULL; while ((s = elf_nextscn(ecp->ein, s)) != NULL) { if (gelf_getshdr(s, &sh) != &sh) errx(EXIT_FAILURE, "elf_getshdr failed: %s", elf_errmsg(-1)); if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA) continue; /* * Skip if this reloc section won't appear in the * output object. */ if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (is_remove_section(ecp, name) || is_remove_reloc_sec(ecp, sh.sh_info)) continue; /* Skip if it's not for .symtab */ if (sh.sh_link != elf_ndxscn(ecp->symtab->is)) continue; d = NULL; n = 0; while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) { len = d->d_size / sh.sh_entsize; for (i = 0; i < len; i++) { if (sh.sh_type == SHT_REL) { if (gelf_getrel(d, i, &r) != &r) errx(EXIT_FAILURE, "elf_getrel failed: %s", elf_errmsg(-1)); n = GELF_R_SYM(r.r_info); } else { if (gelf_getrela(d, i, &ra) != &ra) errx(EXIT_FAILURE, "elf_getrela failed: %s", elf_errmsg(-1)); n = GELF_R_SYM(ra.r_info); } if (n > 0 && n < sc) BIT_SET(ecp->v_rel, n); else if (n != 0) warnx("invalid symbox index"); } } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata failed: %s", elf_errmsg(elferr)); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); } static int generate_symbols(struct elfcopy *ecp) { struct section *s; struct symop *sp; struct symbuf *sy_buf; struct strbuf *st_buf; const char *name; char *newname; unsigned char *gsym; GElf_Shdr ish; GElf_Sym sym; Elf_Data* id; Elf_Scn *is; - size_t ishstrndx, namelen, ndx, nsyms, sc, symndx; + size_t ishstrndx, namelen, ndx, sc, symndx; int ec, elferr, i; if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", elf_errmsg(-1)); if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE) errx(EXIT_FAILURE, "gelf_getclass failed: %s", elf_errmsg(-1)); /* Create buffers for .symtab and .strtab. */ if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) err(EXIT_FAILURE, "calloc failed"); if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) err(EXIT_FAILURE, "calloc failed"); sy_buf->gcap = sy_buf->lcap = 64; st_buf->gcap = 256; st_buf->lcap = 64; st_buf->lsz = 1; /* '\0' at start. */ st_buf->gsz = 0; - nsyms = 0; ecp->symtab->sz = 0; ecp->strtab->sz = 0; ecp->symtab->buf = sy_buf; ecp->strtab->buf = st_buf; /* * Create bit vector v_secsym, which is used to mark sections * that already have corresponding STT_SECTION symbols. */ ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1); if (ecp->v_secsym == NULL) err(EXIT_FAILURE, "calloc failed"); /* Locate .strtab of input object. */ symndx = 0; name = NULL; is = NULL; while ((is = elf_nextscn(ecp->ein, is)) != NULL) { if (gelf_getshdr(is, &ish) != &ish) errx(EXIT_FAILURE, "elf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (strcmp(name, ".strtab") == 0) { symndx = elf_ndxscn(is); break; } } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); /* Symbol table should exist if this function is called. */ if (symndx == 0) { warnx("can't find .strtab section"); return (0); } /* Locate .symtab of input object. */ is = NULL; while ((is = elf_nextscn(ecp->ein, is)) != NULL) { if (gelf_getshdr(is, &ish) != &ish) errx(EXIT_FAILURE, "elf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (strcmp(name, ".symtab") == 0) break; } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); if (is == NULL) errx(EXIT_FAILURE, "can't find .strtab section"); /* * Create bit vector gsym to mark global symbols, and symndx * to keep track of symbol index changes from input object to * output object, it is used by update_reloc() later to update * relocation information. */ gsym = NULL; sc = ish.sh_size / ish.sh_entsize; if (sc > 0) { ecp->symndx = calloc(sc, sizeof(*ecp->symndx)); if (ecp->symndx == NULL) err(EXIT_FAILURE, "calloc failed"); gsym = calloc((sc + 7) / 8, sizeof(*gsym)); if (gsym == NULL) err(EXIT_FAILURE, "calloc failed"); if ((id = elf_getdata(is, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata failed: %s", elf_errmsg(elferr)); return (0); } } else return (0); /* Copy/Filter each symbol. */ for (i = 0; (size_t)i < sc; i++) { if (gelf_getsym(id, i, &sym) != &sym) errx(EXIT_FAILURE, "gelf_getsym failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); /* Symbol filtering. */ if (is_remove_symbol(ecp, sc, i, &sym, name) != 0) continue; /* Check if we need to change the binding of this symbol. */ if (is_global_symbol(sym.st_info) || is_weak_symbol(sym.st_info)) { /* * XXX Binutils objcopy does not weaken certain * symbols. */ if (ecp->flags & WEAKEN_ALL || lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL) sym.st_info = GELF_ST_INFO(STB_WEAK, GELF_ST_TYPE(sym.st_info)); /* Do not localize undefined symbols. */ if (sym.st_shndx != SHN_UNDEF && lookup_symop_list(ecp, name, SYMOP_LOCALIZE) != NULL) sym.st_info = GELF_ST_INFO(STB_LOCAL, GELF_ST_TYPE(sym.st_info)); if (ecp->flags & KEEP_GLOBAL && sym.st_shndx != SHN_UNDEF && lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL) sym.st_info = GELF_ST_INFO(STB_LOCAL, GELF_ST_TYPE(sym.st_info)); } else { /* STB_LOCAL binding. */ if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) != NULL) sym.st_info = GELF_ST_INFO(STB_GLOBAL, GELF_ST_TYPE(sym.st_info)); /* XXX We should globalize weak symbol? */ } /* Check if we need to rename this symbol. */ if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL) name = sp->newname; /* Check if we need to prefix the symbols. */ newname = NULL; if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') { namelen = strlen(name) + strlen(ecp->prefix_sym) + 1; if ((newname = malloc(namelen)) == NULL) err(EXIT_FAILURE, "malloc failed"); snprintf(newname, namelen, "%s%s", ecp->prefix_sym, name); name = newname; } /* Copy symbol, mark global/weak symbol and add to index map. */ if (is_global_symbol(sym.st_info) || is_weak_symbol(sym.st_info)) { BIT_SET(gsym, i); ecp->symndx[i] = sy_buf->ngs; } else ecp->symndx[i] = sy_buf->nls; add_to_symtab(ecp, name, sym.st_value, sym.st_size, sym.st_shndx, sym.st_info, sym.st_other, 0); if (newname != NULL) free(newname); /* * If the symbol is a STT_SECTION symbol, mark the section * it points to. */ if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]); } /* * Give up if there is no real symbols inside the table. * XXX The logic here needs to be improved. We need to * check if that only local symbol is the reserved symbol. */ if (sy_buf->nls <= 1 && sy_buf->ngs == 0) return (0); /* * Create STT_SECTION symbols for sections that do not already * got one. However, we do not create STT_SECTION symbol for * .symtab, .strtab, .shstrtab and reloc sec of relocatables. */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->pseudo) continue; if (strcmp(s->name, ".symtab") == 0 || strcmp(s->name, ".strtab") == 0 || strcmp(s->name, ".shstrtab") == 0) continue; if ((ecp->flags & RELOCATABLE) != 0 && ((s->type == SHT_REL) || (s->type == SHT_RELA))) continue; if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) errx(EXIT_FAILURE, "elf_ndxscn failed: %s", elf_errmsg(-1)); if (!BIT_ISSET(ecp->v_secsym, ndx)) { sym.st_name = 0; sym.st_value = s->vma; sym.st_size = 0; sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); /* * Don't let add_to_symtab() touch sym.st_shndx. * In this case, we know the index already. */ add_to_symtab(ecp, NULL, sym.st_value, sym.st_size, ndx, sym.st_info, sym.st_other, 1); } } /* * Update st_name and index map for global/weak symbols. Note that * global/weak symbols are put after local symbols. */ if (gsym != NULL) { for(i = 0; (size_t) i < sc; i++) { if (!BIT_ISSET(gsym, i)) continue; /* Update st_name. */ if (ec == ELFCLASS32) sy_buf->g32[ecp->symndx[i]].st_name += st_buf->lsz; else sy_buf->g64[ecp->symndx[i]].st_name += st_buf->lsz; /* Update index map. */ ecp->symndx[i] += sy_buf->nls; } free(gsym); } return (1); } void create_symtab(struct elfcopy *ecp) { struct section *s, *sy, *st; size_t maxndx, ndx; sy = ecp->symtab; st = ecp->strtab; /* * Set section index map for .symtab and .strtab. We need to set * these map because otherwise symbols which refer to .symtab and * .strtab will be removed by symbol filtering unconditionally. * And we have to figure out scn index this way (instead of calling * elf_ndxscn) because we can not create Elf_Scn before we're certain * that .symtab and .strtab will exist in the output object. */ maxndx = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->os == NULL) continue; if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) errx(EXIT_FAILURE, "elf_ndxscn failed: %s", elf_errmsg(-1)); if (ndx > maxndx) maxndx = ndx; } ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1; ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2; /* * Generate symbols for output object if SYMTAB_INTACT is not set. * If there is no symbol in the input object or all the symbols are * stripped, then free all the resouces allotted for symbol table, * and clear SYMTAB_EXIST flag. */ if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) { TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list); TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list); free(ecp->symtab); free(ecp->strtab); ecp->symtab = NULL; ecp->strtab = NULL; ecp->flags &= ~SYMTAB_EXIST; return; } /* Create output Elf_Scn for .symtab and .strtab. */ if ((sy->os = elf_newscn(ecp->eout)) == NULL || (st->os = elf_newscn(ecp->eout)) == NULL) errx(EXIT_FAILURE, "elf_newscn failed: %s", elf_errmsg(-1)); /* Update secndx anyway. */ ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os); ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os); /* * Copy .symtab and .strtab section headers from input to output * object to start with, these will be overridden later if need. */ copy_shdr(ecp, sy, ".symtab", 1, 0); copy_shdr(ecp, st, ".strtab", 1, 0); /* Copy verbatim if symbol table is intact. */ if (ecp->flags & SYMTAB_INTACT) { copy_data(sy); copy_data(st); return; } create_symtab_data(ecp); } void free_symtab(struct elfcopy *ecp) { struct symbuf *sy_buf; struct strbuf *st_buf; if (ecp->symtab != NULL && ecp->symtab->buf != NULL) { sy_buf = ecp->symtab->buf; if (sy_buf->l32 != NULL) free(sy_buf->l32); if (sy_buf->g32 != NULL) free(sy_buf->g32); if (sy_buf->l64 != NULL) free(sy_buf->l64); if (sy_buf->g64 != NULL) free(sy_buf->g64); } if (ecp->strtab != NULL && ecp->strtab->buf != NULL) { st_buf = ecp->strtab->buf; if (st_buf->l != NULL) free(st_buf->l); if (st_buf->g != NULL) free(st_buf->g); } } void create_external_symtab(struct elfcopy *ecp) { struct section *s; struct symbuf *sy_buf; struct strbuf *st_buf; GElf_Shdr sh; size_t ndx; if (ecp->oec == ELFCLASS32) ecp->symtab = create_external_section(ecp, ".symtab", NULL, NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0); else ecp->symtab = create_external_section(ecp, ".symtab", NULL, NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0); ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0, SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0); /* Let sh_link field of .symtab section point to .strtab section. */ if (gelf_getshdr(ecp->symtab->os, &sh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); sh.sh_link = elf_ndxscn(ecp->strtab->os); if (!gelf_update_shdr(ecp->symtab->os, &sh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); /* Create buffers for .symtab and .strtab. */ if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL) err(EXIT_FAILURE, "calloc failed"); if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL) err(EXIT_FAILURE, "calloc failed"); sy_buf->gcap = sy_buf->lcap = 64; st_buf->gcap = 256; st_buf->lcap = 64; st_buf->lsz = 1; /* '\0' at start. */ st_buf->gsz = 0; ecp->symtab->sz = 0; ecp->strtab->sz = 0; ecp->symtab->buf = sy_buf; ecp->strtab->buf = st_buf; /* Always create the special symbol at the symtab beginning. */ add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF, ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1); /* Create STT_SECTION symbols. */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->pseudo) continue; if (strcmp(s->name, ".symtab") == 0 || strcmp(s->name, ".strtab") == 0 || strcmp(s->name, ".shstrtab") == 0) continue; (void) elf_errno(); if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) { warnx("elf_ndxscn failed: %s", elf_errmsg(-1)); continue; } add_to_symtab(ecp, NULL, 0, 0, ndx, GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1); } } void add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, uint64_t st_size, uint16_t st_shndx, unsigned char st_info, unsigned char st_other, int ndx_known) { struct symbuf *sy_buf; struct strbuf *st_buf; int pos; /* * Convenient macro for copying global/local 32/64 bit symbols * from input object to the buffer created for output object. * It handles buffer growing, st_name calculating and st_shndx * updating for symbols with non-special section index. */ #define _ADDSYM(B, SZ) do { \ if (sy_buf->B##SZ == NULL) { \ sy_buf->B##SZ = malloc(sy_buf->B##cap * \ sizeof(Elf##SZ##_Sym)); \ if (sy_buf->B##SZ == NULL) \ err(EXIT_FAILURE, "malloc failed"); \ } else if (sy_buf->n##B##s >= sy_buf->B##cap) { \ sy_buf->B##cap *= 2; \ sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \ sizeof(Elf##SZ##_Sym)); \ if (sy_buf->B##SZ == NULL) \ err(EXIT_FAILURE, "realloc failed"); \ } \ sy_buf->B##SZ[sy_buf->n##B##s].st_info = st_info; \ sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other; \ sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value; \ sy_buf->B##SZ[sy_buf->n##B##s].st_size = st_size; \ if (ndx_known) \ sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE) \ sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \ else \ sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = \ ecp->secndx[st_shndx]; \ if (st_buf->B == NULL) { \ st_buf->B = calloc(st_buf->B##cap, sizeof(*st_buf->B)); \ if (st_buf->B == NULL) \ err(EXIT_FAILURE, "malloc failed"); \ } \ if (name != NULL && *name != '\0') { \ pos = lookup_exact_string(st_buf->B, \ st_buf->B##sz, name); \ if (pos != -1) \ sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \ else { \ sy_buf->B##SZ[sy_buf->n##B##s].st_name = \ st_buf->B##sz; \ while (st_buf->B##sz + strlen(name) >= \ st_buf->B##cap - 1) { \ st_buf->B##cap *= 2; \ st_buf->B = realloc(st_buf->B, \ st_buf->B##cap); \ if (st_buf->B == NULL) \ err(EXIT_FAILURE, \ "realloc failed"); \ } \ strncpy(&st_buf->B[st_buf->B##sz], name, \ strlen(name)); \ st_buf->B[st_buf->B##sz + strlen(name)] = '\0'; \ st_buf->B##sz += strlen(name) + 1; \ } \ } else \ sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0; \ sy_buf->n##B##s++; \ } while (0) sy_buf = ecp->symtab->buf; st_buf = ecp->strtab->buf; if (ecp->oec == ELFCLASS32) { if (is_local_symbol(st_info)) _ADDSYM(l, 32); else _ADDSYM(g, 32); } else { if (is_local_symbol(st_info)) _ADDSYM(l, 64); else _ADDSYM(g, 64); } /* Update section size. */ ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) * (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); ecp->strtab->sz = st_buf->lsz + st_buf->gsz; #undef _ADDSYM } void finalize_external_symtab(struct elfcopy *ecp) { struct symbuf *sy_buf; struct strbuf *st_buf; int i; /* * Update st_name for global/weak symbols. (global/weak symbols * are put after local symbols) */ sy_buf = ecp->symtab->buf; st_buf = ecp->strtab->buf; for (i = 0; (size_t) i < sy_buf->ngs; i++) { if (ecp->oec == ELFCLASS32) sy_buf->g32[i].st_name += st_buf->lsz; else sy_buf->g64[i].st_name += st_buf->lsz; } } void create_symtab_data(struct elfcopy *ecp) { struct section *sy, *st; struct symbuf *sy_buf; struct strbuf *st_buf; Elf_Data *gsydata, *lsydata, *gstdata, *lstdata; GElf_Shdr shy, sht; sy = ecp->symtab; st = ecp->strtab; if (gelf_getshdr(sy->os, ­) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); if (gelf_getshdr(st->os, &sht) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); /* * Create two Elf_Data for .symtab section of output object, one * for local symbols and another for global symbols. Note that * local symbols appear first in the .symtab. */ sy_buf = sy->buf; if (sy_buf->nls > 0) { if ((lsydata = elf_newdata(sy->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s.", elf_errmsg(-1)); if (ecp->oec == ELFCLASS32) { lsydata->d_align = 4; lsydata->d_off = 0; lsydata->d_buf = sy_buf->l32; lsydata->d_size = sy_buf->nls * sizeof(Elf32_Sym); lsydata->d_type = ELF_T_SYM; lsydata->d_version = EV_CURRENT; } else { lsydata->d_align = 8; lsydata->d_off = 0; lsydata->d_buf = sy_buf->l64; lsydata->d_size = sy_buf->nls * sizeof(Elf64_Sym); lsydata->d_type = ELF_T_SYM; lsydata->d_version = EV_CURRENT; } } if (sy_buf->ngs > 0) { if ((gsydata = elf_newdata(sy->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s.", elf_errmsg(-1)); if (ecp->oec == ELFCLASS32) { gsydata->d_align = 4; gsydata->d_off = sy_buf->nls * sizeof(Elf32_Sym); gsydata->d_buf = sy_buf->g32; gsydata->d_size = sy_buf->ngs * sizeof(Elf32_Sym); gsydata->d_type = ELF_T_SYM; gsydata->d_version = EV_CURRENT; } else { gsydata->d_align = 8; gsydata->d_off = sy_buf->nls * sizeof(Elf64_Sym); gsydata->d_buf = sy_buf->g64; gsydata->d_size = sy_buf->ngs * sizeof(Elf64_Sym); gsydata->d_type = ELF_T_SYM; gsydata->d_version = EV_CURRENT; } } /* * Create two Elf_Data for .strtab, one for local symbol name * and another for globals. Same as .symtab, local symbol names * appear first. */ st_buf = st->buf; if ((lstdata = elf_newdata(st->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s.", elf_errmsg(-1)); lstdata->d_align = 1; lstdata->d_off = 0; lstdata->d_buf = st_buf->l; lstdata->d_size = st_buf->lsz; lstdata->d_type = ELF_T_BYTE; lstdata->d_version = EV_CURRENT; if (st_buf->gsz > 0) { if ((gstdata = elf_newdata(st->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s.", elf_errmsg(-1)); gstdata->d_align = 1; gstdata->d_off = lstdata->d_size; gstdata->d_buf = st_buf->g; gstdata->d_size = st_buf->gsz; gstdata->d_type = ELF_T_BYTE; gstdata->d_version = EV_CURRENT; } shy.sh_addr = 0; shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8); shy.sh_size = sy->sz; shy.sh_type = SHT_SYMTAB; shy.sh_flags = 0; shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1, EV_CURRENT); /* * According to SYSV abi, here sh_info is one greater than * the symbol table index of the last local symbol(binding * STB_LOCAL). */ shy.sh_info = sy_buf->nls; sht.sh_addr = 0; sht.sh_addralign = 1; sht.sh_size = st->sz; sht.sh_type = SHT_STRTAB; sht.sh_flags = 0; sht.sh_entsize = 0; sht.sh_info = 0; sht.sh_link = 0; if (!gelf_update_shdr(sy->os, ­)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); if (!gelf_update_shdr(st->os, &sht)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); } void add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname, unsigned int op) { struct symop *s; if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) { if ((s = calloc(1, sizeof(*s))) == NULL) errx(EXIT_FAILURE, "not enough memory"); s->name = name; if (op == SYMOP_REDEF) s->newname = newname; } s->op |= op; STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list); } static int match_wildcard(const char *name, const char *pattern) { int reverse, match; reverse = 0; if (*pattern == '!') { reverse = 1; pattern++; } match = 0; if (!fnmatch(pattern, name, 0)) { match = 1; printf("string '%s' match to pattern '%s'\n", name, pattern); } return (reverse ? !match : match); } struct symop * lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op) { struct symop *s; STAILQ_FOREACH(s, &ecp->v_symop, symop_list) { if (name == NULL || !strcmp(name, s->name) || ((ecp->flags & WILDCARD) && match_wildcard(name, s->name))) if ((s->op & op) != 0) return (s); } return (NULL); } static int lookup_exact_string(const char *buf, size_t sz, const char *s) { const char *b; size_t slen; slen = strlen(s); for (b = buf; b < buf + sz; b += strlen(b) + 1) { if (strlen(b) != slen) continue; if (!strcmp(b, s)) return (b - buf); } return (-1); } diff --git a/libdwarf/Makefile b/libdwarf/Makefile index 81b5657a2f72..d0a5443e6fb9 100644 --- a/libdwarf/Makefile +++ b/libdwarf/Makefile @@ -1,324 +1,337 @@ -# $Id: Makefile 2937 2013-04-27 04:48:23Z jkoshy $ +# $Id: Makefile 3097 2014-09-02 22:10:18Z kaiwang27 $ TOP= ${.CURDIR}/.. LIB= dwarf SRCS= \ dwarf_abbrev.c \ dwarf_arange.c \ dwarf_attr.c \ dwarf_attrval.c \ dwarf_cu.c \ dwarf_dealloc.c \ dwarf_die.c \ dwarf_dump.c \ dwarf_errmsg.c \ dwarf_finish.c \ dwarf_form.c \ dwarf_frame.c \ dwarf_funcs.c \ dwarf_init.c \ dwarf_lineno.c \ dwarf_loclist.c \ dwarf_macinfo.c \ dwarf_pro_arange.c \ dwarf_pro_attr.c \ dwarf_pro_die.c \ dwarf_pro_expr.c \ dwarf_pro_finish.c \ dwarf_pro_frame.c \ dwarf_pro_funcs.c \ dwarf_pro_init.c \ dwarf_pro_lineno.c \ dwarf_pro_macinfo.c \ dwarf_pro_pubnames.c \ dwarf_pro_reloc.c \ dwarf_pro_sections.c \ dwarf_pro_types.c \ dwarf_pro_vars.c \ dwarf_pro_weaks.c \ dwarf_pubnames.c \ dwarf_pubtypes.c \ dwarf_ranges.c \ dwarf_reloc.c \ + dwarf_sections.c \ dwarf_seterror.c \ dwarf_str.c \ dwarf_types.c \ dwarf_vars.c \ dwarf_weaks.c \ libdwarf.c \ libdwarf_abbrev.c \ libdwarf_arange.c \ libdwarf_attr.c \ libdwarf_die.c \ libdwarf_error.c \ libdwarf_elf_access.c \ libdwarf_elf_init.c \ libdwarf_frame.c \ libdwarf_info.c \ libdwarf_init.c \ libdwarf_lineno.c \ libdwarf_loc.c \ libdwarf_loclist.c \ libdwarf_macinfo.c \ libdwarf_nametbl.c \ libdwarf_ranges.c \ libdwarf_reloc.c \ libdwarf_rw.c \ libdwarf_sections.c \ libdwarf_str.c INCS= dwarf.h libdwarf.h INCSDIR= /usr/include GENSRCS= dwarf_pubnames.c dwarf_pubtypes.c dwarf_weaks.c \ dwarf_funcs.c dwarf_vars.c dwarf_types.c \ dwarf_pro_pubnames.c dwarf_pro_weaks.c \ dwarf_pro_funcs.c dwarf_pro_types.c \ dwarf_pro_vars.c CLEANFILES= ${GENSRCS} SHLIB_MAJOR= 3 WARNS?= 6 LDADD+= -lelf MAN= dwarf.3 \ dwarf_add_arange.3 \ dwarf_add_AT_comp_dir.3 \ dwarf_add_AT_const_value_string.3 \ dwarf_add_AT_dataref.3 \ dwarf_add_AT_flag.3 \ dwarf_add_AT_location_expr.3 \ dwarf_add_AT_name.3 \ dwarf_add_AT_producer.3 \ dwarf_add_AT_ref_address.3 \ dwarf_add_AT_reference.3 \ dwarf_add_AT_signed_const.3 \ dwarf_add_AT_string.3 \ dwarf_add_AT_targ_address.3 \ dwarf_add_die_to_debug.3 \ dwarf_add_directory_decl.3 \ dwarf_add_expr_addr.3 \ dwarf_add_expr_gen.3 \ dwarf_add_fde_inst.3 \ dwarf_add_file_decl.3 \ dwarf_add_frame_cie.3 \ dwarf_add_frame_fde.3 \ dwarf_add_funcname.3 \ dwarf_add_line_entry.3 \ dwarf_add_pubname.3 \ dwarf_add_typename.3 \ dwarf_add_varname.3 \ dwarf_add_weakname.3 \ dwarf_attr.3 \ dwarf_attrlist.3 \ + dwarf_attroffset.3 \ dwarf_attrval_signed.3 \ dwarf_child.3 \ dwarf_dealloc.3 \ dwarf_def_macro.3 \ dwarf_die_abbrev_code.3 \ dwarf_die_link.3 \ dwarf_diename.3 \ dwarf_dieoffset.3 \ dwarf_end_macro_file.3 \ dwarf_errmsg.3 \ dwarf_errno.3 \ dwarf_expand_frame_instructions.3 \ dwarf_expr_current_offset.3 \ dwarf_expr_into_block.3 \ dwarf_fde_cfa_offset.3 \ dwarf_find_macro_value_start.3 \ dwarf_finish.3 \ dwarf_formaddr.3 \ dwarf_formblock.3 \ dwarf_formexprloc.3 \ dwarf_formflag.3 \ dwarf_formref.3 \ dwarf_formsig8.3 \ dwarf_formstring.3 \ dwarf_formudata.3 \ dwarf_get_abbrev.3 \ dwarf_get_abbrev_children_flag.3 \ dwarf_get_abbrev_code.3 \ dwarf_get_abbrev_entry.3 \ dwarf_get_abbrev_tag.3 \ dwarf_get_address_size.3 \ dwarf_get_arange.3 \ dwarf_get_arange_info.3 \ dwarf_get_aranges.3 \ dwarf_get_AT_name.3 \ dwarf_get_cie_index.3 \ dwarf_get_cie_info.3 \ dwarf_get_cie_of_fde.3 \ dwarf_get_cu_die_offset.3 \ + dwarf_get_die_infotypes_flag.3 \ dwarf_get_elf.3 \ dwarf_get_fde_at_pc.3 \ dwarf_get_fde_info_for_all_regs.3 \ dwarf_get_fde_info_for_all_regs3.3 \ dwarf_get_fde_info_for_cfa_reg3.3 \ dwarf_get_fde_info_for_reg.3 \ dwarf_get_fde_info_for_reg3.3 \ dwarf_get_fde_instr_bytes.3 \ dwarf_get_fde_list.3 \ dwarf_get_fde_n.3 \ dwarf_get_fde_range.3 \ dwarf_get_form_class.3 \ dwarf_get_funcs.3 \ dwarf_get_globals.3 \ dwarf_get_loclist_entry.3 \ dwarf_get_macro_details.3 \ dwarf_get_pubtypes.3 \ dwarf_get_ranges.3 \ dwarf_get_relocation_info.3 \ dwarf_get_relocation_info_count.3 \ dwarf_get_section_bytes.3 \ + dwarf_get_section_max_offsets.3 \ dwarf_get_str.3 \ dwarf_get_types.3 \ dwarf_get_vars.3 \ dwarf_get_weaks.3 \ dwarf_hasattr.3 \ dwarf_hasform.3 \ dwarf_highpc.3 \ dwarf_init.3 \ dwarf_lineno.3 \ dwarf_lne_end_sequence.3 \ dwarf_lne_set_address.3 \ dwarf_loclist.3 \ dwarf_loclist_from_expr.3 \ dwarf_new_die.3 \ dwarf_new_expr.3 \ dwarf_new_fde.3 \ dwarf_next_cu_header.3 \ + dwarf_next_types_section.3 \ dwarf_object_init.3 \ dwarf_producer_init.3 \ dwarf_producer_set_isa.3 \ dwarf_reset_section_bytes.3 \ dwarf_seterrarg.3 \ dwarf_set_frame_cfa_value.3 \ dwarf_set_reloc_application.3 \ dwarf_srcfiles.3 \ dwarf_srclines.3 \ dwarf_start_macro_file.3 \ dwarf_tag.3 \ dwarf_transform_to_disk_form.3 \ dwarf_undef_macro.3 \ dwarf_vendor_ext.3 \ dwarf_whatattr.3 MLINKS+= \ dwarf_add_AT_const_value_string.3 dwarf_add_AT_const_value_signedint.3 \ dwarf_add_AT_const_value_string.3 dwarf_add_AT_const_value_unsignedint.3 \ dwarf_add_AT_signed_const.3 dwarf_add_AT_unsigned_const.3 \ dwarf_add_AT_targ_address.3 dwarf_add_AT_targ_address_b.3 \ dwarf_add_arange.3 dwarf_add_arange_b.3 \ dwarf_add_expr_addr.3 dwarf_add_expr_addr_b.3 \ dwarf_add_frame_fde.3 dwarf_add_frame_fde_b.3 \ dwarf_attrval_signed.3 dwarf_attrval_flag.3 \ dwarf_attrval_signed.3 dwarf_attrval_string.3 \ dwarf_attrval_signed.3 dwarf_attrval_unsigned.3 \ dwarf_child.3 dwarf_offdie.3 \ + dwarf_child.3 dwarf_offdie_b.3 \ dwarf_child.3 dwarf_siblingof.3 \ + dwarf_child.3 dwarf_siblingof_b.3 \ dwarf_dealloc.3 dwarf_fde_cie_list_dealloc.3 \ dwarf_dealloc.3 dwarf_funcs_dealloc.3 \ dwarf_dealloc.3 dwarf_globals_dealloc.3 \ dwarf_dealloc.3 dwarf_pubtypes_dealloc.3 \ dwarf_dealloc.3 dwarf_types_dealloc.3 \ dwarf_dealloc.3 dwarf_vars_dealloc.3 \ dwarf_dealloc.3 dwarf_weaks_dealloc.3 \ dwarf_dealloc.3 dwarf_ranges_dealloc.3 \ dwarf_dealloc.3 dwarf_srclines_dealloc.3 \ dwarf_init.3 dwarf_elf_init.3 \ dwarf_dieoffset.3 dwarf_die_CU_offset.3 \ dwarf_dieoffset.3 dwarf_die_CU_offset_range.3 \ dwarf_dieoffset.3 dwarf_get_cu_die_offset_given_cu_header_offset.3 \ + dwarf_dieoffset.3 dwarf_get_cu_die_offset_given_cu_header_offset_b.3 \ dwarf_finish.3 dwarf_object_finish.3 \ dwarf_formref.3 dwarf_global_formref.3 \ dwarf_formudata.3 dwarf_formsdata.3 \ dwarf_get_AT_name.3 dwarf_get_ACCESS_name.3 \ dwarf_get_AT_name.3 dwarf_get_ATE_name.3 \ dwarf_get_AT_name.3 dwarf_get_CC_name.3 \ dwarf_get_AT_name.3 dwarf_get_CFA_name.3 \ dwarf_get_AT_name.3 dwarf_get_CHILDREN_name.3 \ dwarf_get_AT_name.3 dwarf_get_DS_name.3 \ dwarf_get_AT_name.3 dwarf_get_DSC_name.3 \ dwarf_get_AT_name.3 dwarf_get_EH_name.3 \ dwarf_get_AT_name.3 dwarf_get_END_name.3 \ dwarf_get_AT_name.3 dwarf_get_FORM_name.3 \ dwarf_get_AT_name.3 dwarf_get_ID_name.3 \ dwarf_get_AT_name.3 dwarf_get_INL_name.3 \ dwarf_get_AT_name.3 dwarf_get_LANG_name.3 \ dwarf_get_AT_name.3 dwarf_get_LNE_name.3 \ dwarf_get_AT_name.3 dwarf_get_LNS_name.3 \ dwarf_get_AT_name.3 dwarf_get_MACINFO_name.3 \ dwarf_get_AT_name.3 dwarf_get_OP_name.3 \ dwarf_get_AT_name.3 dwarf_get_ORD_name.3 \ dwarf_get_AT_name.3 dwarf_get_TAG_name.3 \ dwarf_get_AT_name.3 dwarf_get_VIRTUALITY_name.3 \ dwarf_get_AT_name.3 dwarf_get_VIS_name.3 \ dwarf_get_cu_die_offset.3 dwarf_get_arange_cu_header_offset.3 \ dwarf_get_fde_list.3 dwarf_get_fde_list_eh.3 \ dwarf_get_funcs.3 dwarf_func_die_offset.3 \ dwarf_get_funcs.3 dwarf_func_cu_offset.3 \ dwarf_get_funcs.3 dwarf_func_name_offsets.3 \ dwarf_get_funcs.3 dwarf_funcname.3 \ dwarf_get_globals.3 dwarf_global_die_offset.3 \ dwarf_get_globals.3 dwarf_global_cu_offset.3 \ dwarf_get_globals.3 dwarf_global_name_offsets.3 \ dwarf_get_globals.3 dwarf_globname.3 \ dwarf_get_pubtypes.3 dwarf_pubtype_die_offset.3 \ dwarf_get_pubtypes.3 dwarf_pubtype_cu_offset.3 \ dwarf_get_pubtypes.3 dwarf_pubtype_name_offsets.3 \ dwarf_get_pubtypes.3 dwarf_pubtypename.3 \ dwarf_get_ranges.3 dwarf_get_ranges_a.3 \ + dwarf_get_section_max_offsets.3 dwarf_get_section_max_offsets_b.3 \ dwarf_get_types.3 dwarf_type_die_offset.3 \ dwarf_get_types.3 dwarf_type_cu_offset.3 \ dwarf_get_types.3 dwarf_type_name_offsets.3 \ dwarf_get_types.3 dwarf_typename.3 \ dwarf_get_vars.3 dwarf_var_die_offset.3 \ dwarf_get_vars.3 dwarf_var_cu_offset.3 \ dwarf_get_vars.3 dwarf_var_name_offsets.3 \ dwarf_get_vars.3 dwarf_varname.3 \ dwarf_get_weaks.3 dwarf_weak_die_offset.3 \ dwarf_get_weaks.3 dwarf_weak_cu_offset.3 \ dwarf_get_weaks.3 dwarf_weak_name_offsets.3 \ dwarf_get_weaks.3 dwarf_weakname.3 \ dwarf_hasform.3 dwarf_whatform.3 \ dwarf_hasform.3 dwarf_whatform_direct.3 \ dwarf_highpc.3 dwarf_arrayorder.3 \ dwarf_highpc.3 dwarf_bitoffset.3 \ dwarf_highpc.3 dwarf_bitsize.3 \ dwarf_highpc.3 dwarf_bytesize.3 \ + dwarf_highpc.3 dwarf_highpc_b.3 \ dwarf_highpc.3 dwarf_lowpc.3 \ dwarf_highpc.3 dwarf_srclang.3 \ dwarf_lineno.3 dwarf_lineaddr.3 \ dwarf_lineno.3 dwarf_linebeginstatement.3 \ dwarf_lineno.3 dwarf_lineblock.3 \ dwarf_lineno.3 dwarf_lineendsequence.3 \ dwarf_lineno.3 dwarf_lineoff.3 \ dwarf_lineno.3 dwarf_linesrc.3 \ dwarf_lineno.3 dwarf_line_srcfileno.3 \ dwarf_loclist.3 dwarf_loclist_n.3 \ dwarf_loclist_from_expr.3 dwarf_loclist_from_expr_a.3 \ + dwarf_loclist_from_expr.3 dwarf_loclist_from_expr_b.3 \ + dwarf_next_cu_header.3 dwarf_next_cu_header_b.3 \ + dwarf_next_cu_header.3 dwarf_next_cu_header_c.3 \ dwarf_producer_init.3 dwarf_producer_init_b.3 \ dwarf_seterrarg.3 dwarf_seterrhand.3 \ dwarf_set_frame_cfa_value.3 dwarf_set_frame_rule_initial_value.3 \ dwarf_set_frame_cfa_value.3 dwarf_set_frame_rule_table_size.3 \ dwarf_set_frame_cfa_value.3 dwarf_set_frame_same_value.3 \ dwarf_set_frame_cfa_value.3 dwarf_set_frame_undefined_value.3 dwarf_pubnames.c: dwarf_nametbl.m4 dwarf_pubnames.m4 dwarf_pubtypes.c: dwarf_nametbl.m4 dwarf_pubtypes.m4 dwarf_weaks.c: dwarf_nametbl.m4 dwarf_weaks.m4 dwarf_funcs.c: dwarf_nametbl.m4 dwarf_funcs.m4 dwarf_vars.c: dwarf_nametbl.m4 dwarf_vars.m4 dwarf_types.c: dwarf_nametbl.m4 dwarf_types.m4 dwarf_pro_pubnames.c: dwarf_pro_nametbl.m4 dwarf_pro_pubnames.m4 dwarf_pro_weaks.c: dwarf_pro_nametbl.m4 dwarf_pro_weaks.m4 dwarf_pro_funcs.c: dwarf_pro_nametbl.m4 dwarf_pro_funcs.m4 dwarf_pro_types.c: dwarf_pro_nametbl.m4 dwarf_pro_types.m4 dwarf_pro_vars.c: dwarf_pro_nametbl.m4 dwarf_pro_vars.m4 .include "${TOP}/mk/elftoolchain.lib.mk" diff --git a/libdwarf/Version.map b/libdwarf/Version.map index 6e6548bd9732..669f70e44dac 100644 --- a/libdwarf/Version.map +++ b/libdwarf/Version.map @@ -1,228 +1,239 @@ -/* $Id: Version.map 2576 2012-09-13 09:16:11Z jkoshy $ */ +/* $Id: Version.map 3085 2014-09-02 22:08:23Z kaiwang27 $ */ R1.0 { global: dwarf_add_AT_comp_dir; dwarf_add_AT_const_value_signedint; dwarf_add_AT_const_value_string; dwarf_add_AT_const_value_unsignedint; dwarf_add_AT_dataref; dwarf_add_AT_flag; dwarf_add_AT_location_expr; dwarf_add_AT_name; dwarf_add_AT_producer; dwarf_add_AT_ref_address; dwarf_add_AT_reference; dwarf_add_AT_signed_const; dwarf_add_AT_string; dwarf_add_AT_targ_address; dwarf_add_AT_targ_address_b; dwarf_add_AT_unsigned_const; dwarf_add_arange; dwarf_add_arange_b; dwarf_add_die_to_debug; dwarf_add_directory_decl; dwarf_add_expr_addr; dwarf_add_expr_addr_b; dwarf_add_expr_gen; dwarf_add_fde_inst; dwarf_add_file_decl; dwarf_add_frame_cie; dwarf_add_frame_fde; dwarf_add_frame_fde_b; dwarf_add_funcname; dwarf_add_line_entry; dwarf_add_pubname; dwarf_add_typename; dwarf_add_varname; dwarf_add_weakname; dwarf_arrayorder; dwarf_attr; dwarf_attrlist; + dwarf_attroffset; dwarf_attrval_flag; dwarf_attrval_signed; dwarf_attrval_string; dwarf_attrval_unsigned; dwarf_bitoffset; dwarf_bitsize; dwarf_bytesize; dwarf_child; dwarf_dealloc; dwarf_def_macro; dwarf_die_CU_offset; dwarf_die_CU_offset_range; dwarf_die_abbrev_code; dwarf_die_link; dwarf_diename; dwarf_dieoffset; dwarf_elf_init; dwarf_end_macro_file; dwarf_errmsg_; dwarf_expand_frame_instructions; dwarf_expr_current_offset; dwarf_expr_into_block; dwarf_fde_cfa_offset; dwarf_fde_cie_list_dealloc; dwarf_find_macro_value_start; dwarf_finish; dwarf_formaddr; dwarf_formblock; dwarf_formexprloc; dwarf_formflag; dwarf_formref; dwarf_formsdata; dwarf_formsig8; dwarf_formstring; dwarf_formudata; dwarf_func_cu_offset; dwarf_func_die_offset; dwarf_func_name_offsets; dwarf_funcname; dwarf_funcs_dealloc; dwarf_get_ACCESS_name; dwarf_get_ATE_name; dwarf_get_AT_name; dwarf_get_CC_name; dwarf_get_CFA_name; dwarf_get_CHILDREN_name; dwarf_get_DSC_name; dwarf_get_DS_name; dwarf_get_EH_name; dwarf_get_END_name; dwarf_get_FORM_name; dwarf_get_ID_name; dwarf_get_INL_name; dwarf_get_LANG_name; dwarf_get_LNE_name; dwarf_get_LNS_name; dwarf_get_MACINFO_name; dwarf_get_OP_name; dwarf_get_ORD_name; dwarf_get_TAG_name; dwarf_get_VIRTUALITY_name; dwarf_get_VIS_name; dwarf_get_abbrev; dwarf_get_abbrev_children_flag; dwarf_get_abbrev_code; dwarf_get_abbrev_entry; dwarf_get_abbrev_tag; dwarf_get_address_size; dwarf_get_arange; dwarf_get_arange_cu_header_offset; dwarf_get_arange_info; dwarf_get_aranges; dwarf_get_cie_index; dwarf_get_cie_info; dwarf_get_cie_of_fde; dwarf_get_cu_die_offset; dwarf_get_cu_die_offset_given_cu_header_offset; + dwarf_get_cu_die_offset_given_cu_header_offset_b; + dwarf_get_die_infotypes_flag; dwarf_get_elf; dwarf_get_fde_at_pc; dwarf_get_fde_info_for_all_regs3; dwarf_get_fde_info_for_all_regs; dwarf_get_fde_info_for_cfa_reg3; dwarf_get_fde_info_for_reg3; dwarf_get_fde_info_for_reg; dwarf_get_fde_instr_bytes; dwarf_get_fde_list; dwarf_get_fde_list_eh; dwarf_get_fde_n; dwarf_get_fde_range; dwarf_get_form_class; dwarf_get_funcs; dwarf_get_globals; dwarf_get_loclist_entry; dwarf_get_macro_details; dwarf_get_pubtypes; dwarf_get_ranges; dwarf_get_ranges_a; dwarf_get_relocation_info; dwarf_get_relocation_info_count; dwarf_get_section_bytes; + dwarf_get_section_max_offsets; + dwarf_get_section_max_offsets_b; dwarf_get_str; dwarf_get_types; dwarf_get_vars; dwarf_get_weaks; dwarf_global_cu_offset; dwarf_global_die_offset; dwarf_global_formref; dwarf_global_name_offsets; dwarf_globals_dealloc; dwarf_globname; dwarf_hasattr; dwarf_hasform; dwarf_highpc; + dwarf_highpc_b; dwarf_init; dwarf_line_srcfileno; dwarf_lineaddr; dwarf_linebeginstatement; dwarf_lineblock; dwarf_lineendsequence; dwarf_lineno; dwarf_lineoff; dwarf_linesrc; dwarf_lne_end_sequence; dwarf_lne_set_address; dwarf_loclist; dwarf_loclist_from_expr; dwarf_loclist_from_expr_a; + dwarf_loclist_from_expr_b; dwarf_loclist_n; dwarf_lowpc; dwarf_new_die; dwarf_new_expr; dwarf_new_fde; dwarf_next_cu_header; dwarf_next_cu_header_b; + dwarf_next_cu_header_c; + dwarf_next_types_section; dwarf_object_finish; dwarf_object_init; dwarf_offdie; + dwarf_offdie_b; dwarf_producer_finish; dwarf_producer_init; dwarf_producer_init_b; dwarf_producer_set_isa; dwarf_pubtype_cu_offset; dwarf_pubtype_die_offset; dwarf_pubtype_name_offsets; dwarf_pubtypename; dwarf_pubtypes_dealloc; dwarf_ranges_dealloc; dwarf_reset_section_bytes; dwarf_set_frame_cfa_value; dwarf_set_frame_rule_initial_value; dwarf_set_frame_rule_table_size; dwarf_set_frame_same_value; dwarf_set_frame_undefined_value; dwarf_set_reloc_application; dwarf_seterrarg; dwarf_seterrhand; dwarf_siblingof; + dwarf_siblingof_b; dwarf_srcfiles; dwarf_srclang; dwarf_srclines; dwarf_srclines_dealloc; dwarf_start_macro_file; dwarf_tag; dwarf_transform_to_disk_form; dwarf_type_cu_offset; dwarf_type_die_offset; dwarf_type_name_offsets; dwarf_typename; dwarf_types_dealloc; dwarf_undef_macro; dwarf_var_cu_offset; dwarf_var_die_offset; dwarf_var_name_offsets; dwarf_varname; dwarf_vars_dealloc; dwarf_vendor_ext; dwarf_weak_cu_offset; dwarf_weak_die_offset; dwarf_weak_name_offsets; dwarf_weakname; dwarf_weaks_dealloc; dwarf_whatattr; dwarf_whatform; dwarf_whatform_direct; local: *; }; diff --git a/libdwarf/_libdwarf.h b/libdwarf/_libdwarf.h index 23f60e8ee267..d2e74c15687a 100644 --- a/libdwarf/_libdwarf.h +++ b/libdwarf/_libdwarf.h @@ -1,658 +1,665 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) - * Copyright (c) 2009-2011 Kai Wang + * Copyright (c) 2009-2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: _libdwarf.h 2075 2011-10-27 03:47:28Z jkoshy $ + * $Id: _libdwarf.h 3106 2014-12-19 16:00:58Z kaiwang27 $ */ #ifndef __LIBDWARF_H_ #define __LIBDWARF_H_ #include #include #include #include #include #include #include #include #include "dwarf.h" #include "libdwarf.h" #include "uthash.h" #include "_elftc.h" #define DWARF_DIE_HASH_SIZE 8191 struct _libdwarf_globals { Dwarf_Handler errhand; Dwarf_Ptr errarg; int applyrela; }; extern struct _libdwarf_globals _libdwarf; #define _DWARF_SET_ERROR(_d, _e, _err, _elf_err) \ _dwarf_set_error(_d, _e, _err, _elf_err, __func__, __LINE__) #define DWARF_SET_ERROR(_d, _e, _err) \ _DWARF_SET_ERROR(_d, _e, _err, 0) #define DWARF_SET_ELF_ERROR(_d, _e) \ _DWARF_SET_ERROR(_d, _e, DW_DLE_ELF, elf_errno()) /* * Convenient macros for producer bytes stream generation. */ #define WRITE_VALUE(value, bytes) \ dbg->write_alloc(&ds->ds_data, &ds->ds_cap, &ds->ds_size, \ (value), (bytes), error) #define WRITE_ULEB128(value) \ _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap, \ &ds->ds_size, (value), error) #define WRITE_SLEB128(value) \ _dwarf_write_sleb128_alloc(&ds->ds_data, &ds->ds_cap, \ &ds->ds_size, (value), error) #define WRITE_STRING(string) \ _dwarf_write_string_alloc(&ds->ds_data, &ds->ds_cap, \ &ds->ds_size, (string), error) #define WRITE_BLOCK(blk, size) \ _dwarf_write_block_alloc(&ds->ds_data, &ds->ds_cap, \ &ds->ds_size, (blk), (size), error) #define WRITE_PADDING(byte, cnt) \ _dwarf_write_padding_alloc(&ds->ds_data, &ds->ds_cap, \ &ds->ds_size, (byte), (cnt), error) #define RCHECK(expr) \ do { \ ret = expr; \ if (ret != DW_DLE_NONE) \ goto gen_fail; \ } while(0) +typedef struct _Dwarf_CU *Dwarf_CU; struct _Dwarf_AttrDef { uint64_t ad_attrib; /* DW_AT_XXX */ uint64_t ad_form; /* DW_FORM_XXX */ uint64_t ad_offset; /* Offset in abbrev section. */ STAILQ_ENTRY(_Dwarf_AttrDef) ad_next; /* Next attribute define. */ }; struct _Dwarf_Attribute { Dwarf_Die at_die; /* Ptr to containing DIE. */ Dwarf_Die at_refdie; /* Ptr to reference DIE. */ uint64_t at_offset; /* Offset in info section. */ uint64_t at_attrib; /* DW_AT_XXX */ uint64_t at_form; /* DW_FORM_XXX */ int at_indirect; /* Has indirect form. */ union { uint64_t u64; /* Unsigned value. */ int64_t s64; /* Signed value. */ char *s; /* String. */ uint8_t *u8p; /* Block data. */ } u[2]; /* Value. */ Dwarf_Block at_block; /* Block. */ Dwarf_Locdesc *at_ld; /* at value is locdesc. */ Dwarf_P_Expr at_expr; /* at value is expr. */ uint64_t at_relsym; /* Relocation symbol index. */ const char *at_relsec; /* Rel. to dwarf section. */ STAILQ_ENTRY(_Dwarf_Attribute) at_next; /* Next attribute. */ }; struct _Dwarf_Abbrev { uint64_t ab_entry; /* Abbrev entry. */ uint64_t ab_tag; /* Tag: DW_TAG_ */ uint8_t ab_children; /* DW_CHILDREN_no or DW_CHILDREN_yes */ uint64_t ab_offset; /* Offset in abbrev section. */ uint64_t ab_length; /* Length of this abbrev entry. */ uint64_t ab_atnum; /* Number of attribute defines. */ UT_hash_handle ab_hh; /* Uthash handle. */ STAILQ_HEAD(, _Dwarf_AttrDef) ab_attrdef; /* List of attribute defs. */ }; struct _Dwarf_Die { Dwarf_Die die_parent; /* Parent DIE. */ Dwarf_Die die_child; /* First child DIE. */ Dwarf_Die die_left; /* Left sibling DIE. */ Dwarf_Die die_right; /* Right sibling DIE. */ uint64_t die_offset; /* DIE offset in section. */ uint64_t die_next_off; /* Next DIE offset in section. */ uint64_t die_abnum; /* Abbrev number. */ Dwarf_Abbrev die_ab; /* Abbrev pointer. */ Dwarf_Tag die_tag; /* DW_TAG_ */ Dwarf_Debug die_dbg; /* Dwarf_Debug pointer. */ Dwarf_CU die_cu; /* Compilation unit pointer. */ char *die_name; /* Ptr to the name string. */ Dwarf_Attribute *die_attrarray; /* Array of attributes. */ STAILQ_HEAD(, _Dwarf_Attribute) die_attr; /* List of attributes. */ STAILQ_ENTRY(_Dwarf_Die) die_pro_next; /* Next die in pro-die list. */ }; -struct _Dwarf_Loclist { - Dwarf_Locdesc **ll_ldlist; /* Array of Locdesc pointer. */ - int ll_ldlen; /* Number of Locdesc. */ - Dwarf_Unsigned ll_offset; /* Offset in .debug_loc section. */ - Dwarf_Unsigned ll_length; /* Length (in bytes) of the loclist. */ - TAILQ_ENTRY(_Dwarf_Loclist) ll_next; /* Next loclist in list. */ -}; - struct _Dwarf_P_Expr_Entry { Dwarf_Loc ee_loc; /* Location expression. */ Dwarf_Unsigned ee_sym; /* Optional related reloc sym index. */ STAILQ_ENTRY(_Dwarf_P_Expr_Entry) ee_next; /* Next entry in list. */ }; struct _Dwarf_P_Expr { Dwarf_Debug pe_dbg; /* Dwarf_Debug pointer. */ uint8_t *pe_block; /* Expression block data. */ int pe_invalid; /* Block data is up-to-date or not. */ Dwarf_Unsigned pe_length; /* Length of the block. */ STAILQ_HEAD(, _Dwarf_P_Expr_Entry) pe_eelist; /* List of entries. */ STAILQ_ENTRY(_Dwarf_P_Expr) pe_next; /* Next expr in list. */ }; struct _Dwarf_Line { Dwarf_LineInfo ln_li; /* Ptr to line info. */ Dwarf_Addr ln_addr; /* Line address. */ Dwarf_Unsigned ln_symndx; /* Symbol index for relocation. */ Dwarf_Unsigned ln_fileno; /* File number. */ Dwarf_Unsigned ln_lineno; /* Line number. */ Dwarf_Signed ln_column; /* Column number. */ Dwarf_Bool ln_bblock; /* Basic block flag. */ Dwarf_Bool ln_stmt; /* Begin statement flag. */ Dwarf_Bool ln_endseq; /* End sequence flag. */ STAILQ_ENTRY(_Dwarf_Line) ln_next; /* Next line in list. */ }; struct _Dwarf_LineFile { char *lf_fname; /* Filename. */ char *lf_fullpath; /* Full pathname of the file. */ Dwarf_Unsigned lf_dirndx; /* Dir index. */ Dwarf_Unsigned lf_mtime; /* Modification time. */ Dwarf_Unsigned lf_size; /* File size. */ STAILQ_ENTRY(_Dwarf_LineFile) lf_next; /* Next file in list. */ }; struct _Dwarf_LineInfo { Dwarf_Unsigned li_length; /* Length of line info data. */ Dwarf_Half li_version; /* Version of line info. */ Dwarf_Unsigned li_hdrlen; /* Length of line info header. */ Dwarf_Small li_minlen; /* Minimum instrutction length. */ Dwarf_Small li_defstmt; /* Default value of is_stmt. */ int8_t li_lbase; /* Line base for special opcode. */ Dwarf_Small li_lrange; /* Line range for special opcode. */ Dwarf_Small li_opbase; /* Fisrt std opcode number. */ Dwarf_Small *li_oplen; /* Array of std opcode len. */ char **li_incdirs; /* Array of include dirs. */ Dwarf_Unsigned li_inclen; /* Length of inc dir array. */ char **li_lfnarray; /* Array of file names. */ Dwarf_Unsigned li_lflen; /* Length of filename array. */ STAILQ_HEAD(, _Dwarf_LineFile) li_lflist; /* List of files. */ Dwarf_Line *li_lnarray; /* Array of lines. */ Dwarf_Unsigned li_lnlen; /* Length of the line array. */ STAILQ_HEAD(, _Dwarf_Line) li_lnlist; /* List of lines. */ }; struct _Dwarf_NamePair { Dwarf_NameTbl np_nt; /* Ptr to containing name table. */ Dwarf_Die np_die; /* Ptr to Ref. Die. */ Dwarf_Unsigned np_offset; /* Offset in CU. */ char *np_name; /* Object/Type name. */ STAILQ_ENTRY(_Dwarf_NamePair) np_next; /* Next pair in the list. */ }; struct _Dwarf_NameTbl { Dwarf_Unsigned nt_length; /* Name lookup table length. */ Dwarf_Half nt_version; /* Name lookup table version. */ Dwarf_CU nt_cu; /* Ptr to Ref. CU. */ Dwarf_Off nt_cu_offset; /* Ref. CU offset in .debug_info */ Dwarf_Unsigned nt_cu_length; /* Ref. CU length. */ STAILQ_HEAD(, _Dwarf_NamePair) nt_nplist; /* List of offset+name pairs. */ STAILQ_ENTRY(_Dwarf_NameTbl) nt_next; /* Next name table in the list. */ }; struct _Dwarf_NameSec { STAILQ_HEAD(, _Dwarf_NameTbl) ns_ntlist; /* List of name tables. */ Dwarf_NamePair *ns_array; /* Array of pairs of all tables. */ Dwarf_Unsigned ns_len; /* Length of the pair array. */ }; struct _Dwarf_Fde { Dwarf_Debug fde_dbg; /* Ptr to containing dbg. */ Dwarf_Cie fde_cie; /* Ptr to associated CIE. */ Dwarf_FrameSec fde_fs; /* Ptr to containing .debug_frame. */ Dwarf_Ptr fde_addr; /* Ptr to start of the FDE. */ Dwarf_Unsigned fde_offset; /* Offset of the FDE. */ Dwarf_Unsigned fde_length; /* Length of the FDE. */ Dwarf_Unsigned fde_cieoff; /* Offset of associated CIE. */ Dwarf_Unsigned fde_initloc; /* Initial location. */ Dwarf_Unsigned fde_adrange; /* Address range. */ Dwarf_Unsigned fde_auglen; /* Augmentation length. */ uint8_t *fde_augdata; /* Augmentation data. */ uint8_t *fde_inst; /* Instructions. */ Dwarf_Unsigned fde_instlen; /* Length of instructions. */ Dwarf_Unsigned fde_instcap; /* Capacity of inst buffer. */ Dwarf_Unsigned fde_symndx; /* Symbol index for relocation. */ Dwarf_Unsigned fde_esymndx; /* End symbol index for relocation. */ Dwarf_Addr fde_eoff; /* Offset from the end symbol. */ STAILQ_ENTRY(_Dwarf_Fde) fde_next; /* Next FDE in list. */ }; struct _Dwarf_Cie { Dwarf_Debug cie_dbg; /* Ptr to containing dbg. */ Dwarf_Unsigned cie_index; /* Index of the CIE. */ Dwarf_Unsigned cie_offset; /* Offset of the CIE. */ Dwarf_Unsigned cie_length; /* Length of the CIE. */ Dwarf_Half cie_version; /* CIE version. */ uint8_t *cie_augment; /* CIE augmentation (UTF-8). */ Dwarf_Unsigned cie_ehdata; /* Optional EH Data. */ + uint8_t cie_addrsize; /* Address size. (DWARF4) */ + uint8_t cie_segmentsize; /* Segment size. (DWARF4) */ Dwarf_Unsigned cie_caf; /* Code alignment factor. */ Dwarf_Signed cie_daf; /* Data alignment factor. */ Dwarf_Unsigned cie_ra; /* Return address register. */ Dwarf_Unsigned cie_auglen; /* Augmentation length. */ uint8_t *cie_augdata; /* Augmentation data; */ uint8_t cie_fde_encode; /* FDE PC start/range encode. */ Dwarf_Ptr cie_initinst; /* Initial instructions. */ Dwarf_Unsigned cie_instlen; /* Length of init instructions. */ STAILQ_ENTRY(_Dwarf_Cie) cie_next; /* Next CIE in list. */ }; struct _Dwarf_FrameSec { STAILQ_HEAD(, _Dwarf_Cie) fs_cielist; /* List of CIE. */ STAILQ_HEAD(, _Dwarf_Fde) fs_fdelist; /* List of FDE. */ Dwarf_Cie *fs_ciearray; /* Array of CIE. */ Dwarf_Unsigned fs_cielen; /* Length of CIE array. */ Dwarf_Fde *fs_fdearray; /* Array of FDE.*/ Dwarf_Unsigned fs_fdelen; /* Length of FDE array. */ }; struct _Dwarf_Arange { Dwarf_ArangeSet ar_as; /* Ptr to the set it belongs to. */ Dwarf_Unsigned ar_address; /* Start PC. */ Dwarf_Unsigned ar_range; /* PC range. */ Dwarf_Unsigned ar_symndx; /* First symbol index for reloc. */ Dwarf_Unsigned ar_esymndx; /* Second symbol index for reloc. */ Dwarf_Addr ar_eoff; /* Offset from second symbol. */ STAILQ_ENTRY(_Dwarf_Arange) ar_next; /* Next arange in list. */ }; struct _Dwarf_ArangeSet { Dwarf_Unsigned as_length; /* Length of the arange set. */ Dwarf_Half as_version; /* Version of the arange set. */ Dwarf_Off as_cu_offset; /* Offset of associated CU. */ Dwarf_CU as_cu; /* Ptr to associated CU. */ Dwarf_Small as_addrsz; /* Target address size. */ Dwarf_Small as_segsz; /* Target segment size. */ STAILQ_HEAD (, _Dwarf_Arange) as_arlist; /* List of ae entries. */ STAILQ_ENTRY(_Dwarf_ArangeSet) as_next; /* Next set in list. */ }; struct _Dwarf_MacroSet { Dwarf_Macro_Details *ms_mdlist; /* Array of macinfo entries. */ Dwarf_Unsigned ms_cnt; /* Length of the array. */ STAILQ_ENTRY(_Dwarf_MacroSet) ms_next; /* Next set in list. */ }; struct _Dwarf_Rangelist { Dwarf_CU rl_cu; /* Ptr to associated CU. */ Dwarf_Unsigned rl_offset; /* Offset of the rangelist. */ Dwarf_Ranges *rl_rgarray; /* Array of ranges. */ Dwarf_Unsigned rl_rglen; /* Length of the ranges array. */ STAILQ_ENTRY(_Dwarf_Rangelist) rl_next; /* Next rangelist in list. */ }; struct _Dwarf_CU { Dwarf_Debug cu_dbg; /* Ptr to containing dbg. */ Dwarf_Off cu_offset; /* Offset to the this CU. */ uint32_t cu_length; /* Length of CU data. */ uint16_t cu_length_size; /* Size in bytes of the length field. */ uint16_t cu_version; /* DWARF version. */ uint64_t cu_abbrev_offset; /* Offset into .debug_abbrev. */ uint64_t cu_abbrev_offset_cur; /* Current abbrev offset. */ int cu_abbrev_loaded; /* Abbrev table parsed. */ uint64_t cu_abbrev_cnt; /* Abbrev entry count. */ uint64_t cu_lineno_offset; /* Offset into .debug_lineno. */ uint8_t cu_pointer_size;/* Number of bytes in pointer. */ uint8_t cu_dwarf_size; /* CU section dwarf size. */ + Dwarf_Sig8 cu_type_sig; /* Type unit's signature. */ + uint64_t cu_type_offset; /* Type unit's type offset. */ Dwarf_Off cu_next_offset; /* Offset to the next CU. */ uint64_t cu_1st_offset; /* First DIE offset. */ int cu_pass2; /* Two pass DIE traverse. */ Dwarf_LineInfo cu_lineinfo; /* Ptr to Dwarf_LineInfo. */ Dwarf_Abbrev cu_abbrev_hash; /* Abbrev hash table. */ + Dwarf_Bool cu_is_info; /* Compilation/type unit flag. */ STAILQ_ENTRY(_Dwarf_CU) cu_next; /* Next compilation unit. */ }; typedef struct _Dwarf_Section { const char *ds_name; /* Section name. */ Dwarf_Small *ds_data; /* Section data. */ Dwarf_Unsigned ds_addr; /* Section virtual addr. */ Dwarf_Unsigned ds_size; /* Section size. */ } Dwarf_Section; typedef struct _Dwarf_P_Section { char *ds_name; /* Section name. */ Dwarf_Small *ds_data; /* Section data. */ Dwarf_Unsigned ds_size; /* Section size. */ Dwarf_Unsigned ds_cap; /* Section capacity. */ Dwarf_Unsigned ds_ndx; /* ELF section index. */ Dwarf_Unsigned ds_symndx; /* Section symbol index. (for reloc) */ STAILQ_ENTRY(_Dwarf_P_Section) ds_next; /* Next section in the list. */ } *Dwarf_P_Section; typedef struct _Dwarf_Rel_Entry { unsigned char dre_type; /* Reloc type. */ unsigned char dre_length; /* Reloc storage unit length. */ Dwarf_Unsigned dre_offset; /* Reloc storage unit offset. */ Dwarf_Unsigned dre_addend; /* Reloc addend. */ Dwarf_Unsigned dre_symndx; /* Reloc symbol index. */ const char *dre_secname; /* Refer to some debug section. */ STAILQ_ENTRY(_Dwarf_Rel_Entry) dre_next; /* Next reloc entry. */ } *Dwarf_Rel_Entry; typedef struct _Dwarf_Rel_Section { struct _Dwarf_P_Section *drs_ds; /* Ptr to actual reloc ELF section. */ struct _Dwarf_P_Section *drs_ref; /* Which debug section it refers. */ struct Dwarf_Relocation_Data_s *drs_drd; /* Reloc data array. */ STAILQ_HEAD(, _Dwarf_Rel_Entry) drs_dre; /* Reloc entry list. */ Dwarf_Unsigned drs_drecnt; /* Count of entries. */ Dwarf_Unsigned drs_size; /* Size of ELF section in bytes. */ int drs_addend; /* Elf_Rel or Elf_Rela */ STAILQ_ENTRY(_Dwarf_Rel_Section) drs_next; /* Next reloc section. */ } *Dwarf_Rel_Section; typedef struct { Elf_Data *ed_data; void *ed_alloc; } Dwarf_Elf_Data; typedef struct { Elf *eo_elf; GElf_Ehdr eo_ehdr; GElf_Shdr *eo_shdr; Dwarf_Elf_Data *eo_data; Dwarf_Unsigned eo_seccnt; size_t eo_strndx; Dwarf_Obj_Access_Methods eo_methods; } Dwarf_Elf_Object; struct _Dwarf_Debug { Dwarf_Obj_Access_Interface *dbg_iface; Dwarf_Section *dbg_section; /* Dwarf section list. */ Dwarf_Section *dbg_info_sec; /* Pointer to info section. */ Dwarf_Off dbg_info_off; /* Current info section offset. */ + Dwarf_Section *dbg_types_sec; /* Pointer to type section. */ + Dwarf_Off dbg_types_off; /* Current types section offset. */ Dwarf_Unsigned dbg_seccnt; /* Total number of dwarf sections. */ int dbg_mode; /* Access mode. */ int dbg_pointer_size; /* Object address size. */ int dbg_offset_size; /* DWARF offset size. */ int dbg_info_loaded; /* Flag indicating all CU loaded. */ + int dbg_types_loaded; /* Flag indicating all TU loaded. */ Dwarf_Half dbg_machine; /* ELF machine architecture. */ Dwarf_Handler dbg_errhand; /* Error handler. */ Dwarf_Ptr dbg_errarg; /* Argument to the error handler. */ STAILQ_HEAD(, _Dwarf_CU) dbg_cu;/* List of compilation units. */ + STAILQ_HEAD(, _Dwarf_CU) dbg_tu;/* List of type units. */ Dwarf_CU dbg_cu_current; /* Ptr to the current CU. */ - TAILQ_HEAD(, _Dwarf_Loclist) dbg_loclist; /* List of location list. */ + Dwarf_CU dbg_tu_current; /* Ptr to the current TU. */ Dwarf_NameSec dbg_globals; /* Ptr to pubnames lookup section. */ Dwarf_NameSec dbg_pubtypes; /* Ptr to pubtypes lookup section. */ Dwarf_NameSec dbg_weaks; /* Ptr to weaknames lookup section. */ Dwarf_NameSec dbg_funcs; /* Ptr to static funcs lookup sect. */ Dwarf_NameSec dbg_vars; /* Ptr to static vars lookup sect. */ Dwarf_NameSec dbg_types; /* Ptr to types lookup section. */ Dwarf_FrameSec dbg_frame; /* Ptr to .debug_frame section. */ Dwarf_FrameSec dbg_eh_frame; /* Ptr to .eh_frame section. */ STAILQ_HEAD(, _Dwarf_ArangeSet) dbg_aslist; /* List of arange set. */ Dwarf_Arange *dbg_arange_array; /* Array of arange. */ Dwarf_Unsigned dbg_arange_cnt; /* Length of the arange array. */ char *dbg_strtab; /* Dwarf string table. */ Dwarf_Unsigned dbg_strtab_cap; /* Dwarf string table capacity. */ Dwarf_Unsigned dbg_strtab_size; /* Dwarf string table size. */ STAILQ_HEAD(, _Dwarf_MacroSet) dbg_mslist; /* List of macro set. */ STAILQ_HEAD(, _Dwarf_Rangelist) dbg_rllist; /* List of rangelist. */ uint64_t (*read)(uint8_t *, uint64_t *, int); void (*write)(uint8_t *, uint64_t *, uint64_t, int); int (*write_alloc)(uint8_t **, uint64_t *, uint64_t *, uint64_t, int, Dwarf_Error *); uint64_t (*decode)(uint8_t **, int); Dwarf_Half dbg_frame_rule_table_size; Dwarf_Half dbg_frame_rule_initial_value; Dwarf_Half dbg_frame_cfa_value; Dwarf_Half dbg_frame_same_value; Dwarf_Half dbg_frame_undefined_value; Dwarf_Regtable3 *dbg_internal_reg_table; /* * Fields used by libdwarf producer. */ Dwarf_Unsigned dbgp_flags; Dwarf_Unsigned dbgp_isa; Dwarf_Callback_Func dbgp_func; Dwarf_Callback_Func_b dbgp_func_b; Dwarf_Die dbgp_root_die; STAILQ_HEAD(, _Dwarf_Die) dbgp_dielist; STAILQ_HEAD(, _Dwarf_P_Expr) dbgp_pelist; Dwarf_LineInfo dbgp_lineinfo; Dwarf_ArangeSet dbgp_as; Dwarf_Macro_Details *dbgp_mdlist; Dwarf_Unsigned dbgp_mdcnt; STAILQ_HEAD(, _Dwarf_Cie) dbgp_cielist; STAILQ_HEAD(, _Dwarf_Fde) dbgp_fdelist; Dwarf_Unsigned dbgp_cielen; Dwarf_Unsigned dbgp_fdelen; Dwarf_NameTbl dbgp_pubs; Dwarf_NameTbl dbgp_weaks; Dwarf_NameTbl dbgp_funcs; Dwarf_NameTbl dbgp_types; Dwarf_NameTbl dbgp_vars; STAILQ_HEAD(, _Dwarf_P_Section) dbgp_seclist; Dwarf_Unsigned dbgp_seccnt; Dwarf_P_Section dbgp_secpos; Dwarf_P_Section dbgp_info; STAILQ_HEAD(, _Dwarf_Rel_Section) dbgp_drslist; Dwarf_Unsigned dbgp_drscnt; Dwarf_Rel_Section dbgp_drspos; }; /* * Internal function prototypes. */ int _dwarf_abbrev_add(Dwarf_CU, uint64_t, uint64_t, uint8_t, uint64_t, Dwarf_Abbrev *, Dwarf_Error *); void _dwarf_abbrev_cleanup(Dwarf_CU); int _dwarf_abbrev_find(Dwarf_CU, uint64_t, Dwarf_Abbrev *, Dwarf_Error *); int _dwarf_abbrev_gen(Dwarf_P_Debug, Dwarf_Error *); int _dwarf_abbrev_parse(Dwarf_Debug, Dwarf_CU, Dwarf_Unsigned *, Dwarf_Abbrev *, Dwarf_Error *); int _dwarf_add_AT_dataref(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Unsigned, Dwarf_Unsigned, const char *, Dwarf_P_Attribute *, Dwarf_Error *); int _dwarf_add_string_attr(Dwarf_P_Die, Dwarf_P_Attribute *, Dwarf_Half, char *, Dwarf_Error *); int _dwarf_alloc(Dwarf_Debug *, int, Dwarf_Error *); void _dwarf_arange_cleanup(Dwarf_Debug); int _dwarf_arange_gen(Dwarf_P_Debug, Dwarf_Error *); int _dwarf_arange_init(Dwarf_Debug, Dwarf_Error *); void _dwarf_arange_pro_cleanup(Dwarf_P_Debug); int _dwarf_attr_alloc(Dwarf_Die, Dwarf_Attribute *, Dwarf_Error *); Dwarf_Attribute _dwarf_attr_find(Dwarf_Die, Dwarf_Half); int _dwarf_attr_gen(Dwarf_P_Debug, Dwarf_P_Section, Dwarf_Rel_Section, Dwarf_CU, Dwarf_Die, int, Dwarf_Error *); int _dwarf_attr_init(Dwarf_Debug, Dwarf_Section *, uint64_t *, int, Dwarf_CU, Dwarf_Die, Dwarf_AttrDef, uint64_t, int, Dwarf_Error *); int _dwarf_attrdef_add(Dwarf_Debug, Dwarf_Abbrev, uint64_t, uint64_t, uint64_t, Dwarf_AttrDef *, Dwarf_Error *); uint64_t _dwarf_decode_lsb(uint8_t **, int); uint64_t _dwarf_decode_msb(uint8_t **, int); int64_t _dwarf_decode_sleb128(uint8_t **); uint64_t _dwarf_decode_uleb128(uint8_t **); void _dwarf_deinit(Dwarf_Debug); int _dwarf_die_alloc(Dwarf_Debug, Dwarf_Die *, Dwarf_Error *); int _dwarf_die_count_links(Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die); Dwarf_Die _dwarf_die_find(Dwarf_Die, Dwarf_Unsigned); int _dwarf_die_gen(Dwarf_P_Debug, Dwarf_CU, Dwarf_Rel_Section, Dwarf_Error *); void _dwarf_die_link(Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die); int _dwarf_die_parse(Dwarf_Debug, Dwarf_Section *, Dwarf_CU, int, uint64_t, uint64_t, Dwarf_Die *, int, Dwarf_Error *); void _dwarf_die_pro_cleanup(Dwarf_P_Debug); void _dwarf_elf_deinit(Dwarf_Debug); int _dwarf_elf_init(Dwarf_Debug, Elf *, Dwarf_Error *); int _dwarf_elf_load_section(void *, Dwarf_Half, Dwarf_Small **, int *); Dwarf_Endianness _dwarf_elf_get_byte_order(void *); Dwarf_Small _dwarf_elf_get_length_size(void *); Dwarf_Small _dwarf_elf_get_pointer_size(void *); Dwarf_Unsigned _dwarf_elf_get_section_count(void *); int _dwarf_elf_get_section_info(void *, Dwarf_Half, Dwarf_Obj_Access_Section *, int *); void _dwarf_expr_cleanup(Dwarf_P_Debug); int _dwarf_expr_into_block(Dwarf_P_Expr, Dwarf_Error *); +Dwarf_Section *_dwarf_find_next_types_section(Dwarf_Debug, Dwarf_Section *); Dwarf_Section *_dwarf_find_section(Dwarf_Debug, const char *); void _dwarf_frame_cleanup(Dwarf_Debug); int _dwarf_frame_fde_add_inst(Dwarf_P_Fde, Dwarf_Small, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); int _dwarf_frame_gen(Dwarf_P_Debug, Dwarf_Error *); -int _dwarf_frame_get_fop(Dwarf_Debug, uint8_t *, Dwarf_Unsigned, - Dwarf_Frame_Op **, Dwarf_Signed *, Dwarf_Error *); +int _dwarf_frame_get_fop(Dwarf_Debug, uint8_t, uint8_t *, + Dwarf_Unsigned, Dwarf_Frame_Op **, Dwarf_Signed *, + Dwarf_Error *); int _dwarf_frame_get_internal_table(Dwarf_Fde, Dwarf_Addr, Dwarf_Regtable3 **, Dwarf_Addr *, Dwarf_Error *); int _dwarf_frame_interal_table_init(Dwarf_Debug, Dwarf_Error *); void _dwarf_frame_params_init(Dwarf_Debug); void _dwarf_frame_pro_cleanup(Dwarf_P_Debug); int _dwarf_frame_regtable_copy(Dwarf_Debug, Dwarf_Regtable3 **, Dwarf_Regtable3 *, Dwarf_Error *); int _dwarf_frame_section_load(Dwarf_Debug, Dwarf_Error *); int _dwarf_frame_section_load_eh(Dwarf_Debug, Dwarf_Error *); int _dwarf_generate_sections(Dwarf_P_Debug, Dwarf_Error *); Dwarf_Unsigned _dwarf_get_reloc_type(Dwarf_P_Debug, int); int _dwarf_get_reloc_size(Dwarf_Debug, Dwarf_Unsigned); void _dwarf_info_cleanup(Dwarf_Debug); int _dwarf_info_first_cu(Dwarf_Debug, Dwarf_Error *); +int _dwarf_info_first_tu(Dwarf_Debug, Dwarf_Error *); int _dwarf_info_gen(Dwarf_P_Debug, Dwarf_Error *); -int _dwarf_info_load(Dwarf_Debug, int, Dwarf_Error *); +int _dwarf_info_load(Dwarf_Debug, Dwarf_Bool, Dwarf_Bool, + Dwarf_Error *); int _dwarf_info_next_cu(Dwarf_Debug, Dwarf_Error *); +int _dwarf_info_next_tu(Dwarf_Debug, Dwarf_Error *); void _dwarf_info_pro_cleanup(Dwarf_P_Debug); int _dwarf_init(Dwarf_Debug, Dwarf_Unsigned, Dwarf_Handler, Dwarf_Ptr, Dwarf_Error *); int _dwarf_lineno_gen(Dwarf_P_Debug, Dwarf_Error *); int _dwarf_lineno_init(Dwarf_Die, uint64_t, Dwarf_Error *); void _dwarf_lineno_cleanup(Dwarf_LineInfo); void _dwarf_lineno_pro_cleanup(Dwarf_P_Debug); -int _dwarf_loc_fill_locdesc(Dwarf_Debug, Dwarf_Locdesc *, uint8_t *, - uint64_t, uint8_t, Dwarf_Error *); +int _dwarf_loc_fill_locdesc(Dwarf_Debug, Dwarf_Locdesc *, + uint8_t *, uint64_t, uint8_t, uint8_t, uint8_t, + Dwarf_Error *); int _dwarf_loc_fill_locexpr(Dwarf_Debug, Dwarf_Locdesc **, - uint8_t *, uint64_t, uint8_t, Dwarf_Error *); + uint8_t *, uint64_t, uint8_t, uint8_t, uint8_t, + Dwarf_Error *); int _dwarf_loc_add(Dwarf_Die, Dwarf_Attribute, Dwarf_Error *); int _dwarf_loc_expr_add_atom(Dwarf_Debug, uint8_t *, uint8_t *, Dwarf_Small, Dwarf_Unsigned, Dwarf_Unsigned, int *, Dwarf_Error *); int _dwarf_loclist_find(Dwarf_Debug, Dwarf_CU, uint64_t, - Dwarf_Loclist *, Dwarf_Error *); -void _dwarf_loclist_cleanup(Dwarf_Debug); -void _dwarf_loclist_free(Dwarf_Loclist); -int _dwarf_loclist_add(Dwarf_Debug, Dwarf_CU, uint64_t, - Dwarf_Loclist *, Dwarf_Error *); + Dwarf_Locdesc ***, Dwarf_Signed *, Dwarf_Unsigned *, + Dwarf_Error *); void _dwarf_macinfo_cleanup(Dwarf_Debug); int _dwarf_macinfo_gen(Dwarf_P_Debug, Dwarf_Error *); int _dwarf_macinfo_init(Dwarf_Debug, Dwarf_Error *); void _dwarf_macinfo_pro_cleanup(Dwarf_P_Debug); int _dwarf_nametbl_init(Dwarf_Debug, Dwarf_NameSec *, Dwarf_Section *, Dwarf_Error *); void _dwarf_nametbl_cleanup(Dwarf_NameSec *); int _dwarf_nametbl_gen(Dwarf_P_Debug, const char *, Dwarf_NameTbl, Dwarf_Error *); void _dwarf_nametbl_pro_cleanup(Dwarf_NameTbl *); int _dwarf_pro_callback(Dwarf_P_Debug, char *, int, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned *, int *); Dwarf_P_Section _dwarf_pro_find_section(Dwarf_P_Debug, const char *); int _dwarf_ranges_add(Dwarf_Debug, Dwarf_CU, uint64_t, Dwarf_Rangelist *, Dwarf_Error *); void _dwarf_ranges_cleanup(Dwarf_Debug); int _dwarf_ranges_find(Dwarf_Debug, uint64_t, Dwarf_Rangelist *); uint64_t _dwarf_read_lsb(uint8_t *, uint64_t *, int); uint64_t _dwarf_read_msb(uint8_t *, uint64_t *, int); int64_t _dwarf_read_sleb128(uint8_t *, uint64_t *); uint64_t _dwarf_read_uleb128(uint8_t *, uint64_t *); char *_dwarf_read_string(void *, Dwarf_Unsigned, uint64_t *); uint8_t *_dwarf_read_block(void *, uint64_t *, uint64_t); int _dwarf_reloc_section_finalize(Dwarf_P_Debug, Dwarf_Rel_Section, Dwarf_Error *); int _dwarf_reloc_entry_add(Dwarf_P_Debug, Dwarf_Rel_Section, Dwarf_P_Section, unsigned char, unsigned char, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, const char *, Dwarf_Error *); int _dwarf_reloc_entry_add_pair(Dwarf_P_Debug, Dwarf_Rel_Section, Dwarf_P_Section, unsigned char, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); void _dwarf_reloc_cleanup(Dwarf_P_Debug); int _dwarf_reloc_gen(Dwarf_P_Debug, Dwarf_Error *); int _dwarf_reloc_section_gen(Dwarf_P_Debug, Dwarf_Rel_Section, Dwarf_Error *); int _dwarf_reloc_section_init(Dwarf_P_Debug, Dwarf_Rel_Section *, Dwarf_P_Section, Dwarf_Error *); void _dwarf_reloc_section_free(Dwarf_P_Debug, Dwarf_Rel_Section *); void _dwarf_section_cleanup(Dwarf_P_Debug); int _dwarf_section_callback(Dwarf_P_Debug, Dwarf_P_Section, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); void _dwarf_section_free(Dwarf_P_Debug, Dwarf_P_Section *); int _dwarf_section_init(Dwarf_P_Debug, Dwarf_P_Section *, const char *, int, Dwarf_Error *); void _dwarf_set_error(Dwarf_Debug, Dwarf_Error *, int, int, const char *, int); int _dwarf_strtab_add(Dwarf_Debug, char *, uint64_t *, Dwarf_Error *); void _dwarf_strtab_cleanup(Dwarf_Debug); int _dwarf_strtab_gen(Dwarf_P_Debug, Dwarf_Error *); char *_dwarf_strtab_get_table(Dwarf_Debug); int _dwarf_strtab_init(Dwarf_Debug, Dwarf_Error *); +void _dwarf_type_unit_cleanup(Dwarf_Debug); void _dwarf_write_block(void *, uint64_t *, uint8_t *, uint64_t); int _dwarf_write_block_alloc(uint8_t **, uint64_t *, uint64_t *, uint8_t *, uint64_t, Dwarf_Error *); void _dwarf_write_lsb(uint8_t *, uint64_t *, uint64_t, int); int _dwarf_write_lsb_alloc(uint8_t **, uint64_t *, uint64_t *, uint64_t, int, Dwarf_Error *); void _dwarf_write_msb(uint8_t *, uint64_t *, uint64_t, int); int _dwarf_write_msb_alloc(uint8_t **, uint64_t *, uint64_t *, uint64_t, int, Dwarf_Error *); void _dwarf_write_padding(void *, uint64_t *, uint8_t, uint64_t); int _dwarf_write_padding_alloc(uint8_t **, uint64_t *, uint64_t *, uint8_t, uint64_t, Dwarf_Error *); void _dwarf_write_string(void *, uint64_t *, char *); int _dwarf_write_string_alloc(uint8_t **, uint64_t *, uint64_t *, char *, Dwarf_Error *); int _dwarf_write_sleb128(uint8_t *, uint8_t *, int64_t); int _dwarf_write_sleb128_alloc(uint8_t **, uint64_t *, uint64_t *, int64_t, Dwarf_Error *); int _dwarf_write_uleb128(uint8_t *, uint8_t *, uint64_t); int _dwarf_write_uleb128_alloc(uint8_t **, uint64_t *, uint64_t *, uint64_t, Dwarf_Error *); #endif /* !__LIBDWARF_H_ */ diff --git a/libdwarf/dwarf.3 b/libdwarf/dwarf.3 index b32299cd1a11..5363034c45ae 100644 --- a/libdwarf/dwarf.3 +++ b/libdwarf/dwarf.3 @@ -1,727 +1,753 @@ .\" Copyright (c) 2011 Joseph Koshy. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" This software is provided by Joseph Koshy ``as is'' and .\" any express or implied warranties, including, but not limited to, the .\" implied warranties of merchantability and fitness for a particular purpose .\" are disclaimed. in no event shall Joseph Koshy be liable .\" for any direct, indirect, incidental, special, exemplary, or consequential .\" damages (including, but not limited to, procurement of substitute goods .\" or services; loss of use, data, or profits; or business interruption) .\" however caused and on any theory of liability, whether in contract, strict .\" liability, or tort (including negligence or otherwise) arising in any way .\" out of the use of this software, even if advised of the possibility of .\" such damage. .\" -.\" $Id: dwarf.3 2075 2011-10-27 03:47:28Z jkoshy $ +.\" $Id: dwarf.3 3130 2014-12-21 20:06:29Z jkoshy $ .\" -.Dd September 17, 2011 +.Dd December 21, 2014 .Os .Dt DWARF 3 .Sh NAME .Nm dwarf .Nd access debugging information in object files .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Sh DESCRIPTION .Pp The .Lb libdwarf provides functions that allow an application to read and write debugging information in object files. The format of debugging information accessible through this API is defined by the DWARF standard, see .Xr dwarf 4 . .Pp The .Xr DWARF 3 API has two parts: .Bl -bullet .It A consumer API set allows applications to read existing debug information in a program object. The functions that comprise the DWARF consumer API are described in the section .Sx "DWARF Consumer API" below. .It A producer API set that allows applications to add debug information to a program object. The functions that comprise the DWARF producer API are described in the section .Sx "DWARF Producer API" below. .El .Pp Each function referenced below is further described in its own manual page. .Ss Namespace use The DWARF library uses the following prefixes: .Pp .Bl -tag -width ".Li Dwarf_*" -compact .It Li DWARF_* Used for error numbers and constants. .It Li DW_* Used for constants. .It Li Dwarf_* Used for types. .It Li dwarf_* Used for functions and macros that make up the API. .El .Ss Data Types The DWARF(3) API uses the following data types: .Pp .Bl -tag -width ".Vt Dwarf_Unsigned" -compact .It Vt Dwarf_Abbrev Describes DWARF abbreviations. .It Vt Dwarf_Addr A program address in the target object. .It Vt Dwarf_Arange Describes address ranges. .It Vt Dwarf_Attribute , Vt Dwarf_P_Attribute Describes attributes of debugging information entries. .It Vt Dwarf_Bool Used for boolean states. .It Vt Dwarf_Cie , Vt Dwarf_P_Cie Describes call information that is common to several frames. .It Vt Dwarf_Debug , Vt Dwarf_P_Debug An opaque type describing a debug context. .It Vt Dwarf_Die , Vt Dwarf_P_Die A debugging information entry. .It Vt Dwarf_Fde , Vt Dwarf_P_Fde A frame descriptor. .It Vt Dwarf_Func A descriptor representing a function. .It Vt Dwarf_Global A descriptor representing a global name. .It Vt Dwarf_Half A 16-bit wide unsigned numeric type. .It Vt Dwarf_Handler A pointer to an error handling function. .It Vt Dwarf_Line A descriptor for a source line. .It Vt Dwarf_Off An unsigned file offset, corresponding to an .Vt off_t type supported by the underlying operating system. .It Vt Dwarf_P_Expr A descriptor for a location expression. .It Vt Dwarf_Ptr A virtual address used by an application. .It Vt Dwarf_Signed A 64-bit wide signed numeric type. .It Vt Dwarf_Small An 8-bit wide unsigned numeric type. .It Vt Dwarf_Type A descriptor representing a user-specified type. .It Vt Dwarf_Unsigned A 64-bit wide unsigned numeric type. .It Vt Dwarf_Var A descriptor representing a static variable. .It Vt Dwarf_Weak A descriptor representing a weak name. .El .Ss Error Handling .Pp Library functions that encounter an error will return with a value other than .Dv DW_DLV_OK . .Pp The .Lb libdwarf allows applications to specify three levels of error handling: .Bl -enum -compact .It Most library functions take a parameter of type .Vt Dwarf_Error that specifies a location to store an error descriptor in case of an error. If an error occurs during the execution on an API, and if this parameter is non-NULL, then an error descriptor is written to the location specified. .It Otherwise, if the error parameter was NULL, but if an error handler was defined for the debug context in use using .Xr dwarf_init 3 or .Xr dwarf_seterrhand 3 , then the library will invoke the specified error handler with an error descriptor as argument. .It Otherwise, if a library wide error handler was specified using .Xr dwarf_seterrhand 3 , it is called. .El .Pp Error descriptors may be used with .Xr dwarf_errmsg 3 or .Xr dwarf_errno 3 . .Sh The DWARF Consumer API The DWARF consumer API permits applications to read DWARF information in an object file. .Pp The major functional groups of functions in the consumer API are listed below. .Pp .Bl -tag -compact -width "CCCC" .It Abbreviations .Bl -tag -compact .It Fn dwarf_get_abbrev Retrieve abbreviation information at a given offset. .It Fn dwarf_get_abbrev_children_flag Check if an abbreviation has child elements. .It Fn dwarf_get_abbrev_code Retrieve the abbreviation code for an abbreviation entry descriptor. .It Fn dwarf_get_abbrev_entry Retrieve abbreviation information for an abbreviation entry descriptor. .It Fn dwarf_get_abbrev_tag Retrieve the tag for an abbreviation entry. .El .It Addresses .Bl -tag -compact .It Fn dwarf_get_address_size Return the number of bytes needed to represent an address. .It Fn dwarf_get_arange Search for an address range descriptor covering an address. .It Fn dwarf_get_arange_cu_header_offset Retrieve the offsets associated with an address range descriptor. .It Fn dwarf_get_arange_info Extract address range information from a descriptor. .It Fn dwarf_get_aranges Retrieve program address space mappings. .It Fn dwarf_get_cu_die_offset Retrieve the offset associated with a compilation unit for an address range descriptor. .It Fn dwarf_get_ranges , Fn dwarf_get_ranges_a Retrieve information about non-contiguous address ranges for a debugging information entry. .El .It Attributes .Bl -tag -compact .It Fn dwarf_arrayorder Retrieve the value of a .Dv DW_AT_ordering attribute. .It Fn dwarf_attr Retrieve an attribute descriptor. .It Fn dwarf_attrlist Retrieve attribute descriptors for a debugging information entry. +.It Fn dwarf_attroffset +Retrieve the section-relative offset of an attribute descriptor. .It Fn dwarf_attrval_flag Retrieve a .Dv DW_AT_FORM_flag value. .It Fn dwarf_attrval_signed Retrieve an attribute's value as a signed integral quantity. .It Fn dwarf_attrval_string Retrieve an attribute's value as a NUL-terminated string. .It Fn dwarf_attrval_unsigned Retrieve an attribute's value as an unsigned integral quantity. .It Fn dwarf_bitoffset , Retrieve the value of a .Dv DW_AT_bit_offset attribute. .It Fn dwarf_bitsize , Retrieve the value of a .Dv DW_AT_bit_size attribute. .It Fn dwarf_bytesize Retrieve the value of a .Dv DW_AT_byte_size attribute. .It Fn dwarf_formaddr Return the value of an .Dv ADDRESS Ns - Ns class attribute. .It Fn dwarf_formblock Return the value of a .Dv BLOCK Ns - Ns class attribute .It Fn dwarf_formexprloc Return information about a location expression. .It Fn dwarf_formflag Retrieve information about a .Dv BOOLEAN Ns - Ns class attribute. .It Fn dwarf_formref , Fn dwarf_global_formref Retrieve offsets for .Dv REFERENCE Ns - Ns class attributes. .It Fn dwarf_formsdata , Fn dwarf_formudata Retrieve the value of a .Dv CONSTANT Ns - Ns class attribute. .It Fn dwarf_formsig8 Return the type signature for a DWARF type. .It Fn dwarf_formstring Retrieve information about a .Dv STRING Ns - Ns class attribute. .It Fn dwarf_get_form_class Retrieve the form class for an attribute. .It Fn dwarf_hasattr Check for the presence of an attribute. .It Fn dwarf_hasform Check if an attribute has the given form. .It Fn dwarf_whatattr Retrieve the attribute code for an attribute. .It Fn dwarf_whatform , Fn dwarf_whatform_direct Retrieve the form of an attribute. .El .It Call Information Entries and Frame Descriptor Entries .Bl -tag -compact .It Fn dwarf_get_cie_index Retrieve the index for a CIE descriptor. .It Fn dwarf_get_cie_info Retrieve information from a CIE descriptor. .It Fn dwarf_get_cie_of_fde Retrieve a CIE descriptor. .It Fn dwarf_get_fde_at_pc Retrieve an FDE descriptor for an address. .It Fn dwarf_get_fde_info_for_all_regs Retrieve register rule row. .It Fn dwarf_get_fde_info_for_all_regs3 Retrieve register rule row (revised API). .It Fn dwarf_get_fde_info_for_cfa_reg3 Retrieve a CFA register rule. .It Fn dwarf_get_fde_info_for_reg Retrieve a register rule. .It Fn dwarf_get_fde_info_for_reg3 Retrieve a register rule (revised API). .It Fn dwarf_get_fde_instr_bytes Retrieve instructions from an FDE descriptor. .It Fn dwarf_get_fde_list , Fn dwarf_get_fde_list_eh Retrieve frame information. .It Fn dwarf_get_fde_n Retrieve an FDE descriptor. .It Fn dwarf_get_fde_range Retrieve range information from an FDE descriptor. .El .It Compilation Units .Bl -tag -compact -.It Fn dwarf_get_cu_die_offset_given_cu_header_offset +.It Xo +.Fn dwarf_get_cu_die_offset_given_cu_header_offset , +.Fn dwarf_get_cu_die_offset_given_cu_header_offset_b +.Xc Retrieve the offset of the debugging information entry for a -compilation unit. -.It Fn dwarf_next_cu_header , Fn dwarf_next_cu_header_b +compilation or type unit. +.It Xo +.Fn dwarf_next_cu_header , +.Fn dwarf_next_cu_header_b , +.Fn dwarf_next_cu_header_c +.Xc Step through compilation units in a debug context. .El .It Debugging Information Entries .Bl -tag -compact .It Fn dwarf_child Returns the child of a debugging information entry. .It Fn dwarf_die_abbrev_code Returns the abbreviation code for a debugging information entry. .It Fn dwarf_die_CU_offset , Fn dwarf_die_CU_offset_range Retrieve offsets and lengths for a compilation unit. .It Fn dwarf_diename Returns the .Dv DW_AT_name attribute for a debugging information entry. .It Fn dwarf_dieoffset Retrieves the offset for a debugging information entry. -.It Fn dwarf_highpc +.It Fn dwarf_get_die_infotypes_flag +Indicate the originating section for a debugging information entry. +.It Fn dwarf_highpc , Fn dwarf_highpc_b Return the highest PC value for a debugging information entry. .It Fn dwarf_lowpc Return the lowest PC value for a debugging information entry. -.It Fn dwarf_offdie +.It Fn dwarf_offdie , Fn dwarf_offdie_b Retrieve a debugging information entry given an offset. -.It Fn dwarf_siblingof +.It Fn dwarf_siblingof , Fn dwarf_siblingof_b Retrieve the sibling descriptor for a debugging information entry. .It Fn dwarf_srclang Retrive the source language attribute for a debugging information entry. .It Fn dwarf_tag Retrieve the tag for a debugging information entry. .El .It Functions .Bl -tag -compact .It Fn dwarf_func_cu_offset Retrieves the offset for the compilation unit for a function. .It Fn dwarf_func_die_offset Retrieves the offset for the debugging information entry for a function. .It Fn dwarf_funcname Retrieves the name of a function. .It Fn dwarf_func_name_offsets Retrieve both the name and offsets for a function. .It Fn dwarf_get_funcs Retrieve information about static functions. .El .It Globals .Bl -tag -compact .It Fn dwarf_get_globals Retrieve a list of globals. .It Fn dwarf_global_cu_offset Return the offset for compilation unit for a global. .It Fn dwarf_global_die_offset Return the offset for the debugging information entry for a global. .It Fn dwarf_global_name_offsets Return the name and offsets for a global. .It Fn dwarf_globname Return the name for a global. .El .It Initialization and Finalization Functions .Fn dwarf_elf_init and .Fn dwarf_init may be used for initialization. The function .Fn dwarf_finish may be used to release resources. .Pp The functions .Fn dwarf_object_init and .Fn dwarf_object_finish allow an application to specify alternate low-level file access routines. .It Line Numbers .Bl -tag -compact .It Fn dwarf_lineaddr Retrieve the program address for a source line. .It Fn dwarf_linebeginstatement Check if a source line corresponds to the beginning of a statement. .It Fn dwarf_lineblock Check if a source line corresponds to the start of a basic block. .It Fn dwarf_lineendsequence Check if the source line corresponds to the end of a sequence of instructions. .It Fn dwarf_lineno Retrieve the line number for a line descriptor. .It Fn dwarf_lineoff Retrieve the column number for a line descriptor. .It Fn dwarf_linesrc Retrieve the source file for a line descriptor. .It Fn dwarf_line_srcfileno Retrieve the index of the source file for a line descriptor. .It Fn dwarf_srcfiles Retrieve source files for a compilation unit. .It Fn dwarf_srclines Return line number information for a compilation unit. .El .It Location Lists .Bl -tag -compact .It Fn dwarf_get_loclist_entry Retrieve a location list entry. .It Fn dwarf_loclist , Fn dwarf_loclist_n Retrieve location expressions. -.It Fn dwarf_loclist_from_expr , Fn dwarf_loclist_from_expr_a +.It Xo +.Fn dwarf_loclist_from_expr , +.Fn dwarf_loclist_from_expr_a , +.Fn dwarf_loclist_from_expr_b +.Xc Translate a location expression into a location descriptor. .El .It Error Handling .Bl -tag -compact .It Fn dwarf_errmsg Retrieve a human-readable error message. .It Fn dwarf_errno Retrieve an error number from an error descriptor. .It Fn dwarf_seterrarg Set the argument passed to a callback error handler. .It Fn dwarf_seterrhand Set the callback handler to be called in case of an error. .El .It Frame Handling .Bl -tag -compact .It Fn dwarf_expand_frame_instructions Translate frame instruction bytes. .It Fn dwarf_set_frame_cfa_value Set the CFA parameter for the internal register rule table. .It Fn dwarf_set_frame_rule_initial_value Set the initial value of the register rules in the internal register rule table. .It Fn dwarf_set_frame_rule_table_size Set the maximum number of columns in the register rule table. .It Fn dwarf_set_frame_same_value Set the register number representing the .Dq "same value" rule. .It Fn dwarf_set_frame_undefined_value Set the register number representing the .Dq "undefined" rule. .El .It Macros .Bl -tag -compact .It Fn dwarf_find_macro_value_start Return the macro value part of a macro string. .It Fn dwarf_get_macro_details Retrieve macro information. .El .It Memory Management In the DWARF consumer API, the rules for memory management differ between functions. In some cases, the memory areas returned to the application by the library are freed by calling specific API functions. In others, the deallocation function .Fn dwarf_dealloc suffices. The individual manual pages for the API's functions document the specific memory management rules to be followed. .Pp The function .Fn dwarf_dealloc is used to mark memory arenas as unused. Additionally, the following functions release specific types of DWARF resources: .Fn dwarf_fde_cie_list_dealloc , .Fn dwarf_funcs_dealloc , .Fn dwarf_globals_dealloc , .Fn dwarf_pubtypes_dealloc , .Fn dwarf_ranges_dealloc , .Fn dwarf_srclines_dealloc , .Fn dwarf_types_dealloc , .Fn dwarf_vars_dealloc , and .Fn dwarf_weaks_dealloc . .It Symbol Constants The following functions may be used to return symbolic names for DWARF constants: .Fn dwarf_get_ACCESS_name , .Fn dwarf_get_AT_name , .Fn dwarf_get_ATE_name , .Fn dwarf_get_CC_name , .Fn dwarf_get_CFA_name , .Fn dwarf_get_CHILDREN_name , .Fn dwarf_get_DS_name , .Fn dwarf_get_DSC_name , .Fn dwarf_get_EH_name , .Fn dwarf_get_END_name , .Fn dwarf_get_FORM_name , .Fn dwarf_get_ID_name , .Fn dwarf_get_INL_name , .Fn dwarf_get_LANG_name , .Fn dwarf_get_LNE_name , .Fn dwarf_get_LNS_name , .Fn dwarf_get_MACINFO_name , .Fn dwarf_get_OP_name , .Fn dwarf_get_ORD_name , .Fn dwarf_get_TAG_name , .Fn dwarf_get_VIRTUALITY_name , and .Fn dwarf_get_VIS_name . .It Types .Bl -tag -compact .It Fn dwarf_get_pubtypes , Fn dwarf_get_types Retrieve descriptors for user-defined types. +.It Fn dwarf_next_types_section +Step through +.Dq \&.debug_types +sections in a debug context. .It Fn dwarf_pubtype_cu_offset , Fn dwarf_type_cu_offset Return the offset for the compilation unit for a type. .It Fn dwarf_pubtype_die_offset , Fn dwarf_type_die_offset Return the offset for the debugging information entry for a type. .It Fn dwarf_pubtypename , Fn dwarf_typename Retrieve the name of a type. .It Fn dwarf_pubtype_name_offsets , Fn dwarf_type_name_offsets Retrieve the name and offsets for a type. .El .It Variables .Bl -tag -compact .It Fn dwarf_get_vars Retrieve descriptors for static variables. .It Fn dwarf_var_cu_offset Return the offset for the compilation unit for a variable. .It Fn dwarf_var_die_offset Return the offset for the debugging information entry for a variable. .It Fn dwarf_varname Retrieve the name of a variable. .It Fn dwarf_var_name_offsets Retrieve the name and offsets for a variable. .El .It Weak Symbols .Bl -tag -compact .It Fn dwarf_get_weaks Retrieve information about weak symbols. .It Fn dwarf_weak_cu_offset Return the offset for the compilation unit for a weak symbol. .It Fn dwarf_weak_die_offset Return the offset for the debugging information entry for a weak symbol. .It Fn dwarf_weakname Retrieve the name of a weak symbol. .It Fn dwarf_weak_name_offsets Retrieve the name and offsets for a weak symbol. .El .It Miscellaneous .Bl -tag -compact .It Fn dwarf_get_elf Retrieve the ELF descriptor for a debug context, see .Xr elf 3 . .It Fn dwarf_get_str Retrieve a NUL-terminated string from the DWARF string section. .It Fn dwarf_set_reloc_application Control whether relocations are to be handled by .Lb libdwarf . .El .El .Sh The DWARF Producer API The DWARF producer API permits applications to add DWARF information to an object file. .Pp The major functional groups of functions in the producer API are listed below. .Bl -tag -width "CCCC" .It Attribute Management The following functions are used to attach attributes to a debugging information entry: .Fn dwarf_add_AT_comp_dir , .Fn dwarf_add_AT_const_value_signedint , .Fn dwarf_add_AT_const_value_string , .Fn dwarf_add_AT_const_value_unsignedint , .Fn dwarf_add_AT_dataref , .Fn dwarf_add_AT_flag , .Fn dwarf_add_AT_location_expr , .Fn dwarf_add_AT_name , .Fn dwarf_add_AT_producer , .Fn dwarf_add_AT_ref_address , .Fn dwarf_add_AT_reference , .Fn dwarf_add_AT_signed_const , .Fn dwarf_add_AT_string , .Fn dwarf_add_AT_targ_address , .Fn dwarf_add_AT_targ_address_b and .Fn dwarf_add_AT_unsigned_const . .It Debugging Information Entry Management .Bl -tag -compact .It Fn dwarf_add_die_to_debug Set the root debugging information entry for a DWARF producer instance. .It Fn dwarf_die_link Links debugging information entries. .It Fn dwarf_new_die Allocate a new debugging information entry. .El .It Initialization and Finalization The functions .Fn dwarf_producer_init and .Fn dwarf_producer_init_b are used to initialize a producer instance. .Pp When done, applications release resources using the function .Fn dwarf_producer_finish . .It Relocations and Sections .Bl -tag -compact .It Fn dwarf_get_relocation_info Retrieve a relocation array from a producer instance. .It Fn dwarf_get_relocation_info_count Return the number of relocation arrays for a producer instance. .It Fn dwarf_get_section_bytes Retrieve the ELF byte stream for a section. .It Fn dwarf_reset_section_bytes Reset internal state for a producer instance. .It Fn dwarf_transform_to_disk_form Prepare byte streams for writing out. .El .It Macros .Bl -tag -compact .It Fn dwarf_def_macro Add a macro definition. .It Fn dwarf_end_macro_file , Fn dwarf_start_macro_file Record macro file related information. .It Fn dwarf_undef_macro Note the removal of a macro definition. .It Fn dwarf_vendor_ext Enables storing macro information as specified in the DWARF standard. .El .It Symbols, Expressions, Addresses and Offsets .Bl -tag -compact .It Fn dwarf_add_arange , Fn dwarf_add_arange_b Add address range information. .It Fn dwarf_add_directory_decl Add information about an include directory to a producer instance. .It Fn dwarf_add_fde_inst Add an operation to a frame descriptor entry. .It Fn dwarf_add_file_decl Add information about a source file to a producer instance. .It Fn dwarf_add_frame_cie Add call information to a frame descriptor. .It Fn dwarf_add_frame_fde , Fn dwarf_add_frame_fde_b Link a frame descriptor to a producer instance. .It Fn dwarf_add_funcname Add information about a function to a producer instance. .It Fn dwarf_add_line_entry Record mapping information between machine addresses and a source line. .It Fn dwarf_add_expr_addr , Fn dwarf_add_expr_addr_b Add a .Dv DW_OP_addr opcode to a location expression. .It Fn dwarf_add_expr_gen Add an operator to a location expression. .It Fn dwarf_add_pubname Add information about a global name to a producer instance. .It Fn dwarf_add_typename Add information about a type to a producer instance. .It Fn dwarf_add_varname Add information about a static variable to a producer instance. .It Fn dwarf_add_weakname Add information about a weak symbol to a producer instance. .It Fn dwarf_expr_current_offset Retrieve the current size of a location expression. .It Fn dwarf_expr_into_block Convert a location expression into a byte stream. .It Fn dwarf_fde_cfa_offset Append a .Dv DW_CFA_offset operation to a frame descriptor. .It Fn dwarf_lne_end_sequence , Fn dwarf_lne_set_address Note address ranges for source lines. .It Fn dwarf_new_expr Allocate a location expression descriptor. .It Fn dwarf_new_fde Allocate a frame descriptor. .El .It Miscellaneous The function .Fn dwarf_producer_set_isa sets the instruction set architecture for the producer instance. .El .Sh COMPATIBILITY This implementation is believed to be source compatible with the SGI/GNU DWARF(3) library, version 20110113. .Pp Known differences with the SGI/GNU library include: .Bl -bullet -compact .It The memory management scheme used differs, in a backward-compatible way. See .Sx Memory Management above, for coding guidelines for portable applications. .It There is provision for setting a library-wide error handler in addition to the per-debug context handlers supported by the SGI/GNU API, see the subsection .Sx Error Handling above. +.El +.Ss Extensions +The following APIs are extensions specific to this implementation: +.Bl -bullet -compact +.It +.Fn dwarf_attroffset .It -The following API is an extension: -.Fn dwarf_producer_set_isa . +.Fn dwarf_next_types_section +.It +.Fn dwarf_producer_set_isa .El .Sh SEE ALSO .Xr elf 3 .Sh STANDARDS The DWARF standard is defined by .Rs .%T "The DWARF Debugging Information Format" .%V "Version 4" .%O "http://www.dwarfstd.org/" .Re .Sh HISTORY The DWARF(3) API originated at Silicon Graphics Inc. .Pp A BSD-licensed implementation of a subset of the API was written by .An "John Birrell" Aq jb@FreeBSD.org for the FreeBSD project. The implementation was subsequently revised and completed by .An "Kai Wang" Aq kaiwang27@users.sourceforge.net . .Pp Manual pages for this implementation were written by .An "Joseph Koshy" Aq jkoshy@users.sourceforge.net and .An "Kai Wang" Aq kaiwang27@users.sourceforge.net . diff --git a/libdwarf/dwarf.h b/libdwarf/dwarf.h index b1a3e4ec9670..c79da96dbb47 100644 --- a/libdwarf/dwarf.h +++ b/libdwarf/dwarf.h @@ -1,544 +1,599 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *notice, this list of conditions and the following disclaimer in the *documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dwarf.h 2075 2011-10-27 03:47:28Z jkoshy $ + * $Id: dwarf.h 3052 2014-05-26 20:36:24Z kaiwang27 $ */ #ifndef _DWARF_H_ #define _DWARF_H_ #define DW_TAG_array_type 0x01 #define DW_TAG_class_type 0x02 #define DW_TAG_entry_point 0x03 #define DW_TAG_enumeration_type 0x04 #define DW_TAG_formal_parameter 0x05 #define DW_TAG_imported_declaration 0x08 #define DW_TAG_label 0x0a #define DW_TAG_lexical_block 0x0b #define DW_TAG_member 0x0d #define DW_TAG_pointer_type 0x0f #define DW_TAG_reference_type 0x10 #define DW_TAG_compile_unit 0x11 #define DW_TAG_string_type 0x12 #define DW_TAG_structure_type 0x13 #define DW_TAG_subroutine_type 0x15 #define DW_TAG_typedef 0x16 #define DW_TAG_union_type 0x17 #define DW_TAG_unspecified_parameters 0x18 #define DW_TAG_variant 0x19 #define DW_TAG_common_block 0x1a #define DW_TAG_common_inclusion 0x1b #define DW_TAG_inheritance 0x1c #define DW_TAG_inlined_subroutine 0x1d #define DW_TAG_module 0x1e #define DW_TAG_ptr_to_member_type 0x1f #define DW_TAG_set_type 0x20 #define DW_TAG_subrange_type 0x21 #define DW_TAG_with_stmt 0x22 #define DW_TAG_access_declaration 0x23 #define DW_TAG_base_type 0x24 #define DW_TAG_catch_block 0x25 #define DW_TAG_const_type 0x26 #define DW_TAG_constant 0x27 #define DW_TAG_enumerator 0x28 #define DW_TAG_friend 0x2a #define DW_TAG_namelist 0x2b #define DW_TAG_namelist_item 0x2c #define DW_TAG_packed_type 0x2d #define DW_TAG_subprogram 0x2e #define DW_TAG_template_type_parameter 0x2f #define DW_TAG_template_type_param 0x2f #define DW_TAG_template_value_parameter 0x30 #define DW_TAG_template_value_param 0x30 #define DW_TAG_thrown_type 0x31 #define DW_TAG_try_block 0x32 #define DW_TAG_variant_part 0x33 #define DW_TAG_variable 0x34 #define DW_TAG_volatile_type 0x35 #define DW_TAG_dwarf_procedure 0x36 #define DW_TAG_restrict_type 0x37 #define DW_TAG_interface_type 0x38 #define DW_TAG_namespace 0x39 #define DW_TAG_imported_module 0x3a #define DW_TAG_unspecified_type 0x3b #define DW_TAG_partial_unit 0x3c #define DW_TAG_imported_unit 0x3d #define DW_TAG_condition 0x3f #define DW_TAG_shared_type 0x40 #define DW_TAG_type_unit 0x41 #define DW_TAG_rvalue_reference_type 0x42 #define DW_TAG_template_alias 0x43 #define DW_TAG_lo_user 0x4080 #define DW_TAG_hi_user 0xffff +/* GNU extensions. */ +#define DW_TAG_format_label 0x4101 +#define DW_TAG_function_template 0x4102 +#define DW_TAG_class_template 0x4103 +#define DW_TAG_GNU_BINCL 0x4104 +#define DW_TAG_GNU_EINCL 0x4105 +#define DW_TAG_GNU_template_template_parameter 0x4106 +#define DW_TAG_GNU_template_template_param 0x4106 +#define DW_TAG_GNU_template_parameter_pack 0x4107 +#define DW_TAG_GNU_formal_parameter_pack 0x4108 +#define DW_TAG_GNU_call_site 0x4109 +#define DW_TAG_GNU_call_site_parameter 0x410a + #define DW_CHILDREN_no 0x00 #define DW_CHILDREN_yes 0x01 #define DW_AT_sibling 0x01 #define DW_AT_location 0x02 #define DW_AT_name 0x03 #define DW_AT_ordering 0x09 #define DW_AT_subscr_data 0x0a #define DW_AT_byte_size 0x0b #define DW_AT_bit_offset 0x0c #define DW_AT_bit_size 0x0d #define DW_AT_element_list 0x0f #define DW_AT_stmt_list 0x10 #define DW_AT_low_pc 0x11 #define DW_AT_high_pc 0x12 #define DW_AT_language 0x13 #define DW_AT_member 0x14 #define DW_AT_discr 0x15 #define DW_AT_discr_value 0x16 #define DW_AT_visibility 0x17 #define DW_AT_import 0x18 #define DW_AT_string_length 0x19 #define DW_AT_common_reference 0x1a #define DW_AT_comp_dir 0x1b #define DW_AT_const_value 0x1c #define DW_AT_containing_type 0x1d #define DW_AT_default_value 0x1e #define DW_AT_inline 0x20 #define DW_AT_is_optional 0x21 #define DW_AT_lower_bound 0x22 #define DW_AT_producer 0x25 #define DW_AT_prototyped 0x27 #define DW_AT_return_addr 0x2a #define DW_AT_start_scope 0x2c #define DW_AT_bit_stride 0x2e #define DW_AT_stride_size 0x2e #define DW_AT_upper_bound 0x2f #define DW_AT_abstract_origin 0x31 #define DW_AT_accessibility 0x32 #define DW_AT_address_class 0x33 #define DW_AT_artificial 0x34 #define DW_AT_base_types 0x35 #define DW_AT_calling_convention 0x36 #define DW_AT_count 0x37 #define DW_AT_data_member_location 0x38 #define DW_AT_decl_column 0x39 #define DW_AT_decl_file 0x3a #define DW_AT_decl_line 0x3b #define DW_AT_declaration 0x3c #define DW_AT_discr_list 0x3d #define DW_AT_encoding 0x3e #define DW_AT_external 0x3f #define DW_AT_frame_base 0x40 #define DW_AT_friend 0x41 #define DW_AT_identifier_case 0x42 #define DW_AT_macro_info 0x43 #define DW_AT_namelist_item 0x44 #define DW_AT_priority 0x45 #define DW_AT_segment 0x46 #define DW_AT_specification 0x47 #define DW_AT_static_link 0x48 #define DW_AT_type 0x49 #define DW_AT_use_location 0x4a #define DW_AT_variable_parameter 0x4b #define DW_AT_virtuality 0x4c #define DW_AT_vtable_elem_location 0x4d #define DW_AT_allocated 0x4e #define DW_AT_associated 0x4f #define DW_AT_data_location 0x50 #define DW_AT_byte_stride 0x51 #define DW_AT_entry_pc 0x52 #define DW_AT_use_UTF8 0x53 #define DW_AT_extension 0x54 #define DW_AT_ranges 0x55 #define DW_AT_trampoline 0x56 #define DW_AT_call_column 0x57 #define DW_AT_call_file 0x58 #define DW_AT_call_line 0x59 #define DW_AT_description 0x5a #define DW_AT_binary_scale 0x5b #define DW_AT_decimal_scale 0x5c #define DW_AT_small 0x5d #define DW_AT_decimal_sign 0x5e #define DW_AT_digit_count 0x5f #define DW_AT_picture_string 0x60 #define DW_AT_mutable 0x61 #define DW_AT_threads_scaled 0x62 #define DW_AT_explicit 0x63 #define DW_AT_object_pointer 0x64 #define DW_AT_endianity 0x65 #define DW_AT_elemental 0x66 #define DW_AT_pure 0x67 #define DW_AT_recursive 0x68 #define DW_AT_signature 0x69 #define DW_AT_main_subprogram 0x6a #define DW_AT_data_bit_offset 0x6b #define DW_AT_const_expr 0x6c #define DW_AT_enum_class 0x6d #define DW_AT_linkage_name 0x6e #define DW_AT_lo_user 0x2000 #define DW_AT_hi_user 0x3fff +/* GNU extensions. */ +#define DW_AT_sf_names 0x2101 +#define DW_AT_src_info 0x2102 +#define DW_AT_mac_info 0x2103 +#define DW_AT_src_coords 0x2104 +#define DW_AT_body_begin 0x2105 +#define DW_AT_body_end 0x2106 +#define DW_AT_GNU_vector 0x2107 +#define DW_AT_GNU_guarded_by 0x2108 +#define DW_AT_GNU_pt_guarded_by 0x2109 +#define DW_AT_GNU_guarded 0x210a +#define DW_AT_GNU_pt_guarded 0x210b +#define DW_AT_GNU_locks_excluded 0x210c +#define DW_AT_GNU_exclusive_locks_required 0x210d +#define DW_AT_GNU_shared_locks_required 0x210e +#define DW_AT_GNU_odr_signature 0x210f +#define DW_AT_GNU_template_name 0x2110 +#define DW_AT_GNU_call_site_value 0x2111 +#define DW_AT_GNU_call_site_data_value 0x2112 +#define DW_AT_GNU_call_site_target 0x2113 +#define DW_AT_GNU_call_site_target_clobbered 0x2114 +#define DW_AT_GNU_tail_call 0x2115 +#define DW_AT_GNU_all_tail_call_sites 0x2116 +#define DW_AT_GNU_all_call_sites 0x2117 +#define DW_AT_GNU_all_source_call_sites 0x2118 + #define DW_FORM_addr 0x01 #define DW_FORM_block2 0x03 #define DW_FORM_block4 0x04 #define DW_FORM_data2 0x05 #define DW_FORM_data4 0x06 #define DW_FORM_data8 0x07 #define DW_FORM_string 0x08 #define DW_FORM_block 0x09 #define DW_FORM_block1 0x0a #define DW_FORM_data1 0x0b #define DW_FORM_flag 0x0c #define DW_FORM_sdata 0x0d #define DW_FORM_strp 0x0e #define DW_FORM_udata 0x0f #define DW_FORM_ref_addr 0x10 #define DW_FORM_ref1 0x11 #define DW_FORM_ref2 0x12 #define DW_FORM_ref4 0x13 #define DW_FORM_ref8 0x14 #define DW_FORM_ref_udata 0x15 #define DW_FORM_indirect 0x16 #define DW_FORM_sec_offset 0x17 #define DW_FORM_exprloc 0x18 #define DW_FORM_flag_present 0x19 #define DW_FORM_ref_sig8 0x20 +#define DW_FORM_GNU_ref_alt 0x1f20 +#define DW_FORM_GNU_strp_alt 0x1f21 #define DW_OP_addr 0x03 #define DW_OP_deref 0x06 #define DW_OP_const1u 0x08 #define DW_OP_const1s 0x09 #define DW_OP_const2u 0x0a #define DW_OP_const2s 0x0b #define DW_OP_const4u 0x0c #define DW_OP_const4s 0x0d #define DW_OP_const8u 0x0e #define DW_OP_const8s 0x0f #define DW_OP_constu 0x10 #define DW_OP_consts 0x11 #define DW_OP_dup 0x12 #define DW_OP_drop 0x13 #define DW_OP_over 0x14 #define DW_OP_pick 0x15 #define DW_OP_swap 0x16 #define DW_OP_rot 0x17 #define DW_OP_xderef 0x18 #define DW_OP_abs 0x19 #define DW_OP_and 0x1a #define DW_OP_div 0x1b #define DW_OP_minus 0x1c #define DW_OP_mod 0x1d #define DW_OP_mul 0x1e #define DW_OP_neg 0x1f #define DW_OP_not 0x20 #define DW_OP_or 0x21 #define DW_OP_plus 0x22 #define DW_OP_plus_uconst 0x23 #define DW_OP_shl 0x24 #define DW_OP_shr 0x25 #define DW_OP_shra 0x26 #define DW_OP_xor 0x27 #define DW_OP_bra 0x28 #define DW_OP_eq 0x29 #define DW_OP_ge 0x2a #define DW_OP_gt 0x2b #define DW_OP_le 0x2c #define DW_OP_lt 0x2d #define DW_OP_ne 0x2e #define DW_OP_skip 0x2f #define DW_OP_lit0 0x30 #define DW_OP_lit1 0x31 #define DW_OP_lit2 0x32 #define DW_OP_lit3 0x33 #define DW_OP_lit4 0x34 #define DW_OP_lit5 0x35 #define DW_OP_lit6 0x36 #define DW_OP_lit7 0x37 #define DW_OP_lit8 0x38 #define DW_OP_lit9 0x39 #define DW_OP_lit10 0x3a #define DW_OP_lit11 0x3b #define DW_OP_lit12 0x3c #define DW_OP_lit13 0x3d #define DW_OP_lit14 0x3e #define DW_OP_lit15 0x3f #define DW_OP_lit16 0x40 #define DW_OP_lit17 0x41 #define DW_OP_lit18 0x42 #define DW_OP_lit19 0x43 #define DW_OP_lit20 0x44 #define DW_OP_lit21 0x45 #define DW_OP_lit22 0x46 #define DW_OP_lit23 0x47 #define DW_OP_lit24 0x48 #define DW_OP_lit25 0x49 #define DW_OP_lit26 0x4a #define DW_OP_lit27 0x4b #define DW_OP_lit28 0x4c #define DW_OP_lit29 0x4d #define DW_OP_lit30 0x4e #define DW_OP_lit31 0x4f #define DW_OP_reg0 0x50 #define DW_OP_reg1 0x51 #define DW_OP_reg2 0x52 #define DW_OP_reg3 0x53 #define DW_OP_reg4 0x54 #define DW_OP_reg5 0x55 #define DW_OP_reg6 0x56 #define DW_OP_reg7 0x57 #define DW_OP_reg8 0x58 #define DW_OP_reg9 0x59 #define DW_OP_reg10 0x5a #define DW_OP_reg11 0x5b #define DW_OP_reg12 0x5c #define DW_OP_reg13 0x5d #define DW_OP_reg14 0x5e #define DW_OP_reg15 0x5f #define DW_OP_reg16 0x60 #define DW_OP_reg17 0x61 #define DW_OP_reg18 0x62 #define DW_OP_reg19 0x63 #define DW_OP_reg20 0x64 #define DW_OP_reg21 0x65 #define DW_OP_reg22 0x66 #define DW_OP_reg23 0x67 #define DW_OP_reg24 0x68 #define DW_OP_reg25 0x69 #define DW_OP_reg26 0x6a #define DW_OP_reg27 0x6b #define DW_OP_reg28 0x6c #define DW_OP_reg29 0x6d #define DW_OP_reg30 0x6e #define DW_OP_reg31 0x6f #define DW_OP_breg0 0x70 #define DW_OP_breg1 0x71 #define DW_OP_breg2 0x72 #define DW_OP_breg3 0x73 #define DW_OP_breg4 0x74 #define DW_OP_breg5 0x75 #define DW_OP_breg6 0x76 #define DW_OP_breg7 0x77 #define DW_OP_breg8 0x78 #define DW_OP_breg9 0x79 #define DW_OP_breg10 0x7a #define DW_OP_breg11 0x7b #define DW_OP_breg12 0x7c #define DW_OP_breg13 0x7d #define DW_OP_breg14 0x7e #define DW_OP_breg15 0x7f #define DW_OP_breg16 0x80 #define DW_OP_breg17 0x81 #define DW_OP_breg18 0x82 #define DW_OP_breg19 0x83 #define DW_OP_breg20 0x84 #define DW_OP_breg21 0x85 #define DW_OP_breg22 0x86 #define DW_OP_breg23 0x87 #define DW_OP_breg24 0x88 #define DW_OP_breg25 0x89 #define DW_OP_breg26 0x8a #define DW_OP_breg27 0x8b #define DW_OP_breg28 0x8c #define DW_OP_breg29 0x8d #define DW_OP_breg30 0x8e #define DW_OP_breg31 0x8f #define DW_OP_regx 0x90 #define DW_OP_fbreg 0x91 #define DW_OP_bregx 0x92 #define DW_OP_piece 0x93 #define DW_OP_deref_size 0x94 #define DW_OP_xderef_size 0x95 #define DW_OP_nop 0x96 #define DW_OP_push_object_address 0x97 #define DW_OP_call2 0x98 #define DW_OP_call4 0x99 #define DW_OP_call_ref 0x9a #define DW_OP_form_tls_address 0x9b #define DW_OP_call_frame_cfa 0x9c #define DW_OP_bit_piece 0x9d #define DW_OP_implicit_value 0x9e #define DW_OP_stack_value 0x9f #define DW_OP_lo_user 0xe0 -#define DW_OP_GNU_push_tls_address 0xe0 #define DW_OP_hi_user 0xff +/* GNU extensions. */ +#define DW_OP_GNU_push_tls_address 0xe0 +#define DW_OP_GNU_uninit 0xf0 +#define DW_OP_GNU_encoded_addr 0xf1 +#define DW_OP_GNU_implicit_pointer 0xf2 +#define DW_OP_GNU_entry_value 0xf3 +#define DW_OP_GNU_const_type 0xf4 +#define DW_OP_GNU_regval_type 0xf5 +#define DW_OP_GNU_deref_type 0xf6 +#define DW_OP_GNU_convert 0xf7 +#define DW_OP_GNU_reinterpret 0xf9 +#define DW_OP_GNU_parameter_ref 0xfa +#define DW_OP_GNU_addr_index 0xfb +#define DW_OP_GNU_const_index 0xfc + #define DW_ATE_address 0x1 #define DW_ATE_boolean 0x2 #define DW_ATE_complex_float 0x3 #define DW_ATE_float 0x4 #define DW_ATE_signed 0x5 #define DW_ATE_signed_char 0x6 #define DW_ATE_unsigned 0x7 #define DW_ATE_unsigned_char 0x8 #define DW_ATE_imaginary_float 0x9 #define DW_ATE_packed_decimal 0xa #define DW_ATE_numeric_string 0xb #define DW_ATE_edited 0xc #define DW_ATE_signed_fixed 0xd #define DW_ATE_unsigned_fixed 0xe #define DW_ATE_decimal_float 0xf #define DW_ATE_lo_user 0x80 #define DW_ATE_hi_user 0xff #define DW_ACCESS_public 0x01 #define DW_ACCESS_protected 0x02 #define DW_ACCESS_private 0x03 #define DW_END_default 0x00 #define DW_END_big 0x01 #define DW_END_little 0x02 #define DW_END_lo_user 0x40 #define DW_END_high_user 0xff #define DW_VIS_local 0x01 #define DW_VIS_exported 0x02 #define DW_VIS_qualified 0x03 #define DW_VIRTUALITY_none 0x00 #define DW_VIRTUALITY_virtual 0x01 #define DW_VIRTUALITY_pure_virtual 0x02 #define DW_LANG_C89 0x0001 #define DW_LANG_C 0x0002 #define DW_LANG_Ada83 0x0003 #define DW_LANG_C_plus_plus 0x0004 #define DW_LANG_Cobol74 0x0005 #define DW_LANG_Cobol85 0x0006 #define DW_LANG_Fortran77 0x0007 #define DW_LANG_Fortran90 0x0008 #define DW_LANG_Pascal83 0x0009 #define DW_LANG_Modula2 0x000a #define DW_LANG_Java 0x000b #define DW_LANG_C99 0x000c #define DW_LANG_Ada95 0x000d #define DW_LANG_Fortran95 0x000e #define DW_LANG_PLI 0x000f #define DW_LANG_ObjC 0x0010 #define DW_LANG_ObjC_plus_plus 0x0011 #define DW_LANG_UPC 0x0012 #define DW_LANG_D 0x0013 #define DW_LANG_lo_user 0x8000 #define DW_LANG_hi_user 0xffff #define DW_ID_case_sensitive 0x00 #define DW_ID_up_case 0x01 #define DW_ID_down_case 0x02 #define DW_ID_case_insensitive 0x03 #define DW_CC_normal 0x01 #define DW_CC_program 0x02 #define DW_CC_nocall 0x03 #define DW_CC_lo_user 0x40 #define DW_CC_hi_user 0xff #define DW_INL_not_inlined 0x00 #define DW_INL_inlined 0x01 #define DW_INL_declared_not_inlined 0x02 #define DW_INL_declared_inlined 0x03 #define DW_ORD_row_major 0x00 #define DW_ORD_col_major 0x01 #define DW_DS_unsigned 0x01 #define DW_DS_leading_overpunch 0x02 #define DW_DS_trailing_overpunch 0x03 #define DW_DS_leading_separate 0x04 #define DW_DS_trailing_separate 0x05 #define DW_DSC_label 0x00 #define DW_DSC_range 0x01 #define DW_LNS_copy 0x01 #define DW_LNS_advance_pc 0x02 #define DW_LNS_advance_line 0x03 #define DW_LNS_set_file 0x04 #define DW_LNS_set_column 0x05 #define DW_LNS_negate_stmt 0x06 #define DW_LNS_set_basic_block 0x07 #define DW_LNS_const_add_pc 0x08 #define DW_LNS_fixed_advance_pc 0x09 #define DW_LNS_set_prologue_end 0x0a #define DW_LNS_set_epilogue_begin 0x0b #define DW_LNS_set_isa 0x0c #define DW_LNE_end_sequence 0x01 #define DW_LNE_set_address 0x02 #define DW_LNE_define_file 0x03 #define DW_LNE_lo_user 0x80 #define DW_LNE_hi_user 0xff #define DW_MACINFO_define 0x01 #define DW_MACINFO_undef 0x02 #define DW_MACINFO_start_file 0x03 #define DW_MACINFO_end_file 0x04 #define DW_MACINFO_vendor_ext 0xff #define DW_CFA_advance_loc 0x40 #define DW_CFA_offset 0x80 #define DW_CFA_restore 0xc0 #define DW_CFA_extended 0 #define DW_CFA_nop 0x00 #define DW_CFA_set_loc 0x01 #define DW_CFA_advance_loc1 0x02 #define DW_CFA_advance_loc2 0x03 #define DW_CFA_advance_loc4 0x04 #define DW_CFA_offset_extended 0x05 #define DW_CFA_restore_extended 0x06 #define DW_CFA_undefined 0x07 #define DW_CFA_same_value 0x08 #define DW_CFA_register 0x09 #define DW_CFA_remember_state 0x0a #define DW_CFA_restore_state 0x0b #define DW_CFA_def_cfa 0x0c #define DW_CFA_def_cfa_register 0x0d #define DW_CFA_def_cfa_offset 0x0e #define DW_CFA_def_cfa_expression 0x0f #define DW_CFA_expression 0x10 #define DW_CFA_offset_extended_sf 0x11 #define DW_CFA_def_cfa_sf 0x12 #define DW_CFA_def_cfa_offset_sf 0x13 #define DW_CFA_val_offset 0x14 #define DW_CFA_val_offset_sf 0x15 #define DW_CFA_val_expression 0x16 #define DW_CFA_lo_user 0x1c #define DW_CFA_high_user 0x3f /* * LSB(Linux Standard Base) extension to DWARF2. */ #define DW_EH_PE_absptr 0x00 #define DW_EH_PE_uleb128 0x01 #define DW_EH_PE_udata2 0x02 #define DW_EH_PE_udata4 0x03 #define DW_EH_PE_udata8 0x04 #define DW_EH_PE_sleb128 0x09 #define DW_EH_PE_sdata2 0x0a #define DW_EH_PE_sdata4 0x0b #define DW_EH_PE_sdata8 0x0c #define DW_EH_PE_pcrel 0x10 #define DW_EH_PE_textrel 0x20 #define DW_EH_PE_datarel 0x30 #define DW_EH_PE_funcrel 0x40 #define DW_EH_PE_aligned 0x50 #define DW_EH_PE_omit 0xff #endif /* !_DWARF_H_ */ diff --git a/libdwarf/dwarf_attr.3 b/libdwarf/dwarf_attr.3 index b1e30017a89a..9ba367be5f69 100644 --- a/libdwarf/dwarf_attr.3 +++ b/libdwarf/dwarf_attr.3 @@ -1,119 +1,120 @@ .\" Copyright (c) 2010 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_attr.3 2072 2011-10-27 03:26:49Z jkoshy $ +.\" $Id: dwarf_attr.3 3093 2014-09-02 22:09:40Z kaiwang27 $ .\" .Dd April 8, 2010 .Os .Dt DWARF_ATTR 3 .Sh NAME .Nm dwarf_attr .Nd retrieve an attribute descriptor associated with a DWARF debugging information entry .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_attr .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Attribute *atp" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_attr retrieves the attribute descriptor for an attribute associated with the DWARF debugging information entry descriptor in argument .Ar die . .Pp DWARF attribute descriptors are represented by value of the opaque type .Vt Dwarf_Attribute , see .Xr dwarf 3 . .Pp Argument .Ar attr names the desired DWARF attribute. Legal values for argument .Ar attr are those denoted by the .Dv DW_AT_* constants in the DWARF specification. .Pp Argument .Ar atp points to a location into which the returned attribute descriptor will be written. The returned descriptor may then be passed to the form query functions in the .Xr dwarf 3 API set to access the data associated with the attribute. .Pp If argument .Ar err is non-NULL, it will be used to return an error descriptor in case of an error. .Sh RETURN VALUES Function .Fn dwarf_attr returns .Dv DW_DLV_OK on success. .Pp If the debugging information entry descriptor denoted by argument .Ar die does not contain the named attribute, the function returns .Dv DW_DLV_NO_ENTRY and sets argument .Ar err . For other errors, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . .Sh ERRORS Function .Fn dwarf_attr can fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Either of arguments .Ar die or .Ar atp was NULL. .It Bq Er DW_DLE_NO_ENTRY Argument .Ar die had no attribute corresponding to the value in argument .Ar attr . .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attrlist 3 , +.Xr dwarf_attroffset 3 , .Xr dwarf_hasattr 3 , .Xr dwarf_hasform 3 , .Xr dwarf_whatattr 3 , .Xr dwarf_whatform 3 diff --git a/libdwarf/dwarf_attr.c b/libdwarf/dwarf_attr.c index ce40294c6b12..a081d7b93a8f 100644 --- a/libdwarf/dwarf_attr.c +++ b/libdwarf/dwarf_attr.c @@ -1,275 +1,312 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * Copyright (c) 2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_attr.c 2072 2011-10-27 03:26:49Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_attr.c 3064 2014-06-06 19:35:55Z kaiwang27 $"); int dwarf_attr(Dwarf_Die die, Dwarf_Half attr, Dwarf_Attribute *atp, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_Attribute at; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || atp == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *atp = at; return (DW_DLV_OK); } int dwarf_attrlist(Dwarf_Die die, Dwarf_Attribute **attrbuf, Dwarf_Signed *attrcount, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; int i; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || attrbuf == NULL || attrcount == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (die->die_ab->ab_atnum == 0) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *attrcount = die->die_ab->ab_atnum; if (die->die_attrarray != NULL) { *attrbuf = die->die_attrarray; return (DW_DLV_OK); } if ((die->die_attrarray = malloc(*attrcount * sizeof(Dwarf_Attribute))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLV_ERROR); } for (i = 0, at = STAILQ_FIRST(&die->die_attr); i < *attrcount && at != NULL; i++, at = STAILQ_NEXT(at, at_next)) die->die_attrarray[i] = at; *attrbuf = die->die_attrarray; return (DW_DLV_OK); } int dwarf_hasattr(Dwarf_Die die, Dwarf_Half attr, Dwarf_Bool *ret_bool, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_bool == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_bool = (_dwarf_attr_find(die, attr) != NULL); return (DW_DLV_OK); } +int +dwarf_attroffset(Dwarf_Attribute at, Dwarf_Off *ret_off, Dwarf_Error *error) +{ + Dwarf_Debug dbg; + + dbg = at != NULL ? at->at_die->die_dbg : NULL; + + if (at == NULL || ret_off == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); + return (DW_DLV_ERROR); + } + + *ret_off = at->at_offset; + + return (DW_DLV_OK); +} + int dwarf_lowpc(Dwarf_Die die, Dwarf_Addr *ret_lowpc, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_lowpc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_low_pc)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_lowpc = at->u[0].u64; return (DW_DLV_OK); } int dwarf_highpc(Dwarf_Die die, Dwarf_Addr *ret_highpc, Dwarf_Error *error) +{ + + return (dwarf_highpc_b(die, ret_highpc, NULL, NULL, error)); +} + +int +dwarf_highpc_b(Dwarf_Die die, Dwarf_Addr *ret_highpc, Dwarf_Half *ret_form, + enum Dwarf_Form_Class *ret_class, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; + Dwarf_CU cu; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_highpc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_high_pc)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_highpc = at->u[0].u64; + if (ret_form != NULL) { + *ret_form = at->at_form; + } + + if (ret_class != NULL) { + cu = die->die_cu; + *ret_class = dwarf_get_form_class(cu->cu_version, + DW_AT_high_pc, cu->cu_length_size == 4 ? 4 : 8, + at->at_form); + } + return (DW_DLV_OK); } int dwarf_bytesize(Dwarf_Die die, Dwarf_Unsigned *ret_size, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_size == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_byte_size)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_size = at->u[0].u64; return (DW_DLV_OK); } int dwarf_bitsize(Dwarf_Die die, Dwarf_Unsigned *ret_size, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_size == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_bit_size)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_size = at->u[0].u64; return (DW_DLV_OK); } int dwarf_bitoffset(Dwarf_Die die, Dwarf_Unsigned *ret_size, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_size == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_bit_offset)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_size = at->u[0].u64; return (DW_DLV_OK); } int dwarf_srclang(Dwarf_Die die, Dwarf_Unsigned *ret_lang, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_lang == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_language)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_lang = at->u[0].u64; return (DW_DLV_OK); } int dwarf_arrayorder(Dwarf_Die die, Dwarf_Unsigned *ret_order, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_order == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_ordering)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_order = at->u[0].u64; return (DW_DLV_OK); } diff --git a/libdwarf/dwarf_attr.3 b/libdwarf/dwarf_attroffset.3 similarity index 50% copy from libdwarf/dwarf_attr.3 copy to libdwarf/dwarf_attroffset.3 index b1e30017a89a..af24cebab8e9 100644 --- a/libdwarf/dwarf_attr.3 +++ b/libdwarf/dwarf_attroffset.3 @@ -1,119 +1,86 @@ -.\" Copyright (c) 2010 Kai Wang +.\" Copyright (c) 2014 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_attr.3 2072 2011-10-27 03:26:49Z jkoshy $ +.\" $Id: dwarf_attroffset.3 3115 2014-12-20 18:26:46Z jkoshy $ .\" -.Dd April 8, 2010 +.Dd December 20, 2014 .Os -.Dt DWARF_ATTR 3 +.Dt DWARF_ATTROFFSET 3 .Sh NAME -.Nm dwarf_attr -.Nd retrieve an attribute descriptor associated with a DWARF debugging information entry +.Nm dwarf_attroffset +.Nd retrieve the section-relative offset of an attribute descriptor .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int -.Fo dwarf_attr -.Fa "Dwarf_Die die" -.Fa "Dwarf_Half attr" -.Fa "Dwarf_Attribute *atp" +.Fo dwarf_attroffset +.Fa "Dwarf_Attribute at" +.Fa "Dwarf_Off *ret_off" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function -.Fn dwarf_attr -retrieves the attribute descriptor for an attribute associated -with the DWARF debugging information entry descriptor in -argument -.Ar die . -.Pp -DWARF attribute descriptors are represented by value of the opaque -type -.Vt Dwarf_Attribute , -see -.Xr dwarf 3 . -.Pp -Argument -.Ar attr -names the desired DWARF attribute. -Legal values for argument -.Ar attr -are those denoted by the -.Dv DW_AT_* -constants in the DWARF specification. +.Fn dwarf_attroffset +retrieves the section-relative offset of the attribute descriptor +referenced by argument +.Ar at . .Pp Argument -.Ar atp -points to a location into which the returned attribute descriptor -will be written. -The returned descriptor may then be passed to the form query functions in the -.Xr dwarf 3 -API set to access the data associated with the attribute. -.Pp +.Ar ret_off +should point to a location that is to hold the returned +section-relative offset. If argument .Ar err -is non-NULL, it will be used to return an error descriptor in case -of an error. +is non-NULL, it is used to return an error descriptor in case of an +error. .Sh RETURN VALUES -Function -.Fn dwarf_attr +On success, function +.Fn dwarf_attroffset returns -.Dv DW_DLV_OK on success. +.Dv DW_DLV_OK . .Pp -If the debugging information entry descriptor denoted by argument -.Ar die -does not contain the named attribute, the function returns -.Dv DW_DLV_NO_ENTRY -and sets argument -.Ar err . -For other errors, it returns +In case of an error, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . +.Sh COMPATIBILITY +This function is an extension to the +.Xr DWARF 3 +API. .Sh ERRORS -Function -.Fn dwarf_attr -can fail with the following errors: +The +.Fn dwarf_attroffset +function may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT -Either of arguments -.Ar die +Either of the arguments +.Ar at or -.Ar atp +.Ar ret_off was NULL. -.It Bq Er DW_DLE_NO_ENTRY -Argument -.Ar die -had no attribute corresponding to the value -in argument -.Ar attr . .El .Sh SEE ALSO .Xr dwarf 3 , -.Xr dwarf_attrlist 3 , -.Xr dwarf_hasattr 3 , -.Xr dwarf_hasform 3 , -.Xr dwarf_whatattr 3 , -.Xr dwarf_whatform 3 +.Xr dwarf_attr 3 diff --git a/libdwarf/dwarf_attrval.c b/libdwarf/dwarf_attrval.c index 0f17016ad810..3bddae9eceff 100644 --- a/libdwarf/dwarf_attrval.c +++ b/libdwarf/dwarf_attrval.c @@ -1,210 +1,211 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_attrval.c 2072 2011-10-27 03:26:49Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_attrval.c 2977 2014-01-21 20:13:31Z kaiwang27 $"); int dwarf_attrval_flag(Dwarf_Die die, Dwarf_Half attr, Dwarf_Bool *valp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || valp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *valp = 0; if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_flag: + case DW_FORM_flag_present: *valp = (Dwarf_Bool) (!!at->u[0].u64); break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } return (DW_DLV_OK); } int dwarf_attrval_string(Dwarf_Die die, Dwarf_Half attr, const char **strp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || strp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *strp = NULL; if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_strp: *strp = at->u[1].s; break; case DW_FORM_string: *strp = at->u[0].s; break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } return (DW_DLV_OK); } int dwarf_attrval_signed(Dwarf_Die die, Dwarf_Half attr, Dwarf_Signed *valp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || valp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *valp = 0; if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_data1: *valp = (int8_t) at->u[0].s64; break; case DW_FORM_data2: *valp = (int16_t) at->u[0].s64; break; case DW_FORM_data4: *valp = (int32_t) at->u[0].s64; case DW_FORM_data8: case DW_FORM_sdata: *valp = at->u[0].s64; break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } return (DW_DLV_OK); } int dwarf_attrval_unsigned(Dwarf_Die die, Dwarf_Half attr, Dwarf_Unsigned *valp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Die die1; Dwarf_Unsigned val; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || valp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *valp = 0; if ((at = _dwarf_attr_find(die, attr)) == NULL && attr != DW_AT_type) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } die1 = NULL; if (at == NULL && (at = _dwarf_attr_find(die, DW_AT_abstract_origin)) != NULL) { switch (at->at_form) { case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: val = at->u[0].u64; if ((die1 = _dwarf_die_find(die, val)) == NULL || (at = _dwarf_attr_find(die1, attr)) == NULL) { if (die1 != NULL) dwarf_dealloc(dbg, die1, DW_DLA_DIE); DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } } switch (at->at_form) { case DW_FORM_addr: case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_udata: case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: *valp = at->u[0].u64; break; default: if (die1 != NULL) dwarf_dealloc(dbg, die1, DW_DLA_DIE); DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } if (die1 != NULL) dwarf_dealloc(dbg, die1, DW_DLA_DIE); return (DW_DLV_OK); } diff --git a/libdwarf/dwarf_attrval_signed.3 b/libdwarf/dwarf_attrval_signed.3 index 9646990fc2de..93d4ae0596ed 100644 --- a/libdwarf/dwarf_attrval_signed.3 +++ b/libdwarf/dwarf_attrval_signed.3 @@ -1,205 +1,220 @@ .\" Copyright (c) 2011 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_attrval_signed.3 2072 2011-10-27 03:26:49Z jkoshy $ +.\" $Id: dwarf_attrval_signed.3 2980 2014-01-21 20:15:54Z kaiwang27 $ .\" -.Dd January 29, 2011 +.Dd January 18, 2014 .Os .Dt DWARF_ATTRVAL_SIGNED 3 .Sh NAME .Nm dwarf_attrval_flag , .Nm dwarf_attrval_signed , .Nm dwarf_attrval_string , .Nm dwarf_attrval_unsigned .Nd retrieve the value of an attribute within a DWARF debugging information entry .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_attrval_flag .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Bool *ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_attrval_signed .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Signed *ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_attrval_string .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "const char **ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_attrval_unsigned .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Unsigned *ret" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION These functions search the debugging information entry referenced by argument .Ar die for the attribute named by argument .Ar attr . If the named attribute is found, the functions set the location pointed to by argument .Ar ret to the value of the attribute. The argument .Ar err , if non NULL, will be used to return an error descriptor in case of an error. .Pp Function .Fn dwarf_attrval_flag sets the location pointed to by argument .Ar ret -to 1 if the attribute named by argument +to either 0 or 1. If the form of the attribute named by argument .Ar attr -has a non-zero value, or to 0 otherwise. -The form of the attribute named by argument +is +.Dv DW_FORM_flag , +function +.Fn dwarf_attrval_flag +sets the location pointed to by argument +.Ar ret +to 1 if the attribute has a non-zero value, or to 0 otherwise. +If the form of the attribute named by argument .Ar attr -must be -.Dv DW_FORM_flag . +is +.Dv DW_FORM_flag_present , +function +.Fn dwarf_attrval_flag +unconditionally sets the location pointed to by argument +.Ar ret +to 1. +The form of the attribute must be one of +.Dv DW_FORM_flag +or +.Dv DW_FORM_flag_present . .Pp Function .Fn dwarf_attrval_signed stores the value for the attribute named by argument .Ar attr , into the location pointed to by argument .Ar ret . The attribute's value is treated as a signed integral quantity and is sign-extended as needed. The attribute named by the argument .Ar attr must belong to the .Dv CONSTANT class and must have one of the following forms: .Dv DW_FORM_data1 , .Dv DW_FORM_data2 , .Dv DW_FORM_data4 , .Dv DW_FORM_data8 or .Dv DW_FORM_sdata . .Pp Function .Fn dwarf_attrval_string sets the location pointed to by argument .Ar ret to a pointer to a NUL-terminated string that is the value of the attribute named by argument .Ar attr . The form of the attribute must be one of .Dv DW_FORM_string or -.Dv DW_FORM_strp . +.Dv DW_FORM_strp . .Pp Function .Fn dwarf_attrval_unsigned stores the value for the attribute named by argument .Ar attr into the location pointed to by argument .Ar ret . The attribute's value is treated as an unsigned integral quantity, and is zero-extended as needed. The named attribute must belong to one of the .Dv CONSTANT , .Dv ADDRESS or .Dv REFERENCE classes and must have one of the following forms: .Dv DW_FORM_addr , .Dv DW_FORM_data1 , .Dv DW_FORM_data2 , .Dv DW_FORM_data4 , .Dv DW_FORM_data8 , .Dv DW_FORM_udata , .Dv DW_FORM_ref1 , .Dv DW_FORM_ref2 , .Dv DW_FORM_ref4 , .Dv DW_FORM_ref8 , or .Dv DW_FORM_ref_udata . .Pp If the attribute named by argument .Ar attr is not present in the debugging information entry referenced by argument .Ar die , and if a .Dv DW_AT_abstract_origin attribute is present in the debugging information entry, function .Fn dwarf_attrval_unsigned will search for the named attribute in the debugging information entry referenced by the .Dv DW_AT_abstract_origin attribute. .Sh RETURN VALUES On success, these functions returns .Dv DW_DLV_OK . If the named attribute was not found in the specified debugging information entry descriptor these functions return .Dv DW_DLV_NO_ENTRY and set argument .Ar err . For other errors, these functions return .Dv DW_DLV_ERROR and set argument .Ar err . .Sh COMPATIBILITY These functions are extensions added by this implementation of the DWARF(3) API. .Sh ERRORS These functions may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ATTR_FORM_BAD" .It Bq Er DW_DLE_ARGUMENT Either of the arguments .Va die or .Va ret was NULL. .It Bq Er DW_DLE_NO_ENTRY Argument .Ar die did not contain an attribute corresponding to the value in argument .Ar attr . .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute named by argument .Ar attr was not of a permitted form. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_hasattr 3 diff --git a/libdwarf/dwarf_child.3 b/libdwarf/dwarf_child.3 index 57549c01c66e..1e32e58d4451 100644 --- a/libdwarf/dwarf_child.3 +++ b/libdwarf/dwarf_child.3 @@ -1,202 +1,278 @@ -.\" Copyright (c) 2010 Kai Wang +.\" Copyright (c) 2010,2014 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_child.3 2122 2011-11-09 15:35:14Z jkoshy $ +.\" $Id: dwarf_child.3 3127 2014-12-21 19:09:19Z jkoshy $ .\" -.Dd November 9, 2011 +.Dd December 21, 2014 .Os .Dt DWARF_CHILD 3 .Sh NAME .Nm dwarf_child , +.Nm dwarf_offdie , +.Nm dwarf_offdie_b , .Nm dwarf_siblingof , -.Nm dwarf_offdie +.Nm dwarf_siblingof_b .Nd retrieve DWARF Debugging Information Entry descriptors .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fn dwarf_child "Dwarf_Die die" "Dwarf_Die *ret_die" "Dwarf_Error *err" .Ft int +.Fo dwarf_offdie +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Off offset" +.Fa "Dwarf_Die *ret_die" +.Fa "Dwarf_Error *err" +.Fc +.Ft int +.Fo dwarf_offdie_b +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Off offset" +.Fa "Dwarf_Bool is_info" +.Fa "Dwarf_Die *ret_die" +.Fa "Dwarf_Error *err" +.Fc +.Ft int .Fo dwarf_siblingof .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Die die" .Fa "Dwarf_Die *ret_die" .Fa "Dwarf_Error *err" .Fc .Ft int -.Fo dwarf_offdie +.Fo dwarf_siblingof_b .Fa "Dwarf_Debug dbg" -.Fa "Dwarf_Off offset" +.Fa "Dwarf_Die die" .Fa "Dwarf_Die *ret_die" +.Fa "Dwarf_Bool is_info" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION These functions are used to retrieve and traverse DWARF Debugging Information Entry (DIE) descriptors associated with a compilation unit. These descriptors are arranged in the form of a tree, traversable using .Dq child and .Dq sibling links; see .Xr dwarf 3 for more information. DWARF Debugging Information Entry descriptors are represented by the .Vt Dwarf_Die opaque type. .Pp Function .Fn dwarf_child retrieves the child of descriptor denoted by argument .Ar die , and stores it in the location pointed to by argument .Ar ret_die . .Pp Function .Fn dwarf_siblingof retrieves the sibling of the descriptor denoted by argument .Ar die , and stores it in the location pointed to by argument .Ar ret_die . If argument .Ar die is NULL, the first debugging information entry descriptor for the current compilation unit will be returned. This function and function .Fn dwarf_child may be used together to traverse the tree of debugging information entry descriptors for a compilation unit. .Pp Function +.Fn dwarf_siblingof_b +is identical to the function +.Fn dwarf_siblingof +except that it can retrieve the sibling descriptor from either the +current compilation unit or type unit. +If argument +.Ar is_info +is non-zero, the function behaves identically to function +.Fn dwarf_siblingof . +If argument +.Ar is_info +is zero, the descriptor referred by argument +.Ar die +should be associated with a debugging information entry in the +type unit. +The function will store the sibling of the descriptor in the location +pointed to by argument +.Ar ret_die . +If argument +.Ar is_info +is zero and argument +.Ar die +is +.Dv NULL , +the first debugging information entry descriptor for the +current type unit will be returned. +.Pp +Function .Fn dwarf_offdie retrieves the debugging information entry descriptor at global offset .Ar offset in the .Dq .debug_info section of the object associated with argument .Ar dbg . The returned descriptor is written to the location pointed to by argument .Ar ret_die . +.Pp +Function +.Fn dwarf_offdie_b +is identical to the function +.Fn dwarf_offdie +except that it can retrieve the debugging information entry descriptor at +global offset +.Ar offset +from either of the +.Dq .debug_info +and +.Dq .debug_types +sections of the object associated with argument +.Ar dbg . +If argument +.Ar is_info +is non-zero, the function will retrieve the debugging information +entry from the +.Dq .debug_info +section, otherwise the function will retrieve the debugging +information entry from the +.Dq .debug_types +section. +The returned descriptor is written to the location pointed to by argument +.Ar ret_die . .Ss Memory Management The memory area used for the .Vt Dwarf_Die descriptor returned in argument .Ar ret_die is allocated by the .Lb libdwarf . Application code should use function .Fn dwarf_dealloc with the allocation type .Dv DW_DLA_DIE to free the memory area when the .Vt Dwarf_Die descriptor is no longer needed. .Sh RETURN VALUES These functions return the following values: .Bl -tag -width ".Bq Er DW_DLV_NO_ENTRY" .It Bq Er DW_DLV_OK The call succeeded. .It Bq Er DW_DLV_ERROR The requested operation failed. Additional information about the error encountered will be recorded in argument .Ar err , if it is not NULL. .It Bq Er DW_DLV_NO_ENTRY For functions -.Fn dwarf_child +.Fn dwarf_child , +.Fn dwarf_siblingof and -.Fn dwarf_siblingof , +.Fn dwarf_siblingof_b , the descriptor denoted by argument .Ar die did not have a child or sibling. -For function -.Fn dwarf_offdie , +.Pp +For functions +.Fn dwarf_offdie +and +.Fn dwarf_offdie_b , there was no debugging information entry at the offset specified by argument .Ar offset . .El .Sh ERRORS These functions may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_DIE_NO_CU_CONTEXT" .It Bq Er DW_DLE_ARGUMENT Arguments .Ar dbg , .Ar die or .Ar ret_die were NULL. .It Bq Er DW_DLE_DIE_NO_CU_CONTEXT Argument .Ar dbg was not associated with a compilation unit. .It Bq Er DW_DLE_NO_ENTRY The descriptor denoted by argument .Ar die had no child or sibling, or there was no DWARF debugging information entry at the offset specified by argument .Va offset . .El .Sh EXAMPLES To retrieve the first DWARF Debugging Information Entry descriptor for the first compilation unit associated with a .Vt Dwarf_Debug instance, and to traverse all its children, use: .Bd -literal -offset indent Dwarf_Debug dbg; Dwarf_Die die, die0; Dwarf_Error de; \&... allocate dbg using dwarf_init() etc ... if (dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", dwarf_errmsg(de)); /* Get the first DIE for the current compilation unit. */ die = NULL; if (dwarf_siblingof(dbg, die, &die0, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de)); /* Get the first child of this DIE. */ die = die0; if (dwarf_child(die, &die0, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de)); /* Get the rest of children. */ do { die = die0; if (dwarf_siblingof(dbg, die, &die0, &de) == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de)); } while (die0 != NULL); .Ed .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_errmsg 3 , +.Xr dwarf_get_die_infotypes_flag.3 , .Xr dwarf_next_cu_header 3 diff --git a/libdwarf/dwarf_cu.c b/libdwarf/dwarf_cu.c index c203dc2f1fc7..d103488d1098 100644 --- a/libdwarf/dwarf_cu.c +++ b/libdwarf/dwarf_cu.c @@ -1,99 +1,161 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * Copyright (c) 2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_cu.c 2072 2011-10-27 03:26:49Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_cu.c 3041 2014-05-18 15:11:03Z kaiwang27 $"); int -dwarf_next_cu_header_b(Dwarf_Debug dbg, Dwarf_Unsigned *cu_length, - Dwarf_Half *cu_version, Dwarf_Off *cu_abbrev_offset, - Dwarf_Half *cu_pointer_size, Dwarf_Half *cu_offset_size, - Dwarf_Half *cu_extension_size, Dwarf_Unsigned *cu_next_offset, - Dwarf_Error *error) +dwarf_next_cu_header_c(Dwarf_Debug dbg, Dwarf_Bool is_info, + Dwarf_Unsigned *cu_length, Dwarf_Half *cu_version, + Dwarf_Off *cu_abbrev_offset, Dwarf_Half *cu_pointer_size, + Dwarf_Half *cu_offset_size, Dwarf_Half *cu_extension_size, + Dwarf_Sig8 *type_signature, Dwarf_Unsigned *type_offset, + Dwarf_Unsigned *cu_next_offset, Dwarf_Error *error) { Dwarf_CU cu; int ret; if (dbg == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } - if (dbg->dbg_cu_current == NULL) - ret = _dwarf_info_first_cu(dbg, error); - else - ret = _dwarf_info_next_cu(dbg, error); + if (is_info) { + if (dbg->dbg_cu_current == NULL) + ret = _dwarf_info_first_cu(dbg, error); + else + ret = _dwarf_info_next_cu(dbg, error); + } else { + if (dbg->dbg_tu_current == NULL) + ret = _dwarf_info_first_tu(dbg, error); + else + ret = _dwarf_info_next_tu(dbg, error); + } if (ret == DW_DLE_NO_ENTRY) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } else if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); - if (dbg->dbg_cu_current == NULL) { - DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); - return (DW_DLV_NO_ENTRY); + if (is_info) { + if (dbg->dbg_cu_current == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); + } + cu = dbg->dbg_cu_current; + } else { + if (dbg->dbg_tu_current == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); + } + cu = dbg->dbg_tu_current; } - cu = dbg->dbg_cu_current; if (cu_length) *cu_length = cu->cu_length; if (cu_version) *cu_version = cu->cu_version; if (cu_abbrev_offset) *cu_abbrev_offset = (Dwarf_Off) cu->cu_abbrev_offset; if (cu_pointer_size) *cu_pointer_size = cu->cu_pointer_size; if (cu_offset_size) { if (cu->cu_length_size == 4) *cu_offset_size = 4; else *cu_offset_size = 8; } if (cu_extension_size) { if (cu->cu_length_size == 4) *cu_extension_size = 0; else *cu_extension_size = 4; } if (cu_next_offset) - *cu_next_offset = dbg->dbg_cu_current->cu_next_offset; + *cu_next_offset = cu->cu_next_offset; + + if (!is_info) { + if (type_signature) + *type_signature = cu->cu_type_sig; + if (type_offset) + *type_offset = cu->cu_type_offset; + } return (DW_DLV_OK); } + +int +dwarf_next_cu_header_b(Dwarf_Debug dbg, Dwarf_Unsigned *cu_length, + Dwarf_Half *cu_version, Dwarf_Off *cu_abbrev_offset, + Dwarf_Half *cu_pointer_size, Dwarf_Half *cu_offset_size, + Dwarf_Half *cu_extension_size, Dwarf_Unsigned *cu_next_offset, + Dwarf_Error *error) +{ + + return (dwarf_next_cu_header_c(dbg, 1, cu_length, cu_version, + cu_abbrev_offset, cu_pointer_size, cu_offset_size, + cu_extension_size, NULL, NULL, cu_next_offset, error)); +} + int dwarf_next_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned *cu_length, Dwarf_Half *cu_version, Dwarf_Off *cu_abbrev_offset, Dwarf_Half *cu_pointer_size, Dwarf_Unsigned *cu_next_offset, Dwarf_Error *error) { return (dwarf_next_cu_header_b(dbg, cu_length, cu_version, cu_abbrev_offset, cu_pointer_size, NULL, NULL, cu_next_offset, error)); } + +int +dwarf_next_types_section(Dwarf_Debug dbg, Dwarf_Error *error) +{ + + /* Free resource allocated for current .debug_types section. */ + _dwarf_type_unit_cleanup(dbg); + dbg->dbg_types_loaded = 0; + dbg->dbg_types_off = 0; + + /* Reset type unit pointer. */ + dbg->dbg_tu_current = NULL; + + /* Search for the next .debug_types section. */ + dbg->dbg_types_sec = _dwarf_find_next_types_section(dbg, + dbg->dbg_types_sec); + + if (dbg->dbg_types_sec == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); + } + + return (DW_DLV_OK); +} diff --git a/libdwarf/dwarf_die.c b/libdwarf/dwarf_die.c index b2b38403005f..de6351ac608f 100644 --- a/libdwarf/dwarf_die.c +++ b/libdwarf/dwarf_die.c @@ -1,335 +1,413 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) - * Copyright (c) 2009,2011 Kai Wang + * Copyright (c) 2009,2011,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_die.c 2073 2011-10-27 03:30:47Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_die.c 3039 2014-05-18 15:10:56Z kaiwang27 $"); int dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *error) { Dwarf_Debug dbg; + Dwarf_Section *ds; Dwarf_CU cu; int ret; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_die == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (die->die_ab->ab_children == DW_CHILDREN_no) - return (DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); dbg = die->die_dbg; cu = die->die_cu; - ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu, - cu->cu_dwarf_size, die->die_next_off, cu->cu_next_offset, - ret_die, 0, error); + ds = cu->cu_is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; + ret = _dwarf_die_parse(die->die_dbg, ds, cu, cu->cu_dwarf_size, + die->die_next_off, cu->cu_next_offset, ret_die, 0, error); if (ret == DW_DLE_NO_ENTRY) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } else if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); return (DW_DLV_OK); } int -dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die, - Dwarf_Error *error) +dwarf_siblingof_b(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die, + Dwarf_Bool is_info, Dwarf_Error *error) { Dwarf_CU cu; Dwarf_Attribute at; + Dwarf_Section *ds; uint64_t offset; int ret, search_sibling; if (dbg == NULL || ret_die == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } - if ((cu = dbg->dbg_cu_current) == NULL) { + ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; + cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current; + + if (cu == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); return (DW_DLV_ERROR); } /* Application requests the first DIE in this CU. */ if (die == NULL) - return (dwarf_offdie(dbg, cu->cu_1st_offset, ret_die, - error)); + return (dwarf_offdie_b(dbg, cu->cu_1st_offset, is_info, + ret_die, error)); + + /* + * Check if the `is_info' flag matches the debug section the + * DIE belongs to. + */ + if (is_info != die->die_cu->cu_is_info) { + DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); + return (DW_DLV_ERROR); + } /* * If the DIE doesn't have any children, its sibling sits next * right to it. */ search_sibling = 0; if (die->die_ab->ab_children == DW_CHILDREN_no) offset = die->die_next_off; else { /* * Look for DW_AT_sibling attribute for the offset of * its sibling. */ if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) { if (at->at_form != DW_FORM_ref_addr) offset = at->u[0].u64 + cu->cu_offset; else offset = at->u[0].u64; } else { offset = die->die_next_off; search_sibling = 1; } } - ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu, - cu->cu_dwarf_size, offset, cu->cu_next_offset, ret_die, - search_sibling, error); + ret = _dwarf_die_parse(die->die_dbg, ds, cu, cu->cu_dwarf_size, offset, + cu->cu_next_offset, ret_die, search_sibling, error); if (ret == DW_DLE_NO_ENTRY) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } else if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); return (DW_DLV_OK); } + +int +dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die, + Dwarf_Error *error) +{ + + return (dwarf_siblingof_b(dbg, die, ret_die, 1, error)); +} + static int -_dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Off offset, - Dwarf_Die *ret_die, Dwarf_Error *error) +_dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_Section *s, Dwarf_CU cu, + Dwarf_Off offset, Dwarf_Die *ret_die, Dwarf_Error *error) { assert(dbg != NULL && cu != NULL && ret_die != NULL); - return (_dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size, + return (_dwarf_die_parse(dbg, s, cu, cu->cu_dwarf_size, offset, cu->cu_next_offset, ret_die, 0, error)); } int -dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die, - Dwarf_Error *error) +dwarf_offdie_b(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Bool is_info, + Dwarf_Die *ret_die, Dwarf_Error *error) { + Dwarf_Section *ds; Dwarf_CU cu; int ret; if (dbg == NULL || ret_die == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } + ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; + cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current; + /* First search the current CU. */ - if (dbg->dbg_cu_current != NULL) { - cu = dbg->dbg_cu_current; + if (cu != NULL) { if (offset > cu->cu_offset && offset < cu->cu_next_offset) { - ret = _dwarf_search_die_within_cu(dbg, cu, offset, + ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset, ret_die, error); if (ret == DW_DLE_NO_ENTRY) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } else if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); return (DW_DLV_OK); } } /* Search other CUs. */ - ret = _dwarf_info_load(dbg, 1, error); + ret = _dwarf_info_load(dbg, 1, is_info, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); - STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { - if (offset < cu->cu_offset || offset > cu->cu_next_offset) - continue; - ret = _dwarf_search_die_within_cu(dbg, cu, offset, - ret_die, error); - if (ret == DW_DLE_NO_ENTRY) { - DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); - return (DW_DLV_NO_ENTRY); - } else if (ret != DW_DLE_NONE) - return (DW_DLV_ERROR); - return (DW_DLV_OK); + if (is_info) { + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + if (offset < cu->cu_offset || + offset > cu->cu_next_offset) + continue; + ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset, + ret_die, error); + if (ret == DW_DLE_NO_ENTRY) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); + } else if (ret != DW_DLE_NONE) + return (DW_DLV_ERROR); + return (DW_DLV_OK); + } + } else { + STAILQ_FOREACH(cu, &dbg->dbg_tu, cu_next) { + if (offset < cu->cu_offset || + offset > cu->cu_next_offset) + continue; + ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset, + ret_die, error); + if (ret == DW_DLE_NO_ENTRY) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); + } else if (ret != DW_DLE_NONE) + return (DW_DLV_ERROR); + return (DW_DLV_OK); + } } DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } +int +dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die, + Dwarf_Error *error) +{ + + return (dwarf_offdie_b(dbg, offset, 1, ret_die, error)); +} + int dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || tag == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } assert(die->die_ab != NULL); *tag = (Dwarf_Half) die->die_ab->ab_tag; return (DW_DLV_OK); } int dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_offset == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_offset = die->die_offset; return (DW_DLV_OK); } int dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_CU cu; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_offset == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } cu = die->die_cu; assert(cu != NULL); *ret_offset = die->die_offset - cu->cu_offset; return (DW_DLV_OK); } int dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset, Dwarf_Off *cu_length, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_CU cu; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || cu_offset == NULL || cu_length == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } cu = die->die_cu; assert(cu != NULL); *cu_offset = cu->cu_offset; *cu_length = cu->cu_length + cu->cu_length_size; return (DW_DLV_OK); } int dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || ret_name == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (die->die_name == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_name = die->die_name; return (DW_DLV_OK); } int dwarf_die_abbrev_code(Dwarf_Die die) { assert(die != NULL); return (die->die_abnum); } int -dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, - Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset, - Dwarf_Error *error) +dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, Dwarf_Bool is_info, + Dwarf_Off *out_cu_die_offset, Dwarf_Error *error) { Dwarf_CU cu; if (dbg == NULL || out_cu_die_offset == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } - STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { - if (cu->cu_offset == in_cu_header_offset) { - *out_cu_die_offset = cu->cu_1st_offset; - break; + if (is_info) { + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + if (cu->cu_offset == in_cu_header_offset) { + *out_cu_die_offset = cu->cu_1st_offset; + break; + } + } + } else { + STAILQ_FOREACH(cu, &dbg->dbg_tu, cu_next) { + if (cu->cu_offset == in_cu_header_offset) { + *out_cu_die_offset = cu->cu_1st_offset; + break; + } } } if (cu == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } +int +dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset, + Dwarf_Error *error) +{ + + return (dwarf_get_cu_die_offset_given_cu_header_offset_b(dbg, + in_cu_header_offset, 1, out_cu_die_offset, error)); +} + int dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size, Dwarf_Error *error) { if (dbg == NULL || addr_size == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *addr_size = dbg->dbg_pointer_size; return (DW_DLV_OK); } + +Dwarf_Bool +dwarf_get_die_infotypes_flag(Dwarf_Die die) +{ + + assert(die != NULL); + + return (die->die_cu->cu_is_info); +} diff --git a/libdwarf/dwarf_dieoffset.3 b/libdwarf/dwarf_dieoffset.3 index 545bf2699c4d..00b0e71b8389 100644 --- a/libdwarf/dwarf_dieoffset.3 +++ b/libdwarf/dwarf_dieoffset.3 @@ -1,172 +1,206 @@ -.\" Copyright (c) 2010 Kai Wang +.\" Copyright (c) 2010,2014 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_dieoffset.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_dieoffset.3 3129 2014-12-21 20:06:26Z jkoshy $ .\" -.Dd April 17, 2010 +.Dd December 21, 2014 .Os .Dt DWARF_DIEOFFSET 3 .Sh NAME .Nm dwarf_die_CU_offset , .Nm dwarf_die_CU_offset_range , .Nm dwarf_dieoffset , -.Nm dwarf_get_cu_die_offset_given_cu_header_offset +.Nm dwarf_get_cu_die_offset_given_cu_header_offset , +.Nm dwarf_get_cu_die_offset_given_cu_header_offset_b .Nd return offsets of DWARF debugging information entries .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_die_CU_offset .Fa "Dwarf_Die die" .Fa "Dwarf_Off *ret_offset" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_die_CU_offset_range .Fa "Dwarf_Die die" .Fa "Dwarf_Off *cu_offset" .Fa "Dwarf_Off *cu_length" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_dieoffset .Fa "Dwarf_Die die" .Fa "Dwarf_Off *ret_offset" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_get_cu_die_offset_given_cu_header_offset .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Off in_cu_header_offset" .Fa "Dwarf_Off *out_cu_die_offset" .Fa "Dwarf_Error *err" .Fc +.Ft int +.Fo dwarf_get_cu_die_offset_given_cu_header_offset_b +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Off in_cu_header_offset" +.Fa "Dwarf_Bool is_info" +.Fa "Dwarf_Off *out_cu_die_offset" +.Fa "Dwarf_Error *err" +.Fc .Sh DESCRIPTION These functions are used to retrieve offsets for DWARF debugging information entries. .Pp Function .Fn dwarf_die_CU_offset returns the offset of the debugging information entry referenced by argument .Ar die relative to the start of its containing compilation unit. Argument .Ar ret_offset should point to the location that is to hold the returned offset. If argument .Ar err is non-NULL, it will be used to return an error descriptor in case of an error. .Pp Function .Fn dwarf_die_CU_offset_range returns the section-relative offset and length of the compilation unit containing the debugging information entry referenced by argument .Ar die . Argument .Ar cu_offset should point to a location that will hold the returned offset. Argument .Ar cu_length should point to a location that will hold the returned length of the compilation unit. If argument .Ar err is non-NULL, it will be used to return an error descriptor in case of an error. .Pp Function .Fn dwarf_dieoffset retrieves the section-relative offset of the debugging information entry referenced by argument .Ar die . Argument .Ar ret_offset should point to a location that is to hold the returned section-relative offset. If argument .Ar err is non-NULL, it will be used to return an error descriptor in case of an error. .Pp Function .Fn dwarf_get_cu_die_offset_given_cu_header_offset -returns the offset for the debugging information entry for a +returns the offset for the first debugging information entry for a compilation unit, given an offset to the header of the compilation unit. Argument .Ar dbg should reference a valid debugging context allocated using .Xr dwarf_init 3 . Argument .Ar in_cu_header_offset contains the offset to the start of a compilation unit. Argument .Ar out_cu_die_offset points to a location that will hold the returned offset. If argument .Ar err is non-NULL, it will be used to return an error descriptor in case of an error. +.Pp +Function +.Fn dwarf_get_cu_die_offset_given_cu_header_offset_b +behaves identically to the function +.Fn dwarf_get_cu_die_offset_given_cu_header_offset +when the argument +.Ar is_info +is non-zero. +When the argument +.Ar is_info +is zero, function +.Fn dwarf_get_cu_die_offset_given_cu_header_offset_b +returns the offset for the first debugging information entry for a +type unit, given an offset to the header of the type unit in argument +.Ar in_cu_header_offset . +Argument +.Ar out_cu_die_offset +points to a location that will hold the returned offset. +If the argument +.Ar err +is non-NULL, it will be used to return an error descriptor in case of +an error. .Sh RETURN VALUES -On success, these functions returns +On success, these functions return .Dv DW_DLV_OK . In case of an error, these functions return .Dv DW_DLV_ERROR and set argument .Ar err . .Pp Function .Fn dwarf_get_cu_die_offset_given_cu_header_offset +and +.Fn dwarf_get_cu_die_offset_given_cu_header_offset_b returns .Dv DW_DLV_NO_ENTRY and sets argument .Ar err -if there is no compilation unit located at the +if there is no compilation or type unit located at the offset specified in argument .Ar in_cu_header_offset . .Sh ERRORS These functions may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT One of the arguments .Va cu_length , .Va cu_offset , .Va dbg , .Va die , .Va out_cu_die_offset or .Va ret_offset was NULL. .It Bq Er DW_DLE_NO_ENTRY Argument .Ar in_cu_header_offset specified an unknown offset. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_next_cu_header 3 , -.Xr dwarf_offdie 3 +.Xr dwarf_offdie 3 , +.Xr dwarf_offdie_b 3 diff --git a/libdwarf/dwarf_dump.c b/libdwarf/dwarf_dump.c index 9b5d1f767e1a..3219fa4c0c6c 100644 --- a/libdwarf/dwarf_dump.c +++ b/libdwarf/dwarf_dump.c @@ -1,1292 +1,1384 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * Copyright (c) 2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_dump.c 2073 2011-10-27 03:30:47Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_dump.c 3052 2014-05-26 20:36:24Z kaiwang27 $"); int dwarf_get_ACCESS_name(unsigned access, const char **s) { assert(s != NULL); switch (access) { case DW_ACCESS_public: *s = "DW_ACCESS_public"; break; case DW_ACCESS_protected: *s = "DW_ACCESS_protected"; break; case DW_ACCESS_private: *s = "DW_ACCESS_private"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_AT_name(unsigned attr, const char **s) { assert(s != NULL); switch (attr) { case DW_AT_abstract_origin: *s = "DW_AT_abstract_origin"; break; case DW_AT_accessibility: *s = "DW_AT_accessibility"; break; case DW_AT_address_class: *s = "DW_AT_address_class"; break; case DW_AT_artificial: *s = "DW_AT_artificial"; break; case DW_AT_allocated: *s = "DW_AT_allocated"; break; case DW_AT_associated: *s = "DW_AT_associated"; break; case DW_AT_base_types: *s = "DW_AT_base_types"; break; case DW_AT_binary_scale: *s = "DW_AT_binary_scale"; break; case DW_AT_bit_offset: *s = "DW_AT_bit_offset"; break; case DW_AT_bit_size: *s = "DW_AT_bit_size"; break; case DW_AT_bit_stride: *s = "DW_AT_bit_stride"; break; case DW_AT_byte_size: *s = "DW_AT_byte_size"; break; case DW_AT_byte_stride: *s = "DW_AT_byte_stride"; break; case DW_AT_calling_convention: *s = "DW_AT_calling_convention"; break; case DW_AT_common_reference: *s = "DW_AT_common_reference"; break; case DW_AT_comp_dir: *s = "DW_AT_comp_dir"; break; case DW_AT_const_expr: *s = "DW_AT_const_expr"; break; case DW_AT_const_value: *s = "DW_AT_const_value"; break; case DW_AT_containing_type: *s = "DW_AT_containing_type"; break; case DW_AT_count: *s = "DW_AT_count"; break; case DW_AT_call_column: *s = "DW_AT_call_column"; break; case DW_AT_call_file: *s = "DW_AT_call_file"; break; case DW_AT_call_line: *s = "DW_AT_call_line"; break; case DW_AT_data_bit_offset: *s = "DW_AT_data_bit_offset"; break; case DW_AT_data_location: *s = "DW_AT_data_location"; break; case DW_AT_data_member_location: *s = "DW_AT_data_member_location"; break; case DW_AT_decl_column: *s = "DW_AT_decl_column"; break; case DW_AT_decl_file: *s = "DW_AT_decl_file"; break; case DW_AT_decl_line: *s = "DW_AT_decl_line"; break; case DW_AT_declaration: *s = "DW_AT_declaration"; break; case DW_AT_default_value: *s = "DW_AT_default_value"; break; case DW_AT_decimal_scale: *s = "DW_AT_decimal_scale"; break; case DW_AT_decimal_sign: *s = "DW_AT_decimal_sign"; break; case DW_AT_description: *s = "DW_AT_description"; break; case DW_AT_digit_count: *s = "DW_AT_digit_count"; break; case DW_AT_discr: *s = "DW_AT_discr"; break; case DW_AT_discr_list: *s = "DW_AT_discr_list"; break; case DW_AT_discr_value: *s = "DW_AT_discr_value"; break; case DW_AT_element_list: *s = "DW_AT_element_list"; break; case DW_AT_encoding: *s = "DW_AT_encoding"; break; case DW_AT_enum_class: *s = "DW_AT_enum_class"; break; case DW_AT_external: *s = "DW_AT_external"; break; case DW_AT_entry_pc: *s = "DW_AT_entry_pc"; break; case DW_AT_extension: *s = "DW_AT_extension"; break; case DW_AT_explicit: *s = "DW_AT_explicit"; break; case DW_AT_endianity: *s = "DW_AT_endianity"; break; case DW_AT_elemental: *s = "DW_AT_elemental"; break; case DW_AT_frame_base: *s = "DW_AT_frame_base"; break; case DW_AT_friend: *s = "DW_AT_friend"; break; case DW_AT_high_pc: *s = "DW_AT_high_pc"; break; case DW_AT_hi_user: *s = "DW_AT_hi_user"; break; case DW_AT_identifier_case: *s = "DW_AT_identifier_case"; break; case DW_AT_import: *s = "DW_AT_import"; break; case DW_AT_inline: *s = "DW_AT_inline"; break; case DW_AT_is_optional: *s = "DW_AT_is_optional"; break; case DW_AT_language: *s = "DW_AT_language"; break; case DW_AT_linkage_name: *s = "DW_AT_linkage_name"; break; case DW_AT_lo_user: *s = "DW_AT_lo_user"; break; case DW_AT_location: *s = "DW_AT_location"; break; case DW_AT_low_pc: *s = "DW_AT_low_pc"; break; case DW_AT_lower_bound: *s = "DW_AT_lower_bound"; break; case DW_AT_macro_info: *s = "DW_AT_macro_info"; break; case DW_AT_main_subprogram: *s = "DW_AT_main_subprogram"; break; case DW_AT_mutable: *s = "DW_AT_mutable"; break; case DW_AT_member: *s = "DW_AT_member"; break; case DW_AT_name: *s = "DW_AT_name"; break; case DW_AT_namelist_item: *s = "DW_AT_namelist_item"; break; case DW_AT_ordering: *s = "DW_AT_ordering"; break; case DW_AT_object_pointer: *s = "DW_AT_object_pointer"; break; case DW_AT_priority: *s = "DW_AT_priority"; break; case DW_AT_producer: *s = "DW_AT_producer"; break; case DW_AT_prototyped: *s = "DW_AT_prototyped"; break; case DW_AT_picture_string: *s = "DW_AT_picture_string"; break; case DW_AT_pure: *s = "DW_AT_pure"; break; case DW_AT_return_addr: *s = "DW_AT_return_addr"; break; case DW_AT_ranges: *s = "DW_AT_ranges"; break; case DW_AT_recursive: *s = "DW_AT_recursive"; break; case DW_AT_segment: *s = "DW_AT_segment"; break; case DW_AT_sibling: *s = "DW_AT_sibling"; break; case DW_AT_signature: *s = "DW_AT_signature"; break; case DW_AT_specification: *s = "DW_AT_specification"; break; case DW_AT_start_scope: *s = "DW_AT_start_scope"; break; case DW_AT_static_link: *s = "DW_AT_static_link"; break; case DW_AT_stmt_list: *s = "DW_AT_stmt_list"; break; case DW_AT_string_length: *s = "DW_AT_string_length"; break; case DW_AT_subscr_data: *s = "DW_AT_subscr_data"; break; case DW_AT_small: *s = "DW_AT_small"; break; case DW_AT_type: *s = "DW_AT_type"; break; case DW_AT_trampoline: *s = "DW_AT_trampoline"; break; case DW_AT_threads_scaled: *s = "DW_AT_threads_scaled"; break; case DW_AT_upper_bound: *s = "DW_AT_upper_bound"; break; case DW_AT_use_location: *s = "DW_AT_use_location"; break; case DW_AT_use_UTF8: *s = "DW_AT_use_UTF8"; break; case DW_AT_variable_parameter: *s = "DW_AT_variable_parameter"; break; case DW_AT_virtuality: *s = "DW_AT_virtuality"; break; case DW_AT_visibility: *s = "DW_AT_visibility"; break; case DW_AT_vtable_elem_location: *s = "DW_AT_vtable_elem_location"; break; + case DW_AT_sf_names: + *s = "DW_AT_sf_names"; break; + case DW_AT_src_info: + *s = "DW_AT_src_info"; break; + case DW_AT_mac_info: + *s = "DW_AT_mac_info"; break; + case DW_AT_src_coords: + *s = "DW_AT_src_coords"; break; + case DW_AT_body_begin: + *s = "DW_AT_body_begin"; break; + case DW_AT_body_end: + *s = "DW_AT_body_end"; break; + case DW_AT_GNU_vector: + *s = "DW_AT_GNU_vector"; break; + case DW_AT_GNU_guarded_by: + *s = "DW_AT_GNU_guarded_by"; break; + case DW_AT_GNU_pt_guarded_by: + *s = "DW_AT_GNU_pt_guarded_by"; break; + case DW_AT_GNU_guarded: + *s = "DW_AT_GNU_guarded"; break; + case DW_AT_GNU_pt_guarded: + *s = "DW_AT_GNU_pt_guarded"; break; + case DW_AT_GNU_locks_excluded: + *s = "DW_AT_GNU_locks_excluded"; break; + case DW_AT_GNU_exclusive_locks_required: + *s = "DW_AT_GNU_exclusive_locks_required"; break; + case DW_AT_GNU_shared_locks_required: + *s = "DW_AT_GNU_shared_locks_required"; break; + case DW_AT_GNU_odr_signature: + *s = "DW_AT_GNU_odr_signature"; break; + case DW_AT_GNU_template_name: + *s = "DW_AT_GNU_template_name"; break; + case DW_AT_GNU_call_site_value: + *s = "DW_AT_GNU_call_site_value"; break; + case DW_AT_GNU_call_site_data_value: + *s = "DW_AT_GNU_call_site_data_value"; break; + case DW_AT_GNU_call_site_target: + *s = "DW_AT_GNU_call_site_target"; break; + case DW_AT_GNU_call_site_target_clobbered: + *s = "DW_AT_GNU_call_site_target_clobbered"; break; + case DW_AT_GNU_tail_call: + *s = "DW_AT_GNU_tail_call"; break; + case DW_AT_GNU_all_tail_call_sites: + *s = "DW_AT_GNU_all_tail_call_sites"; break; + case DW_AT_GNU_all_call_sites: + *s = "DW_AT_GNU_all_call_sites"; break; + case DW_AT_GNU_all_source_call_sites: + *s = "DW_AT_GNU_all_source_call_sites"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_ATE_name(unsigned ate, const char **s) { assert(s != NULL); switch(ate) { case DW_ATE_address: *s = "DW_ATE_address"; break; case DW_ATE_boolean: *s = "DW_ATE_boolean"; break; case DW_ATE_complex_float: *s = "DW_ATE_complex_float"; break; case DW_ATE_float: *s = "DW_ATE_float"; break; case DW_ATE_signed: *s = "DW_ATE_signed"; break; case DW_ATE_signed_char: *s = "DW_ATE_signed_char"; break; case DW_ATE_unsigned: *s = "DW_ATE_unsigned"; break; case DW_ATE_unsigned_char: *s = "DW_ATE_unsigned_char"; break; case DW_ATE_imaginary_float: *s = "DW_ATE_imaginary_float"; break; case DW_ATE_packed_decimal: *s = "DW_ATE_packed_decimal"; break; case DW_ATE_numeric_string: *s = "DW_ATE_numeric_string"; break; case DW_ATE_edited: *s = "DW_ATE_edited"; break; case DW_ATE_signed_fixed: *s = "DW_ATE_signed_fixed"; break; case DW_ATE_unsigned_fixed: *s = "DW_ATE_unsigned_fixed"; break; case DW_ATE_decimal_float: *s = "DW_ATE_decimal_float"; break; case DW_ATE_lo_user: *s = "DW_ATE_lo_user"; break; case DW_ATE_hi_user: *s = "DW_ATE_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_CC_name(unsigned cc, const char **s) { assert(s != NULL); switch (cc) { case DW_CC_normal: *s = "DW_CC_normal"; break; case DW_CC_program: *s = "DW_CC_program"; break; case DW_CC_nocall: *s = "DW_CC_nocall"; break; case DW_CC_lo_user: *s = "DW_CC_lo_user"; break; case DW_CC_hi_user: *s = "DW_CC_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_CFA_name(unsigned cfa, const char **s) { assert(s != NULL); switch (cfa) { case DW_CFA_advance_loc: *s = "DW_CFA_advance_loc"; break; case DW_CFA_offset: *s = "DW_CFA_offset"; break; case DW_CFA_restore: *s = "DW_CFA_restore"; break; case DW_CFA_nop: *s = "DW_CFA_nop"; break; case DW_CFA_set_loc: *s = "DW_CFA_set_loc"; break; case DW_CFA_advance_loc1: *s = "DW_CFA_advance_loc1"; break; case DW_CFA_advance_loc2: *s = "DW_CFA_advance_loc2"; break; case DW_CFA_advance_loc4: *s = "DW_CFA_advance_loc4"; break; case DW_CFA_offset_extended: *s = "DW_CFA_offset_extended"; break; case DW_CFA_restore_extended: *s = "DW_CFA_restore_extended"; break; case DW_CFA_undefined: *s = "DW_CFA_undefined"; break; case DW_CFA_same_value: *s = "DW_CFA_same_value"; break; case DW_CFA_register: *s = "DW_CFA_register"; break; case DW_CFA_remember_state: *s = "DW_CFA_remember_state"; break; case DW_CFA_restore_state: *s = "DW_CFA_restore_state"; break; case DW_CFA_def_cfa: *s = "DW_CFA_def_cfa"; break; case DW_CFA_def_cfa_register: *s = "DW_CFA_def_cfa_register"; break; case DW_CFA_def_cfa_offset: *s = "DW_CFA_def_cfa_offset"; break; case DW_CFA_def_cfa_expression: *s = "DW_CFA_def_cfa_expression"; break; case DW_CFA_expression: *s = "DW_CFA_expression"; break; case DW_CFA_offset_extended_sf: *s = "DW_CFA_offset_extended_sf"; break; case DW_CFA_def_cfa_sf: *s = "DW_CFA_def_cfa_sf"; break; case DW_CFA_def_cfa_offset_sf: *s = "DW_CFA_def_cfa_offset_sf"; break; case DW_CFA_val_offset: *s = "DW_CFA_val_offset"; break; case DW_CFA_val_offset_sf: *s = "DW_CFA_val_offset_sf"; break; case DW_CFA_val_expression: *s = "DW_CFA_val_expression"; break; case DW_CFA_lo_user: *s = "DW_CFA_lo_user"; break; case DW_CFA_high_user: *s = "DW_CFA_high_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_CHILDREN_name(unsigned children, const char **s) { assert(s != NULL); switch (children) { case DW_CHILDREN_no: *s = "DW_CHILDREN_no"; break; case DW_CHILDREN_yes: *s = "DW_CHILDREN_yes"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_FORM_name(unsigned form, const char **s) { assert(s != NULL); switch (form) { case DW_FORM_addr: *s = "DW_FORM_addr"; break; case DW_FORM_block: *s = "DW_FORM_block"; break; case DW_FORM_block1: *s = "DW_FORM_block1"; break; case DW_FORM_block2: *s = "DW_FORM_block2"; break; case DW_FORM_block4: *s = "DW_FORM_block4"; break; case DW_FORM_data1: *s = "DW_FORM_data1"; break; case DW_FORM_data2: *s = "DW_FORM_data2"; break; case DW_FORM_data4: *s = "DW_FORM_data4"; break; case DW_FORM_data8: *s = "DW_FORM_data8"; break; case DW_FORM_exprloc: *s = "DW_FORM_exprloc"; break; case DW_FORM_flag: *s = "DW_FORM_flag"; break; case DW_FORM_flag_present: *s = "DW_FORM_flag_present"; break; case DW_FORM_indirect: *s = "DW_FORM_indirect"; break; case DW_FORM_ref1: *s = "DW_FORM_ref1"; break; case DW_FORM_ref2: *s = "DW_FORM_ref2"; break; case DW_FORM_ref4: *s = "DW_FORM_ref4"; break; case DW_FORM_ref8: *s = "DW_FORM_ref8"; break; case DW_FORM_ref_addr: *s = "DW_FORM_ref_addr"; break; case DW_FORM_ref_sig8: *s = "DW_FORM_ref_sig8"; break; case DW_FORM_ref_udata: *s = "DW_FORM_ref_udata"; break; case DW_FORM_sdata: *s = "DW_FORM_sdata"; break; case DW_FORM_sec_offset: *s = "DW_FORM_sec_offset"; break; case DW_FORM_string: *s = "DW_FORM_string"; break; case DW_FORM_strp: *s = "DW_FORM_strp"; break; case DW_FORM_udata: *s = "DW_FORM_udata"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_DS_name(unsigned ds, const char **s) { assert(s != NULL); switch (ds) { case DW_DS_unsigned: *s = "DW_DS_unsigned"; break; case DW_DS_leading_overpunch: *s = "DW_DS_leading_overpunch"; break; case DW_DS_trailing_overpunch: *s = "DW_DS_trailing_overpunch"; break; case DW_DS_leading_separate: *s = "DW_DS_leading_separate"; break; case DW_DS_trailing_separate: *s = "DW_DS_trailing_separate"; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_DSC_name(unsigned dsc, const char **s) { assert(s != NULL); switch (dsc) { case DW_DSC_label: *s = "DW_DSC_label"; break; case DW_DSC_range: *s = "DW_DSC_range"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_EH_name(unsigned eh, const char **s) { assert(s != NULL); switch (eh) { case DW_EH_PE_absptr: *s = "DW_EH_PE_absptr"; break; case DW_EH_PE_uleb128: *s = "DW_EH_PE_uleb128"; break; case DW_EH_PE_udata2: *s = "DW_EH_PE_udata2"; break; case DW_EH_PE_udata4: *s = "DW_EH_PE_udata4"; break; case DW_EH_PE_udata8: *s = "DW_EH_PE_udata8"; break; case DW_EH_PE_sleb128: *s = "DW_EH_PE_sleb128"; break; case DW_EH_PE_sdata2: *s = "DW_EH_PE_sdata2"; break; case DW_EH_PE_sdata4: *s = "DW_EH_PE_sdata4"; break; case DW_EH_PE_sdata8: *s = "DW_EH_PE_sdata8"; break; case DW_EH_PE_pcrel: *s = "DW_EH_PE_pcrel"; break; case DW_EH_PE_textrel: *s = "DW_EH_PE_textrel"; break; case DW_EH_PE_datarel: *s = "DW_EH_PE_datarel"; break; case DW_EH_PE_funcrel: *s = "DW_EH_PE_funcrel"; break; case DW_EH_PE_aligned: *s = "DW_EH_PE_aligned"; break; case DW_EH_PE_omit: *s = "DW_EH_PE_omit"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_END_name(unsigned end, const char **s) { assert(s != NULL); switch (end) { case DW_END_default: *s = "DW_END_default"; break; case DW_END_big: *s = "DW_END_big"; break; case DW_END_little: *s = "DW_END_little"; break; case DW_END_lo_user: *s = "DW_END_lo_user"; break; case DW_END_high_user: *s = "DW_END_high_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_ID_name(unsigned id, const char **s) { assert(s != NULL); switch (id) { case DW_ID_case_sensitive: *s = "DW_ID_case_sensitive"; break; case DW_ID_up_case: *s = "DW_ID_up_case"; break; case DW_ID_down_case: *s = "DW_ID_down_case"; break; case DW_ID_case_insensitive: *s = "DW_ID_case_insensitive"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_INL_name(unsigned inl, const char **s) { assert(s != NULL); switch (inl) { case DW_INL_not_inlined: *s = "DW_INL_not_inlined"; break; case DW_INL_inlined: *s = "DW_INL_inlined"; break; case DW_INL_declared_not_inlined: *s = "DW_INL_declared_not_inlined"; break; case DW_INL_declared_inlined: *s = "DW_INL_declared_inlined"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_LANG_name(unsigned lang, const char **s) { assert(s != NULL); switch (lang) { case DW_LANG_C89: *s = "DW_LANG_C89"; break; case DW_LANG_C: *s = "DW_LANG_C"; break; case DW_LANG_Ada83: *s = "DW_LANG_Ada83"; break; case DW_LANG_C_plus_plus: *s = "DW_LANG_C_plus_plus"; break; case DW_LANG_Cobol74: *s = "DW_LANG_Cobol74"; break; case DW_LANG_Cobol85: *s = "DW_LANG_Cobol85"; break; case DW_LANG_Fortran77: *s = "DW_LANG_Fortran77"; break; case DW_LANG_Fortran90: *s = "DW_LANG_Fortran90"; break; case DW_LANG_Pascal83: *s = "DW_LANG_Pascal83"; break; case DW_LANG_Modula2: *s = "DW_LANG_Modula2"; break; case DW_LANG_Java: *s = "DW_LANG_Java"; break; case DW_LANG_C99: *s = "DW_LANG_C99"; break; case DW_LANG_Ada95: *s = "DW_LANG_Ada95"; break; case DW_LANG_Fortran95: *s = "DW_LANG_Fortran95"; break; case DW_LANG_PLI: *s = "DW_LANG_PLI"; break; case DW_LANG_ObjC: *s = "DW_LANG_ObjC"; break; case DW_LANG_ObjC_plus_plus: *s = "DW_LANG_ObjC_plus_plus"; break; case DW_LANG_UPC: *s = "DW_LANG_UPC"; break; case DW_LANG_D: *s = "DW_LANG_D"; break; case DW_LANG_lo_user: *s = "DW_LANG_lo_user"; break; case DW_LANG_hi_user: *s = "DW_LANG_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_LNE_name(unsigned lne, const char **s) { assert(s != NULL); switch (lne) { case DW_LNE_end_sequence: *s = "DW_LNE_end_sequence"; break; case DW_LNE_set_address: *s = "DW_LNE_set_address"; break; case DW_LNE_define_file: *s = "DW_LNE_define_file"; break; case DW_LNE_lo_user: *s = "DW_LNE_lo_user"; break; case DW_LNE_hi_user: *s = "DW_LNE_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_LNS_name(unsigned lns, const char **s) { assert(s != NULL); switch (lns) { case DW_LNS_copy: *s = "DW_LNS_copy"; break; case DW_LNS_advance_pc: *s = "DW_LNS_advance_pc"; break; case DW_LNS_advance_line: *s = "DW_LNS_advance_line"; break; case DW_LNS_set_file: *s = "DW_LNS_set_file"; break; case DW_LNS_set_column: *s = "DW_LNS_set_column"; break; case DW_LNS_negate_stmt: *s = "DW_LNS_negate_stmt"; break; case DW_LNS_set_basic_block: *s = "DW_LNS_set_basic_block"; break; case DW_LNS_const_add_pc: *s = "DW_LNS_const_add_pc"; break; case DW_LNS_fixed_advance_pc: *s = "DW_LNS_fixed_advance_pc"; break; case DW_LNS_set_prologue_end: *s = "DW_LNS_set_prologue_end"; break; case DW_LNS_set_epilogue_begin: *s = "DW_LNS_set_epilogue_begin"; break; case DW_LNS_set_isa: *s = "DW_LNS_set_isa"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_MACINFO_name(unsigned mi, const char **s) { assert(s != NULL); switch (mi) { case DW_MACINFO_define: *s = "DW_MACINFO_define"; break; case DW_MACINFO_undef: *s = "DW_MACINFO_undef"; break; case DW_MACINFO_start_file: *s = "DW_MACINFO_start_file"; break; case DW_MACINFO_end_file: *s = "DW_MACINFO_end_file"; break; case DW_MACINFO_vendor_ext: *s = "DW_MACINFO_vendor_ext"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_OP_name(unsigned op, const char **s) { assert(s != NULL); switch (op) { case DW_OP_deref: *s = "DW_OP_deref"; break; case DW_OP_reg0: *s = "DW_OP_reg0"; break; case DW_OP_reg1: *s = "DW_OP_reg1"; break; case DW_OP_reg2: *s = "DW_OP_reg2"; break; case DW_OP_reg3: *s = "DW_OP_reg3"; break; case DW_OP_reg4: *s = "DW_OP_reg4"; break; case DW_OP_reg5: *s = "DW_OP_reg5"; break; case DW_OP_reg6: *s = "DW_OP_reg6"; break; case DW_OP_reg7: *s = "DW_OP_reg7"; break; case DW_OP_reg8: *s = "DW_OP_reg8"; break; case DW_OP_reg9: *s = "DW_OP_reg9"; break; case DW_OP_reg10: *s = "DW_OP_reg10"; break; case DW_OP_reg11: *s = "DW_OP_reg11"; break; case DW_OP_reg12: *s = "DW_OP_reg12"; break; case DW_OP_reg13: *s = "DW_OP_reg13"; break; case DW_OP_reg14: *s = "DW_OP_reg14"; break; case DW_OP_reg15: *s = "DW_OP_reg15"; break; case DW_OP_reg16: *s = "DW_OP_reg16"; break; case DW_OP_reg17: *s = "DW_OP_reg17"; break; case DW_OP_reg18: *s = "DW_OP_reg18"; break; case DW_OP_reg19: *s = "DW_OP_reg19"; break; case DW_OP_reg20: *s = "DW_OP_reg20"; break; case DW_OP_reg21: *s = "DW_OP_reg21"; break; case DW_OP_reg22: *s = "DW_OP_reg22"; break; case DW_OP_reg23: *s = "DW_OP_reg23"; break; case DW_OP_reg24: *s = "DW_OP_reg24"; break; case DW_OP_reg25: *s = "DW_OP_reg25"; break; case DW_OP_reg26: *s = "DW_OP_reg26"; break; case DW_OP_reg27: *s = "DW_OP_reg27"; break; case DW_OP_reg28: *s = "DW_OP_reg28"; break; case DW_OP_reg29: *s = "DW_OP_reg29"; break; case DW_OP_reg30: *s = "DW_OP_reg30"; break; case DW_OP_reg31: *s = "DW_OP_reg31"; break; case DW_OP_lit0: *s = "DW_OP_lit0"; break; case DW_OP_lit1: *s = "DW_OP_lit1"; break; case DW_OP_lit2: *s = "DW_OP_lit2"; break; case DW_OP_lit3: *s = "DW_OP_lit3"; break; case DW_OP_lit4: *s = "DW_OP_lit4"; break; case DW_OP_lit5: *s = "DW_OP_lit5"; break; case DW_OP_lit6: *s = "DW_OP_lit6"; break; case DW_OP_lit7: *s = "DW_OP_lit7"; break; case DW_OP_lit8: *s = "DW_OP_lit8"; break; case DW_OP_lit9: *s = "DW_OP_lit9"; break; case DW_OP_lit10: *s = "DW_OP_lit10"; break; case DW_OP_lit11: *s = "DW_OP_lit11"; break; case DW_OP_lit12: *s = "DW_OP_lit12"; break; case DW_OP_lit13: *s = "DW_OP_lit13"; break; case DW_OP_lit14: *s = "DW_OP_lit14"; break; case DW_OP_lit15: *s = "DW_OP_lit15"; break; case DW_OP_lit16: *s = "DW_OP_lit16"; break; case DW_OP_lit17: *s = "DW_OP_lit17"; break; case DW_OP_lit18: *s = "DW_OP_lit18"; break; case DW_OP_lit19: *s = "DW_OP_lit19"; break; case DW_OP_lit20: *s = "DW_OP_lit20"; break; case DW_OP_lit21: *s = "DW_OP_lit21"; break; case DW_OP_lit22: *s = "DW_OP_lit22"; break; case DW_OP_lit23: *s = "DW_OP_lit23"; break; case DW_OP_lit24: *s = "DW_OP_lit24"; break; case DW_OP_lit25: *s = "DW_OP_lit25"; break; case DW_OP_lit26: *s = "DW_OP_lit26"; break; case DW_OP_lit27: *s = "DW_OP_lit27"; break; case DW_OP_lit28: *s = "DW_OP_lit28"; break; case DW_OP_lit29: *s = "DW_OP_lit29"; break; case DW_OP_lit30: *s = "DW_OP_lit30"; break; case DW_OP_lit31: *s = "DW_OP_lit31"; break; case DW_OP_dup: *s = "DW_OP_dup"; break; case DW_OP_drop: *s = "DW_OP_drop"; break; case DW_OP_over: *s = "DW_OP_over"; break; case DW_OP_swap: *s = "DW_OP_swap"; break; case DW_OP_rot: *s = "DW_OP_rot"; break; case DW_OP_xderef: *s = "DW_OP_xderef"; break; case DW_OP_abs: *s = "DW_OP_abs"; break; case DW_OP_and: *s = "DW_OP_and"; break; case DW_OP_div: *s = "DW_OP_div"; break; case DW_OP_minus: *s = "DW_OP_minus"; break; case DW_OP_mod: *s = "DW_OP_mod"; break; case DW_OP_mul: *s = "DW_OP_mul"; break; case DW_OP_neg: *s = "DW_OP_neg"; break; case DW_OP_not: *s = "DW_OP_not"; break; case DW_OP_or: *s = "DW_OP_or"; break; case DW_OP_plus: *s = "DW_OP_plus"; break; case DW_OP_shl: *s = "DW_OP_shl"; break; case DW_OP_shr: *s = "DW_OP_shr"; break; case DW_OP_shra: *s = "DW_OP_shra"; break; case DW_OP_xor: *s = "DW_OP_xor"; break; case DW_OP_eq: *s = "DW_OP_eq"; break; case DW_OP_ge: *s = "DW_OP_ge"; break; case DW_OP_gt: *s = "DW_OP_gt"; break; case DW_OP_le: *s = "DW_OP_le"; break; case DW_OP_lt: *s = "DW_OP_lt"; break; case DW_OP_ne: *s = "DW_OP_ne"; break; case DW_OP_nop: *s = "DW_OP_nop"; break; case DW_OP_const1u: *s = "DW_OP_const1u"; break; case DW_OP_const1s: *s = "DW_OP_const1s"; break; case DW_OP_pick: *s = "DW_OP_pick"; break; case DW_OP_deref_size: *s = "DW_OP_deref_size"; break; case DW_OP_xderef_size: *s = "DW_OP_xderef_size"; break; case DW_OP_const2u: *s = "DW_OP_const2u"; break; case DW_OP_const2s: *s = "DW_OP_const2s"; break; case DW_OP_bra: *s = "DW_OP_bra"; break; case DW_OP_skip: *s = "DW_OP_skip"; break; case DW_OP_const4u: *s = "DW_OP_const4u"; break; case DW_OP_const4s: *s = "DW_OP_const4s"; break; case DW_OP_const8u: *s = "DW_OP_const8u"; break; case DW_OP_const8s: *s = "DW_OP_const8s"; break; case DW_OP_constu: *s = "DW_OP_constu"; break; case DW_OP_plus_uconst: *s = "DW_OP_plus_uconst"; break; case DW_OP_regx: *s = "DW_OP_regx"; break; case DW_OP_piece: *s = "DW_OP_piece"; break; case DW_OP_consts: *s = "DW_OP_consts"; break; case DW_OP_breg0: *s = "DW_OP_breg0"; break; case DW_OP_breg1: *s = "DW_OP_breg1"; break; case DW_OP_breg2: *s = "DW_OP_breg2"; break; case DW_OP_breg3: *s = "DW_OP_breg3"; break; case DW_OP_breg4: *s = "DW_OP_breg4"; break; case DW_OP_breg5: *s = "DW_OP_breg5"; break; case DW_OP_breg6: *s = "DW_OP_breg6"; break; case DW_OP_breg7: *s = "DW_OP_breg7"; break; case DW_OP_breg8: *s = "DW_OP_breg8"; break; case DW_OP_breg9: *s = "DW_OP_breg9"; break; case DW_OP_breg10: *s = "DW_OP_breg10"; break; case DW_OP_breg11: *s = "DW_OP_breg11"; break; case DW_OP_breg12: *s = "DW_OP_breg12"; break; case DW_OP_breg13: *s = "DW_OP_breg13"; break; case DW_OP_breg14: *s = "DW_OP_breg14"; break; case DW_OP_breg15: *s = "DW_OP_breg15"; break; case DW_OP_breg16: *s = "DW_OP_breg16"; break; case DW_OP_breg17: *s = "DW_OP_breg17"; break; case DW_OP_breg18: *s = "DW_OP_breg18"; break; case DW_OP_breg19: *s = "DW_OP_breg19"; break; case DW_OP_breg20: *s = "DW_OP_breg20"; break; case DW_OP_breg21: *s = "DW_OP_breg21"; break; case DW_OP_breg22: *s = "DW_OP_breg22"; break; case DW_OP_breg23: *s = "DW_OP_breg23"; break; case DW_OP_breg24: *s = "DW_OP_breg24"; break; case DW_OP_breg25: *s = "DW_OP_breg25"; break; case DW_OP_breg26: *s = "DW_OP_breg26"; break; case DW_OP_breg27: *s = "DW_OP_breg27"; break; case DW_OP_breg28: *s = "DW_OP_breg28"; break; case DW_OP_breg29: *s = "DW_OP_breg29"; break; case DW_OP_breg30: *s = "DW_OP_breg30"; break; case DW_OP_breg31: *s = "DW_OP_breg31"; break; case DW_OP_fbreg: *s = "DW_OP_fbreg"; break; case DW_OP_bregx: *s = "DW_OP_bregx"; break; case DW_OP_addr: *s = "DW_OP_addr"; break; case DW_OP_push_object_address: *s = "DW_OP_push_object_address"; break; case DW_OP_call2: *s = "DW_OP_call2"; break; case DW_OP_call4: *s = "DW_OP_call4"; break; case DW_OP_call_ref: *s = "DW_OP_call_ref"; break; case DW_OP_form_tls_address: *s = "DW_OP_form_tls_address"; break; case DW_OP_call_frame_cfa: *s = "DW_OP_call_frame_cfa"; break; case DW_OP_bit_piece: *s = "DW_OP_bit_piece"; break; case DW_OP_implicit_value: *s = "DW_OP_implicit_value"; break; case DW_OP_stack_value: *s = "DW_OP_stack_value"; break; case DW_OP_GNU_push_tls_address: *s = "DW_OP_GNU_push_tls_address"; break; + case DW_OP_GNU_uninit: + *s = "DW_OP_GNU_uninit"; break; + case DW_OP_GNU_encoded_addr: + *s = "DW_OP_GNU_encoded_addr"; break; + case DW_OP_GNU_implicit_pointer: + *s = "DW_OP_GNU_implicit_pointer"; break; + case DW_OP_GNU_entry_value: + *s = "DW_OP_GNU_entry_value"; break; + case DW_OP_GNU_const_type: + *s = "DW_OP_GNU_const_type"; break; + case DW_OP_GNU_regval_type: + *s = "DW_OP_GNU_regval_type"; break; + case DW_OP_GNU_deref_type: + *s = "DW_OP_GNU_deref_type"; break; + case DW_OP_GNU_convert: + *s = "DW_OP_GNU_convert"; break; + case DW_OP_GNU_reinterpret: + *s = "DW_OP_GNU_reinterpret"; break; + case DW_OP_GNU_parameter_ref: + *s = "DW_OP_GNU_parameter_ref"; break; + case DW_OP_GNU_addr_index: + *s = "DW_OP_GNU_addr_index"; break; + case DW_OP_GNU_const_index: + *s = "DW_OP_GNU_const_index"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_ORD_name(unsigned ord, const char **s) { assert(s != NULL); switch (ord) { case DW_ORD_row_major: *s = "DW_ORD_row_major"; break; case DW_ORD_col_major: *s = "DW_ORD_col_major"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_TAG_name(unsigned tag, const char **s) { assert(s != NULL); switch (tag) { case DW_TAG_access_declaration: *s = "DW_TAG_access_declaration"; break; case DW_TAG_array_type: *s = "DW_TAG_array_type"; break; case DW_TAG_base_type: *s = "DW_TAG_base_type"; break; case DW_TAG_catch_block: *s = "DW_TAG_catch_block"; break; case DW_TAG_class_type: *s = "DW_TAG_class_type"; break; case DW_TAG_common_block: *s = "DW_TAG_common_block"; break; case DW_TAG_common_inclusion: *s = "DW_TAG_common_inclusion"; break; case DW_TAG_compile_unit: *s = "DW_TAG_compile_unit"; break; case DW_TAG_condition: *s = "DW_TAG_condition"; break; case DW_TAG_const_type: *s = "DW_TAG_const_type"; break; case DW_TAG_constant: *s = "DW_TAG_constant"; break; case DW_TAG_dwarf_procedure: *s = "DW_TAG_dwarf_procedure"; break; case DW_TAG_entry_point: *s = "DW_TAG_entry_point"; break; case DW_TAG_enumeration_type: *s = "DW_TAG_enumeration_type"; break; case DW_TAG_enumerator: *s = "DW_TAG_enumerator"; break; case DW_TAG_formal_parameter: *s = "DW_TAG_formal_parameter"; break; case DW_TAG_friend: *s = "DW_TAG_friend"; break; case DW_TAG_imported_declaration: *s = "DW_TAG_imported_declaration"; break; case DW_TAG_imported_module: *s = "DW_TAG_imported_module"; break; case DW_TAG_imported_unit: *s = "DW_TAG_imported_unit"; break; case DW_TAG_inheritance: *s = "DW_TAG_inheritance"; break; case DW_TAG_inlined_subroutine: *s = "DW_TAG_inlined_subroutine"; break; case DW_TAG_interface_type: *s = "DW_TAG_interface_type"; break; case DW_TAG_label: *s = "DW_TAG_label"; break; case DW_TAG_lexical_block: *s = "DW_TAG_lexical_block"; break; case DW_TAG_member: *s = "DW_TAG_member"; break; case DW_TAG_module: *s = "DW_TAG_module"; break; case DW_TAG_namelist: *s = "DW_TAG_namelist"; break; case DW_TAG_namelist_item: *s = "DW_TAG_namelist_item"; break; case DW_TAG_namespace: *s = "DW_TAG_namespace"; break; case DW_TAG_packed_type: *s = "DW_TAG_packed_type"; break; case DW_TAG_partial_unit: *s = "DW_TAG_partial_unit"; break; case DW_TAG_pointer_type: *s = "DW_TAG_pointer_type"; break; case DW_TAG_ptr_to_member_type: *s = "DW_TAG_ptr_to_member_type"; break; case DW_TAG_reference_type: *s = "DW_TAG_reference_type"; break; case DW_TAG_restrict_type: *s = "DW_TAG_restrict_type"; break; case DW_TAG_rvalue_reference_type: *s = "DW_TAG_rvalue_reference_type"; break; case DW_TAG_set_type: *s = "DW_TAG_set_type"; break; case DW_TAG_shared_type: *s = "DW_TAG_shared_type"; break; case DW_TAG_string_type: *s = "DW_TAG_string_type"; break; case DW_TAG_structure_type: *s = "DW_TAG_structure_type"; break; case DW_TAG_subprogram: *s = "DW_TAG_subprogram"; break; case DW_TAG_subrange_type: *s = "DW_TAG_subrange_type"; break; case DW_TAG_subroutine_type: *s = "DW_TAG_subroutine_type"; break; case DW_TAG_template_alias: *s = "DW_TAG_template_alias"; break; case DW_TAG_template_type_parameter: *s = "DW_TAG_template_type_parameter"; break; case DW_TAG_template_value_parameter: *s = "DW_TAG_template_value_parameter"; break; case DW_TAG_thrown_type: *s = "DW_TAG_thrown_type"; break; case DW_TAG_try_block: *s = "DW_TAG_try_block"; break; case DW_TAG_type_unit: *s = "DW_TAG_type_unit"; break; case DW_TAG_typedef: *s = "DW_TAG_typedef"; break; case DW_TAG_union_type: *s = "DW_TAG_union_type"; break; case DW_TAG_unspecified_parameters: *s = "DW_TAG_unspecified_parameters"; break; case DW_TAG_unspecified_type: *s = "DW_TAG_unspecified_type"; break; case DW_TAG_variable: *s = "DW_TAG_variable"; break; case DW_TAG_variant: *s = "DW_TAG_variant"; break; case DW_TAG_variant_part: *s = "DW_TAG_variant_part"; break; case DW_TAG_volatile_type: *s = "DW_TAG_volatile_type"; break; case DW_TAG_with_stmt: *s = "DW_TAG_with_stmt"; break; + case DW_TAG_format_label: + *s = "DW_TAG_format_label"; break; + case DW_TAG_function_template: + *s = "DW_TAG_function_template"; break; + case DW_TAG_class_template: + *s = "DW_TAG_class_template"; break; + case DW_TAG_GNU_BINCL: + *s = "DW_TAG_GNU_BINCL"; break; + case DW_TAG_GNU_EINCL: + *s = "DW_TAG_GNU_EINCL"; break; + case DW_TAG_GNU_template_template_param: + *s = "DW_TAG_GNU_template_template_param"; break; + case DW_TAG_GNU_template_parameter_pack: + *s = "DW_TAG_GNU_template_parameter_pack"; break; + case DW_TAG_GNU_formal_parameter_pack: + *s = "DW_TAG_GNU_formal_parameter_pack"; break; + case DW_TAG_GNU_call_site: + *s = "DW_TAG_GNU_call_site"; break; + case DW_TAG_GNU_call_site_parameter: + *s = "DW_TAG_GNU_call_site_parameter"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_VIRTUALITY_name(unsigned vir, const char **s) { assert(s != NULL); switch (vir) { case DW_VIRTUALITY_none: *s = "DW_VIRTUALITY_none"; break; case DW_VIRTUALITY_virtual: *s = "DW_VIRTUALITY_virtual"; break; case DW_VIRTUALITY_pure_virtual: *s = "DW_VIRTUALITY_pure_virtual"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_VIS_name(unsigned vis, const char **s) { assert(s != NULL); switch (vis) { case DW_VIS_local: *s = "DW_VIS_local"; break; case DW_VIS_exported: *s = "DW_VIS_exported"; break; case DW_VIS_qualified: *s = "DW_VIS_qualified"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } diff --git a/libdwarf/dwarf_errmsg.c b/libdwarf/dwarf_errmsg.c index 86afa28457bd..e300893a61c1 100644 --- a/libdwarf/dwarf_errmsg.c +++ b/libdwarf/dwarf_errmsg.c @@ -1,90 +1,90 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_errmsg.c 2576 2012-09-13 09:16:11Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_errmsg.c 2975 2014-01-21 20:08:04Z kaiwang27 $"); -const char *_libdwarf_errors[] = { +static const char *_libdwarf_errors[] = { #define DEFINE_ERROR(N,S) [DW_DLE_##N] = S DEFINE_ERROR(NONE, "No Error"), DEFINE_ERROR(ERROR, "An error"), DEFINE_ERROR(NO_ENTRY, "No entry found"), DEFINE_ERROR(ARGUMENT, "Invalid argument"), DEFINE_ERROR(DEBUG_INFO_NULL, "Debug info NULL"), DEFINE_ERROR(MEMORY, "Insufficient memory"), DEFINE_ERROR(ELF, "ELF error"), DEFINE_ERROR(CU_LENGTH_ERROR, "Invalid compilation unit data"), DEFINE_ERROR(VERSION_STAMP_ERROR, "Unsupported version"), DEFINE_ERROR(DEBUG_ABBREV_NULL, "Abbrev not found"), DEFINE_ERROR(DIE_NO_CU_CONTEXT, "No current compilation unit"), DEFINE_ERROR(LOC_EXPR_BAD, "Invalid location expression"), DEFINE_ERROR(EXPR_LENGTH_BAD, "Invalid DWARF expression length"), DEFINE_ERROR(DEBUG_LOC_SECTION_SHORT, "Loclist section too short"), DEFINE_ERROR(ATTR_FORM_BAD, "Invalid attribute form"), DEFINE_ERROR(DEBUG_LINE_LENGTH_BAD, "Line info section too short"), DEFINE_ERROR(LINE_FILE_NUM_BAD, "Invalid file number."), DEFINE_ERROR(DIR_INDEX_BAD, "Invalid dir index."), DEFINE_ERROR(DEBUG_FRAME_LENGTH_BAD, "Frame section too short"), DEFINE_ERROR(NO_CIE_FOR_FDE, "FDE without corresponding CIE"), DEFINE_ERROR(FRAME_AUGMENTATION_UNKNOWN, "Unknown CIE augmentation"), DEFINE_ERROR(FRAME_INSTR_EXEC_ERROR, "Frame instruction exec error"), DEFINE_ERROR(FRAME_VERSION_BAD, "Unsupported frame section version"), DEFINE_ERROR(FRAME_TABLE_COL_BAD, "Invalid table column value"), DEFINE_ERROR(DF_REG_NUM_TOO_HIGH, "Register number too large"), DEFINE_ERROR(PC_NOT_IN_FDE_RANGE, "PC requested not in the FDE range"), DEFINE_ERROR(ARANGE_OFFSET_BAD, "Invalid address range offset"), DEFINE_ERROR(DEBUG_MACRO_INCONSISTENT, "Invalid macinfo data"), DEFINE_ERROR(ELF_SECT_ERR, "Application callback failed"), DEFINE_ERROR(NUM, "Unknown DWARF error") #undef DEFINE_ERROR }; const char * dwarf_errmsg_(Dwarf_Error *error) { const char *p; if (error == NULL) return NULL; if (error->err_error < 0 || error->err_error >= DW_DLE_NUM) return _libdwarf_errors[DW_DLE_NUM]; else if (error->err_error == DW_DLE_NONE) return _libdwarf_errors[DW_DLE_NONE]; else p = _libdwarf_errors[error->err_error]; if (error->err_error == DW_DLE_ELF) snprintf(error->err_msg, sizeof(error->err_msg), "ELF error : %s [%s(%d)]", elf_errmsg(error->err_elferror), error->err_func, error->err_line); else snprintf(error->err_msg, sizeof(error->err_msg), "%s [%s(%d)]", p, error->err_func, error->err_line); return (const char *) error->err_msg; } diff --git a/libdwarf/dwarf_frame.c b/libdwarf/dwarf_frame.c index 5ccbbc4aead7..442f232cf092 100644 --- a/libdwarf/dwarf_frame.c +++ b/libdwarf/dwarf_frame.c @@ -1,603 +1,603 @@ /*- * Copyright (c) 2009,2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_frame.c 2073 2011-10-27 03:30:47Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_frame.c 3106 2014-12-19 16:00:58Z kaiwang27 $"); int dwarf_get_fde_list(Dwarf_Debug dbg, Dwarf_Cie **cie_list, Dwarf_Signed *cie_count, Dwarf_Fde **fde_list, Dwarf_Signed *fde_count, Dwarf_Error *error) { if (dbg == NULL || cie_list == NULL || cie_count == NULL || fde_list == NULL || fde_count == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (dbg->dbg_internal_reg_table == NULL) { if (_dwarf_frame_interal_table_init(dbg, error) != DW_DLE_NONE) return (DW_DLV_ERROR); } if (dbg->dbg_frame == NULL) { if (_dwarf_frame_section_load(dbg, error) != DW_DLE_NONE) return (DW_DLV_ERROR); if (dbg->dbg_frame == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } } if (dbg->dbg_frame->fs_ciearray == NULL || dbg->dbg_frame->fs_fdearray == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *cie_list = dbg->dbg_frame->fs_ciearray; *cie_count = dbg->dbg_frame->fs_cielen; *fde_list = dbg->dbg_frame->fs_fdearray; *fde_count = dbg->dbg_frame->fs_fdelen; return (DW_DLV_OK); } int dwarf_get_fde_list_eh(Dwarf_Debug dbg, Dwarf_Cie **cie_list, Dwarf_Signed *cie_count, Dwarf_Fde **fde_list, Dwarf_Signed *fde_count, Dwarf_Error *error) { if (dbg == NULL || cie_list == NULL || cie_count == NULL || fde_list == NULL || fde_count == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (dbg->dbg_internal_reg_table == NULL) { if (_dwarf_frame_interal_table_init(dbg, error) != DW_DLE_NONE) return (DW_DLV_ERROR); } if (dbg->dbg_eh_frame == NULL) { if (_dwarf_frame_section_load_eh(dbg, error) != DW_DLE_NONE) return (DW_DLV_ERROR); if (dbg->dbg_eh_frame == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } } if (dbg->dbg_eh_frame->fs_ciearray == NULL || dbg->dbg_eh_frame->fs_fdearray == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *cie_list = dbg->dbg_eh_frame->fs_ciearray; *cie_count = dbg->dbg_eh_frame->fs_cielen; *fde_list = dbg->dbg_eh_frame->fs_fdearray; *fde_count = dbg->dbg_eh_frame->fs_fdelen; return (DW_DLV_OK); } int dwarf_get_fde_n(Dwarf_Fde *fdelist, Dwarf_Unsigned fde_index, Dwarf_Fde *ret_fde, Dwarf_Error *error) { Dwarf_FrameSec fs; Dwarf_Debug dbg; dbg = fdelist != NULL ? (*fdelist)->fde_dbg : NULL; if (fdelist == NULL || ret_fde == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } fs = fdelist[0]->fde_fs; assert(fs != NULL); if (fde_index >= fs->fs_fdelen) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } *ret_fde = fdelist[fde_index]; return (DW_DLV_OK); } int dwarf_get_fde_at_pc(Dwarf_Fde *fdelist, Dwarf_Addr pc, Dwarf_Fde *ret_fde, Dwarf_Addr *lopc, Dwarf_Addr *hipc, Dwarf_Error *error) { Dwarf_FrameSec fs; Dwarf_Debug dbg; Dwarf_Fde fde; int i; dbg = fdelist != NULL ? (*fdelist)->fde_dbg : NULL; if (fdelist == NULL || ret_fde == NULL || lopc == NULL || hipc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } fs = fdelist[0]->fde_fs; assert(fs != NULL); for (i = 0; (Dwarf_Unsigned)i < fs->fs_fdelen; i++) { fde = fdelist[i]; if (pc >= fde->fde_initloc && pc < fde->fde_initloc + fde->fde_adrange) { *ret_fde = fde; *lopc = fde->fde_initloc; *hipc = fde->fde_initloc + fde->fde_adrange - 1; return (DW_DLV_OK); } } DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } int dwarf_get_cie_of_fde(Dwarf_Fde fde, Dwarf_Cie *ret_cie, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || ret_cie == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_cie = fde->fde_cie; return (DW_DLV_OK); } int dwarf_get_fde_range(Dwarf_Fde fde, Dwarf_Addr *low_pc, Dwarf_Unsigned *func_len, Dwarf_Ptr *fde_bytes, Dwarf_Unsigned *fde_byte_len, Dwarf_Off *cie_offset, Dwarf_Signed *cie_index, Dwarf_Off *fde_offset, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || low_pc == NULL || func_len == NULL || fde_bytes == NULL || fde_byte_len == NULL || cie_offset == NULL || cie_index == NULL || fde_offset == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *low_pc = fde->fde_initloc; *func_len = fde->fde_adrange; *fde_bytes = fde->fde_addr; *fde_byte_len = fde->fde_length; *cie_offset = fde->fde_cieoff; *cie_index = fde->fde_cie->cie_index; *fde_offset = fde->fde_offset; return (DW_DLV_OK); } int dwarf_get_cie_info(Dwarf_Cie cie, Dwarf_Unsigned *bytes_in_cie, Dwarf_Small *version, char **augmenter, Dwarf_Unsigned *caf, Dwarf_Unsigned *daf, Dwarf_Half *ra, Dwarf_Ptr *initinst, Dwarf_Unsigned *inst_len, Dwarf_Error *error) { if (cie == NULL || bytes_in_cie == NULL || version == NULL || augmenter == NULL || caf == NULL || daf == NULL || ra == NULL || initinst == NULL || inst_len == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *bytes_in_cie = cie->cie_length; *version = cie->cie_version; *augmenter = (char *) cie->cie_augment; *caf = cie->cie_caf; *daf = cie->cie_daf; *ra = cie->cie_ra; *initinst = cie->cie_initinst; *inst_len = cie->cie_instlen; return (DW_DLV_OK); } int dwarf_get_cie_index(Dwarf_Cie cie, Dwarf_Signed *cie_index, Dwarf_Error *error) { if (cie == NULL || cie_index == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *cie_index = cie->cie_index; return (DW_DLV_OK); } int dwarf_get_fde_instr_bytes(Dwarf_Fde fde, Dwarf_Ptr *ret_inst, Dwarf_Unsigned *ret_len, Dwarf_Error *error) { Dwarf_Debug dbg; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || ret_inst == NULL || ret_len == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_inst = fde->fde_inst; *ret_len = fde->fde_instlen; return (DW_DLV_OK); } #define RL rt->rt3_rules[table_column] #define CFA rt->rt3_cfa_rule int dwarf_get_fde_info_for_reg(Dwarf_Fde fde, Dwarf_Half table_column, Dwarf_Addr pc_requested, Dwarf_Signed *offset_relevant, Dwarf_Signed *register_num, Dwarf_Signed *offset, Dwarf_Addr *row_pc, Dwarf_Error *error) { Dwarf_Regtable3 *rt; Dwarf_Debug dbg; Dwarf_Addr pc; int ret; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || offset_relevant == NULL || register_num == NULL || offset == NULL || row_pc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (pc_requested < fde->fde_initloc || pc_requested >= fde->fde_initloc + fde->fde_adrange) { DWARF_SET_ERROR(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); return (DW_DLV_ERROR); } ret = _dwarf_frame_get_internal_table(fde, pc_requested, &rt, &pc, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); if (table_column == dbg->dbg_frame_cfa_value) { /* Application ask for CFA. */ *offset_relevant = CFA.dw_offset_relevant; *register_num = CFA.dw_regnum; *offset = CFA.dw_offset_or_block_len; } else { /* Application ask for normal registers. */ if (table_column >= dbg->dbg_frame_rule_table_size || table_column >= DW_REG_TABLE_SIZE) { DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); return (DW_DLV_ERROR); } *offset_relevant = RL.dw_offset_relevant; *register_num = RL.dw_regnum; *offset = RL.dw_offset_or_block_len; } *row_pc = pc; return (DW_DLV_OK); } int dwarf_get_fde_info_for_all_regs(Dwarf_Fde fde, Dwarf_Addr pc_requested, Dwarf_Regtable *reg_table, Dwarf_Addr *row_pc, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_Regtable3 *rt; Dwarf_Addr pc; Dwarf_Half cfa; int i, ret; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || reg_table == NULL || row_pc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } assert(dbg != NULL); if (pc_requested < fde->fde_initloc || pc_requested >= fde->fde_initloc + fde->fde_adrange) { DWARF_SET_ERROR(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); return (DW_DLV_ERROR); } ret = _dwarf_frame_get_internal_table(fde, pc_requested, &rt, &pc, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); /* * Copy the CFA rule to the column intended for holding the CFA, * if it's within the range of regtable. */ cfa = dbg->dbg_frame_cfa_value; if (cfa < DW_REG_TABLE_SIZE) { reg_table->rules[cfa].dw_offset_relevant = CFA.dw_offset_relevant; reg_table->rules[cfa].dw_regnum = CFA.dw_regnum; reg_table->rules[cfa].dw_offset = CFA.dw_offset_or_block_len; } /* * Copy other columns. */ for (i = 0; i < DW_REG_TABLE_SIZE && i < dbg->dbg_frame_rule_table_size; i++) { /* Do not overwrite CFA column */ if (i == cfa) continue; reg_table->rules[i].dw_offset_relevant = rt->rt3_rules[i].dw_offset_relevant; reg_table->rules[i].dw_regnum = rt->rt3_rules[i].dw_regnum; reg_table->rules[i].dw_offset = rt->rt3_rules[i].dw_offset_or_block_len; } *row_pc = pc; return (DW_DLV_OK); } int dwarf_get_fde_info_for_reg3(Dwarf_Fde fde, Dwarf_Half table_column, Dwarf_Addr pc_requested, Dwarf_Small *value_type, Dwarf_Signed *offset_relevant, Dwarf_Signed *register_num, Dwarf_Signed *offset_or_block_len, Dwarf_Ptr *block_ptr, Dwarf_Addr *row_pc, Dwarf_Error *error) { Dwarf_Regtable3 *rt; Dwarf_Debug dbg; Dwarf_Addr pc; int ret; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || value_type == NULL || offset_relevant == NULL || register_num == NULL || offset_or_block_len == NULL || block_ptr == NULL || row_pc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (pc_requested < fde->fde_initloc || pc_requested >= fde->fde_initloc + fde->fde_adrange) { DWARF_SET_ERROR(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); return (DW_DLV_ERROR); } ret = _dwarf_frame_get_internal_table(fde, pc_requested, &rt, &pc, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); if (table_column >= dbg->dbg_frame_rule_table_size) { DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); return (DW_DLV_ERROR); } *value_type = RL.dw_value_type; *offset_relevant = RL.dw_offset_relevant; *register_num = RL.dw_regnum; *offset_or_block_len = RL.dw_offset_or_block_len; *block_ptr = RL.dw_block_ptr; *row_pc = pc; return (DW_DLV_OK); } int dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde fde, Dwarf_Addr pc_requested, Dwarf_Small *value_type, Dwarf_Signed *offset_relevant, Dwarf_Signed *register_num, Dwarf_Signed *offset_or_block_len, Dwarf_Ptr *block_ptr, Dwarf_Addr *row_pc, Dwarf_Error *error) { Dwarf_Regtable3 *rt; Dwarf_Debug dbg; Dwarf_Addr pc; int ret; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || value_type == NULL || offset_relevant == NULL || register_num == NULL || offset_or_block_len == NULL || block_ptr == NULL || row_pc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (pc_requested < fde->fde_initloc || pc_requested >= fde->fde_initloc + fde->fde_adrange) { DWARF_SET_ERROR(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); return (DW_DLV_ERROR); } ret = _dwarf_frame_get_internal_table(fde, pc_requested, &rt, &pc, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); *value_type = CFA.dw_value_type; *offset_relevant = CFA.dw_offset_relevant; *register_num = CFA.dw_regnum; *offset_or_block_len = CFA.dw_offset_or_block_len; *block_ptr = CFA.dw_block_ptr; *row_pc = pc; return (DW_DLV_OK); } #undef RL #undef CFA int dwarf_get_fde_info_for_all_regs3(Dwarf_Fde fde, Dwarf_Addr pc_requested, Dwarf_Regtable3 *reg_table, Dwarf_Addr *row_pc, Dwarf_Error *error) { Dwarf_Regtable3 *rt; Dwarf_Debug dbg; Dwarf_Addr pc; int ret; dbg = fde != NULL ? fde->fde_dbg : NULL; if (fde == NULL || reg_table == NULL || reg_table->rt3_rules == NULL || row_pc == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } assert(dbg != NULL); if (pc_requested < fde->fde_initloc || pc_requested >= fde->fde_initloc + fde->fde_adrange) { DWARF_SET_ERROR(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); return (DW_DLV_ERROR); } ret = _dwarf_frame_get_internal_table(fde, pc_requested, &rt, &pc, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); ret = _dwarf_frame_regtable_copy(dbg, ®_table, rt, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); *row_pc = pc; return (DW_DLV_OK); } int dwarf_expand_frame_instructions(Dwarf_Cie cie, Dwarf_Ptr instruction, Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt, Dwarf_Error *error) { Dwarf_Debug dbg; int ret; dbg = cie != NULL ? cie->cie_dbg : NULL; if (cie == NULL || instruction == NULL || len == 0 || ret_oplist == NULL || ret_opcnt == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } - ret = _dwarf_frame_get_fop(dbg, instruction, len, ret_oplist, ret_opcnt, - error); + ret = _dwarf_frame_get_fop(dbg, cie->cie_addrsize, instruction, len, + ret_oplist, ret_opcnt, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); return (DW_DLV_OK); } Dwarf_Half dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, Dwarf_Half value) { Dwarf_Half old_value; old_value = dbg->dbg_frame_rule_table_size; dbg->dbg_frame_rule_table_size = value; return (old_value); } Dwarf_Half dwarf_set_frame_rule_initial_value(Dwarf_Debug dbg, Dwarf_Half value) { Dwarf_Half old_value; old_value = dbg->dbg_frame_rule_initial_value; dbg->dbg_frame_rule_initial_value = value; return (old_value); } Dwarf_Half dwarf_set_frame_cfa_value(Dwarf_Debug dbg, Dwarf_Half value) { Dwarf_Half old_value; old_value = dbg->dbg_frame_cfa_value; dbg->dbg_frame_cfa_value = value; return (old_value); } Dwarf_Half dwarf_set_frame_same_value(Dwarf_Debug dbg, Dwarf_Half value) { Dwarf_Half old_value; old_value = dbg->dbg_frame_same_value; dbg->dbg_frame_same_value = value; return (old_value); } Dwarf_Half dwarf_set_frame_undefined_value(Dwarf_Debug dbg, Dwarf_Half value) { Dwarf_Half old_value; old_value = dbg->dbg_frame_undefined_value; dbg->dbg_frame_undefined_value = value; return (old_value); } diff --git a/libdwarf/dwarf_get_die_infotypes_flag.3 b/libdwarf/dwarf_get_die_infotypes_flag.3 new file mode 100644 index 000000000000..4f5a19ace367 --- /dev/null +++ b/libdwarf/dwarf_get_die_infotypes_flag.3 @@ -0,0 +1,73 @@ +.\" Copyright (c) 2014 Kai Wang +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: dwarf_get_die_infotypes_flag.3 3118 2014-12-20 20:30:06Z jkoshy $ +.\" +.Dd December 20, 2014 +.Os +.Dt DWARF_GET_DIE_INFOTYPES_FLAG 3 +.Sh NAME +.Nm dwarf_get_die_infotypes_flag +.Nd indicate the originating DWARF section for a DIE +.Sh LIBRARY +.Lb libdwarf +.Sh SYNOPSIS +.In libdwarf.h +.Ft Dwarf_Bool +.Fo dwarf_get_die_infotypes_flag +.Fa "Dwarf_Die die" +.Fc +.Sh DESCRIPTION +Function +.Fn dwarf_get_die_infotypes_flag +returns a flag indicating the originating DWARF section for the +debugging information entry referenced by argument +.Ar die . +.Pp +Argument +.Ar die +should reference a valid debugging information entry descriptor. +.Sh RETURN VALUES +Function +.Fn dwarf_get_die_infotypes_flag +returns a non-zero value if argument +.Ar die +originates in the +.Dq .debug_info +section. +.Pp +It returns zero if argument +.Ar die +originates in the +.Dq .debug_types +section. +.Sh ERRORS +Function +.Fn dwarf_get_die_infotypes_flag +always succeeds. +.Sh SEE ALSO +.Xr dwarf 3 , +.Xr dwarf_next_cu_header_c 3 , +.Xr dwarf_offdie_b 3 , +.Xr dwarf_siblingof_b 3 diff --git a/libdwarf/dwarf_get_section_max_offsets.3 b/libdwarf/dwarf_get_section_max_offsets.3 new file mode 100644 index 000000000000..6f79341cd367 --- /dev/null +++ b/libdwarf/dwarf_get_section_max_offsets.3 @@ -0,0 +1,116 @@ +.\" Copyright (c) 2014 Kai Wang +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: dwarf_get_section_max_offsets.3 3098 2014-09-02 22:18:29Z kaiwang27 $ +.\" +.Dd July 27, 2014 +.Os +.Dt DWARF_GET_SECTION_MAX_OFFSETS +.Sh NAME +.Nm dwarf_get_section_max_offsets , +.Nm dwarf_get_section_max_offsets_b +.Nd return the size of DWARF sections +.Sh LIBRARY +.Lb libdwarf +.Sh SYNOPSIS +.In libdwarf.h +.Ft int +.Fo dwarf_get_section_max_offsets +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Unsigned *debug_info" +.Fa "Dwarf_Unsigned *debug_abbrev" +.Fa "Dwarf_Unsigned *debug_line" +.Fa "Dwarf_Unsigned *debug_loc" +.Fa "Dwarf_Unsigned *debug_aranges" +.Fa "Dwarf_Unsigned *debug_macinfo" +.Fa "Dwarf_Unsigned *debug_pubnames" +.Fa "Dwarf_Unsigned *debug_str" +.Fa "Dwarf_Unsigned *debug_frame" +.Fa "Dwarf_Unsigned *debug_ranges" +.Fa "Dwarf_Unsigned *debug_pubtypes" +.Fc +.Ft int +.Fo dwarf_get_section_max_offsets_b +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Unsigned *debug_info" +.Fa "Dwarf_Unsigned *debug_abbrev" +.Fa "Dwarf_Unsigned *debug_line" +.Fa "Dwarf_Unsigned *debug_loc" +.Fa "Dwarf_Unsigned *debug_aranges" +.Fa "Dwarf_Unsigned *debug_macinfo" +.Fa "Dwarf_Unsigned *debug_pubnames" +.Fa "Dwarf_Unsigned *debug_str" +.Fa "Dwarf_Unsigned *debug_frame" +.Fa "Dwarf_Unsigned *debug_ranges" +.Fa "Dwarf_Unsigned *debug_pubtypes" +.Fa "Dwarf_Unsigned *debug_types" +.Fc +.Sh DESCRIPTION +Function +.Fn dwarf_get_section_max_offsets_b +retrieves the sizes of the DWARF sections in a DWARF debug context. +Argument +.Ar dbg +should reference a DWARF debug context allocated using +.Xr dwarf_init 3 . +The function stores the size of each DWARF section to the location +pointed to by the argument corresponding to the section name. +If a DWARF section does not exist, the location pointed to by the +argument corresponding to that section will be set to zero. +.Pp +A value of NULL may be used for any of the arguments +.Ar debug_info , +.Ar debug_abbrev , +.Ar debug_line , +.Ar debug_loc , +.Ar debug_aranges , +.Ar debug_macinfo , +.Ar debug_pubnames , +.Ar debug_str , +.Ar debug_frame , +.Ar debug_ranges , +.Ar debug_pubtypes +and +.Ar debug_types +if the caller is not interested in the respective section size. +.Pp +Function +.Fn dwarf_get_section_max_offsets +is identical to function +.Fn dwarf_get_section_max_offsets_b +except that it does not provide argument +.Ar debug_types , +thus it can not retrieve the size of the +.Dq \&.debug_types +section. +.Sh RETURN VALUES +On success, these functions return +.Dv DW_DLV_OK . +If argument +.Ar dbg +is NULL, they return +.Dv DW_DLV_ERROR . +.Sh SEE ALSO +.Xr dwarf 3 , +.Xr dwarf_init 3 diff --git a/libdwarf/dwarf_highpc.3 b/libdwarf/dwarf_highpc.3 index 998a3b6ad650..4d31f5c8d1a2 100644 --- a/libdwarf/dwarf_highpc.3 +++ b/libdwarf/dwarf_highpc.3 @@ -1,162 +1,193 @@ -.\" Copyright (c) 2010 Kai Wang +.\" Copyright (c) 2010,2014 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_highpc.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_highpc.3 3092 2014-09-02 22:09:30Z kaiwang27 $ .\" -.Dd April 7, 2010 +.Dd July 22, 2014 .Os .Dt DWARF_HIGHPC 3 .Sh NAME .Nm dwarf_arrayorder , .Nm dwarf_bitoffset , .Nm dwarf_bitsize , .Nm dwarf_bytesize , .Nm dwarf_highpc , +.Nm dwarf_highpc_b , .Nm dwarf_lowpc , .Nm dwarf_srclang .Nd retrieve the value of a DWARF attribute .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_arrayorder .Fa "Dwarf_Die die" .Fa "Dwarf_Unsigned *ret_order" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_bitoffset .Fa "Dwarf_Die die" .Fa "Dwarf_Unsigned *ret_size" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_bitsize .Fa "Dwarf_Die die" .Fa "Dwarf_Unsigned *ret_size" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_bytesize .Fa "Dwarf_Die die" .Fa "Dwarf_Unsigned *ret_size" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_highpc .Fa "Dwarf_Die die" .Fa "Dwarf_Addr *ret_highpc" .Fa "Dwarf_Error *err" .Fc .Ft int +.Fo dwarf_highpc_b +.Fa "Dwarf_Die die" +.Fa "Dwarf_Addr *ret_highpc" +.Fa "Dwarf_Half *ret_form" +.Fa "enum Dwarf_Form_Class *ret_class" +.Fa "Dwarf_Error *err" +.Fc +.Ft int .Fo dwarf_lowpc .Fa "Dwarf_Die die" .Fa "Dwarf_Addr *ret_lowpc" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_srclang .Fa "Dwarf_Die die" .Fa "Dwarf_Unsigned *ret_lang" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION These convenience functions are used to retrieve DWARF attribute values associated with a Debugging Information Entry (DIE) descriptor denoted by argument .Ar die . These functions store the value of the requested attribute into the location pointed to by their second argument, provided that the requested attribute exists in the debugging information entry. .Pp The list of functions and the DWARF attribute that they retrieve are: .Pp .Bl -tag -width ".Fn dwarf_arrayorder" -compact .It Fn dwarf_arrayorder Retrieve the .Dv DW_AT_ordering attribute value. .It Fn dwarf_bitoffset Retrieve the .Dv DW_AT_bit_offset attribute value. .It Fn dwarf_bitsize Retrieve the .Dv DW_AT_bit_size attribute value. .It Fn dwarf_bytesize Retrieve the .Dv DW_AT_byte_size attribute value. .It Fn dwarf_highpc Retrieve the .Dv DW_AT_high_pc attribute value. +.It Fn dwarf_highpc_b +Retrieve the +.Dv DW_AT_high_pc +attribute value. .It Fn dwarf_lowpc Retrieve the .Dv DW_AT_low_pc attribute value. .It Fn dwarf_srclang Retrieve the .Dv DW_AT_language attribute value. .El +.Pp +Function +.Fn dwarf_highpc_b +is an enhanced version of function +.Fn dwarf_highpc . +It sets the location specified by argument +.Ar ret_form +to the form code of the attribute +.Dv DW_AT_high_pc , +and sets the location specified by argument +.Ar ret_class +to the class of that form. +A value of NULL may be used for either of the arguments +.Ar ret_form +or +.Ar ret_class +if the caller is not interested in the respective value. .Sh RETURN VALUES These functions return .Dv DW_DLV_OK on success. .Pp If the debugging information entry descriptor denoted by argument .Ar die does not contain the requested attribute, these functions return .Dv DW_DLV_NO_ENTRY and set argument .Ar err . For other errors, they return .Dv DW_DLV_ERROR and set argument .Ar err . .Sh ERRORS These functions can fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Arguments .Ar die , .Ar ret_highpc , .Ar ret_lowpc , .Ar ret_size , .Ar ret_lang or .Ar ret_order were NULL. .It Bq Er DW_DLE_NO_ENTRY Argument .Ar die had no requested attribute. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_attrlist 3 , -.Xr dwarf_hasattr 3 +.Xr dwarf_hasattr 3 , +.Xr dwarf_get_form_class 3 diff --git a/libdwarf/dwarf_lineno.c b/libdwarf/dwarf_lineno.c index d0c24b176b71..cbcc9aeaa69d 100644 --- a/libdwarf/dwarf_lineno.c +++ b/libdwarf/dwarf_lineno.c @@ -1,294 +1,294 @@ /*- * Copyright (c) 2009,2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_lineno.c 2074 2011-10-27 03:34:33Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_lineno.c 2983 2014-02-09 00:24:31Z kaiwang27 $"); int dwarf_srclines(Dwarf_Die die, Dwarf_Line **linebuf, Dwarf_Signed *linecount, Dwarf_Error *error) { Dwarf_LineInfo li; Dwarf_Debug dbg; Dwarf_Line ln; Dwarf_CU cu; Dwarf_Attribute at; int i; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || linebuf == NULL || linecount == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_stmt_list)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } cu = die->die_cu; if (cu->cu_lineinfo == NULL) { if (_dwarf_lineno_init(die, at->u[0].u64, error) != DW_DLE_NONE) return (DW_DLV_ERROR); } if (cu->cu_lineinfo == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } li = cu->cu_lineinfo; *linecount = (Dwarf_Signed) li->li_lnlen; if (*linecount == 0) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } if (li->li_lnarray != NULL) { *linebuf = li->li_lnarray; return (DW_DLV_OK); } - if ((li->li_lnarray = malloc(*linecount * - sizeof(struct _Dwarf_Line))) == NULL) { + if ((li->li_lnarray = malloc(*linecount * sizeof(Dwarf_Line))) == + NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLV_ERROR); } for (i = 0, ln = STAILQ_FIRST(&li->li_lnlist); i < *linecount && ln != NULL; i++, ln = STAILQ_NEXT(ln, ln_next)) li->li_lnarray[i] = ln; *linebuf = li->li_lnarray; return (DW_DLV_OK); } int dwarf_srcfiles(Dwarf_Die die, char ***srcfiles, Dwarf_Signed *srccount, Dwarf_Error *error) { Dwarf_LineInfo li; Dwarf_LineFile lf; Dwarf_Debug dbg; Dwarf_CU cu; Dwarf_Attribute at; int i; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || srcfiles == NULL || srccount == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if ((at = _dwarf_attr_find(die, DW_AT_stmt_list)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } cu = die->die_cu; if (cu->cu_lineinfo == NULL) { if (_dwarf_lineno_init(die, at->u[0].u64, error) != DW_DLE_NONE) return (DW_DLV_ERROR); } if (cu->cu_lineinfo == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } li = cu->cu_lineinfo; *srccount = (Dwarf_Signed) li->li_lflen; if (*srccount == 0) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } if (li->li_lfnarray != NULL) { *srcfiles = li->li_lfnarray; return (DW_DLV_OK); } if ((li->li_lfnarray = malloc(*srccount * sizeof(char *))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLV_ERROR); } for (i = 0, lf = STAILQ_FIRST(&li->li_lflist); i < *srccount && lf != NULL; i++, lf = STAILQ_NEXT(lf, lf_next)) { if (lf->lf_fullpath) li->li_lfnarray[i] = lf->lf_fullpath; else li->li_lfnarray[i] = lf->lf_fname; } *srcfiles = li->li_lfnarray; return (DW_DLV_OK); } int dwarf_linebeginstatement(Dwarf_Line ln, Dwarf_Bool *ret_bool, Dwarf_Error *error) { if (ln == NULL || ret_bool == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_bool = ln->ln_stmt; return (DW_DLV_OK); } int dwarf_lineendsequence(Dwarf_Line ln, Dwarf_Bool *ret_bool, Dwarf_Error *error) { if (ln == NULL || ret_bool == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_bool = ln->ln_endseq; return (DW_DLV_OK); } int dwarf_lineno(Dwarf_Line ln, Dwarf_Unsigned *ret_lineno, Dwarf_Error *error) { if (ln == NULL || ret_lineno == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_lineno = ln->ln_lineno; return (DW_DLV_OK); } int dwarf_line_srcfileno(Dwarf_Line ln, Dwarf_Unsigned *ret_fileno, Dwarf_Error *error) { if (ln == NULL || ret_fileno == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_fileno = ln->ln_fileno; return (DW_DLV_OK); } int dwarf_lineaddr(Dwarf_Line ln, Dwarf_Addr *ret_lineaddr, Dwarf_Error *error) { if (ln == NULL || ret_lineaddr == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_lineaddr = ln->ln_addr; return (DW_DLV_OK); } int dwarf_lineoff(Dwarf_Line ln, Dwarf_Signed *ret_lineoff, Dwarf_Error *error) { if (ln == NULL || ret_lineoff == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (ln->ln_column == 0) *ret_lineoff = -1; else *ret_lineoff = (Dwarf_Signed) ln->ln_column; return (DW_DLV_OK); } int dwarf_linesrc(Dwarf_Line ln, char **ret_linesrc, Dwarf_Error *error) { Dwarf_LineInfo li; Dwarf_LineFile lf; int i; if (ln == NULL || ret_linesrc == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } li = ln->ln_li; assert(li != NULL); for (i = 1, lf = STAILQ_FIRST(&li->li_lflist); (Dwarf_Unsigned) i < ln->ln_fileno && lf != NULL; i++, lf = STAILQ_NEXT(lf, lf_next)) ; if (lf == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_LINE_FILE_NUM_BAD); return (DW_DLV_ERROR); } if (lf->lf_fullpath) { *ret_linesrc = (char *) lf->lf_fullpath; return (DW_DLV_OK); } *ret_linesrc = lf->lf_fname; return (DW_DLV_OK); } int dwarf_lineblock(Dwarf_Line ln, Dwarf_Bool *ret_bool, Dwarf_Error *error) { if (ln == NULL || ret_bool == NULL) { DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *ret_bool = ln->ln_bblock; return (DW_DLV_OK); } diff --git a/libdwarf/dwarf_loclist.c b/libdwarf/dwarf_loclist.c index cf6fa9dc9f8e..e780a87128e5 100644 --- a/libdwarf/dwarf_loclist.c +++ b/libdwarf/dwarf_loclist.c @@ -1,262 +1,302 @@ /*- - * Copyright (c) 2009 Kai Wang + * Copyright (c) 2009,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_loclist.c 2074 2011-10-27 03:34:33Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_loclist.c 3066 2014-06-06 19:36:06Z kaiwang27 $"); + +static int +copy_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *dst, Dwarf_Locdesc *src, + Dwarf_Error *error) +{ + + assert(src != NULL && dst != NULL); + + dst->ld_lopc = src->ld_lopc; + dst->ld_hipc = src->ld_hipc; + dst->ld_cents = src->ld_cents; + + if (dst->ld_cents > 0) { + dst->ld_s = calloc(dst->ld_cents, sizeof(Dwarf_Loc)); + if (dst->ld_s == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); + return (DW_DLE_MEMORY); + } + memcpy(dst->ld_s, src->ld_s, src->ld_cents * + sizeof(Dwarf_Loc)); + } else + dst->ld_s = NULL; + + return (DW_DLE_NONE); +} int dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf, Dwarf_Signed *listlen, Dwarf_Error *error) { - Dwarf_Loclist ll; Dwarf_Debug dbg; int ret; dbg = at != NULL ? at->at_die->die_dbg : NULL; if (at == NULL || llbuf == NULL || listlen == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } switch (at->at_attrib) { case DW_AT_location: case DW_AT_string_length: case DW_AT_return_addr: case DW_AT_data_member_location: case DW_AT_frame_base: case DW_AT_segment: case DW_AT_static_link: case DW_AT_use_location: case DW_AT_vtable_elem_location: switch (at->at_form) { case DW_FORM_data4: case DW_FORM_data8: - ret = _dwarf_loclist_find(at->at_die->die_dbg, - at->at_die->die_cu, at->u[0].u64, &ll, error); + /* + * DW_FORM_data[48] can not be used as section offset + * since DWARF4. For DWARF[23], the application needs + * to determine if DW_FORM_data[48] is representing + * a constant or a section offset. + */ + if (at->at_die->die_cu->cu_version >= 4) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); + } + /* FALLTHROUGH */ + case DW_FORM_sec_offset: + ret = _dwarf_loclist_find(dbg, at->at_die->die_cu, + at->u[0].u64, llbuf, listlen, NULL, error); if (ret == DW_DLE_NO_ENTRY) { DWARF_SET_ERROR(dbg, error, ret); return (DW_DLV_NO_ENTRY); } if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); - *llbuf = ll->ll_ldlist; - *listlen = ll->ll_ldlen; return (DW_DLV_OK); case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: + case DW_FORM_exprloc: if (at->at_ld == NULL) { ret = _dwarf_loc_add(at->at_die, at, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); } - *llbuf = &at->at_ld; + *llbuf = calloc(1, sizeof(Dwarf_Locdesc *)); + if (*llbuf == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); + return (DW_DLV_ERROR); + } + (*llbuf)[0] = calloc(1, sizeof(Dwarf_Locdesc)); + if ((*llbuf)[0] == NULL) { + free(*llbuf); + DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); + return (DW_DLV_ERROR); + } + if (copy_locdesc(dbg, (*llbuf)[0], at->at_ld, error) != + DW_DLE_NONE) { + free((*llbuf)[0]); + free(*llbuf); + return (DW_DLV_ERROR); + } *listlen = 1; return (DW_DLV_OK); default: /* Malformed Attr? */ DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_NO_ENTRY); } default: /* Wrong attr supplied. */ DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } } int dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen, Dwarf_Error *error) { - Dwarf_Loclist ll; - Dwarf_Debug dbg; - int ret; + Dwarf_Locdesc **_llbuf; + int i, ret; - dbg = at != NULL ? at->at_die->die_dbg : NULL; + ret = dwarf_loclist_n(at, &_llbuf, listlen, error); + if (ret != DW_DLV_OK) + return (ret); - if (at == NULL || llbuf == NULL || listlen == NULL) { - DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); - return (DW_DLV_ERROR); - } + /* Only return the first location description of the list. */ + *llbuf = _llbuf[0]; - switch (at->at_attrib) { - case DW_AT_location: - case DW_AT_string_length: - case DW_AT_return_addr: - case DW_AT_data_member_location: - case DW_AT_frame_base: - case DW_AT_segment: - case DW_AT_static_link: - case DW_AT_use_location: - case DW_AT_vtable_elem_location: - switch (at->at_form) { - case DW_FORM_data4: - case DW_FORM_data8: - ret = _dwarf_loclist_find(at->at_die->die_dbg, - at->at_die->die_cu, at->u[0].u64, &ll, error); - if (ret == DW_DLE_NO_ENTRY) { - DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY); - return (DW_DLV_NO_ENTRY); - } - if (ret != DW_DLE_NONE) - return (DW_DLV_ERROR); - *llbuf = ll->ll_ldlist[0]; - *listlen = 1; - return (DW_DLV_OK); - case DW_FORM_block: - case DW_FORM_block1: - case DW_FORM_block2: - case DW_FORM_block4: - if (at->at_ld == NULL) { - ret = _dwarf_loc_add(at->at_die, at, error); - if (ret != DW_DLE_NONE) - return (DW_DLV_ERROR); - } - *llbuf = at->at_ld; - *listlen = 1; - return (DW_DLV_OK); - default: - DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); - return (DW_DLV_ERROR); - } - default: - /* Wrong attr supplied. */ - DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); - return (DW_DLV_ERROR); + /* Free the rest of the list. */ + for (i = 1; i < *listlen; i++) { + if (_llbuf[i]->ld_s) + free(_llbuf[i]->ld_s); + free(_llbuf[i]); } + free(_llbuf); + + *listlen = 1; + + return (DW_DLV_OK); } int dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset, Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data, Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry, Dwarf_Error *error) { - Dwarf_Loclist ll, next_ll; - Dwarf_Locdesc *ld; + Dwarf_Locdesc *ld, **llbuf; Dwarf_Section *ds; + Dwarf_Signed listlen; int i, ret; + /* + * Note that this API sometimes will not work correctly because + * it assumes that all units have the same pointer size and offset + * size. + */ + if (dbg == NULL || hipc == NULL || lopc == NULL || data == NULL || entry_len == NULL || next_entry == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } - ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset, &ll, - error); + ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset, + &llbuf, &listlen, entry_len, error); if (ret == DW_DLE_NO_ENTRY) { DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY); return (DW_DLV_NO_ENTRY); } else if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); *hipc = *lopc = 0; - for (i = 0; i < ll->ll_ldlen; i++) { - ld = ll->ll_ldlist[i]; + for (i = 0; i < listlen; i++) { + ld = llbuf[i]; if (i == 0) { *hipc = ld->ld_hipc; *lopc = ld->ld_lopc; } else { if (ld->ld_lopc < *lopc) *lopc = ld->ld_lopc; if (ld->ld_hipc > *hipc) *hipc = ld->ld_hipc; } } ds = _dwarf_find_section(dbg, ".debug_loc"); assert(ds != NULL); - *data = (uint8_t *) ds->ds_data + ll->ll_offset; - *entry_len = ll->ll_length; - - next_ll = TAILQ_NEXT(ll, ll_next); - if (next_ll != NULL) - *next_entry = next_ll->ll_offset; - else - *next_entry = ds->ds_size; + *data = (uint8_t *) ds->ds_data + offset; + *next_entry = offset + *entry_len; return (DW_DLV_OK); } int dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in, Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen, Dwarf_Error *error) { - Dwarf_Locdesc *ld; - int ret; - - if (dbg == NULL || bytes_in == NULL || bytes_len == 0 || - llbuf == NULL || listlen == NULL) { - DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); - return (DW_DLV_ERROR); - } - - ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, - dbg->dbg_pointer_size, error); - if (ret != DW_DLE_NONE) - return (DW_DLV_ERROR); - - *llbuf = ld; - *listlen = 1; - return (DW_DLV_OK); + return (dwarf_loclist_from_expr_a(dbg, bytes_in, bytes_len, + dbg->dbg_pointer_size, llbuf, listlen, error)); } int dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in, Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen, Dwarf_Error *error) +{ + Dwarf_Half offset_size; + Dwarf_Small version; + + /* + * Obtain offset size and DWARF version from the current + * Compilation Unit or Type Unit. These values are needed + * for correctly parsing DW_OP_GNU_implicit_pointer operator. + * + * Note that dwarf_loclist_from_expr_b() should be used instead + * if the application knows correct values for offset size + * and DWARF version. + */ + if (dbg->dbg_cu_current) { + offset_size = dbg->dbg_cu_current->cu_length_size == 4 ? 4 : 8; + version = dbg->dbg_cu_current->cu_version; + } else if (dbg->dbg_tu_current) { + offset_size = dbg->dbg_tu_current->cu_length_size == 4 ? 4 : 8; + version = dbg->dbg_tu_current->cu_version; + } else { + /* Default values if no CU/TU context. */ + offset_size = 4; + version = 2; /* DWARF2 */ + } + + return (dwarf_loclist_from_expr_b(dbg, bytes_in, bytes_len, addr_size, + offset_size, version, llbuf, listlen, error)); +} + +int +dwarf_loclist_from_expr_b(Dwarf_Debug dbg, Dwarf_Ptr bytes_in, + Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Half offset_size, + Dwarf_Small version, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen, + Dwarf_Error *error) { Dwarf_Locdesc *ld; int ret; if (dbg == NULL || bytes_in == NULL || bytes_len == 0 || llbuf == NULL || listlen == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (addr_size != 4 && addr_size != 8) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } + if (offset_size != 4 && offset_size != 8) { + DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); + return (DW_DLV_ERROR); + } + ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size, - error); + offset_size, version, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); *llbuf = ld; *listlen = 1; return (DW_DLV_OK); } diff --git a/libdwarf/dwarf_loclist_from_expr.3 b/libdwarf/dwarf_loclist_from_expr.3 index d317f7e28004..d0eb88c464d2 100644 --- a/libdwarf/dwarf_loclist_from_expr.3 +++ b/libdwarf/dwarf_loclist_from_expr.3 @@ -1,173 +1,201 @@ -.\" Copyright (c) 2011 Kai Wang +.\" Copyright (c) 2011,2014 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_loclist_from_expr.3 2074 2011-10-27 03:34:33Z jkoshy $ +.\" $Id: dwarf_loclist_from_expr.3 3129 2014-12-21 20:06:26Z jkoshy $ .\" -.Dd July 6, 2011 +.Dd December 21, 2014 .Os .Dt DWARF_LOCLIST_FROM_EXPR 3 .Sh NAME .Nm dwarf_loclist_from_expr , -.Nm dwarf_loclist_from_expr_a +.Nm dwarf_loclist_from_expr_a , +.Nm dwarf_loclist_from_expr_b .Nd translate DWARF location expression bytes .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_loclist_from_expr .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Ptr bytes_in" .Fa "Dwarf_Unsigned bytes_len" .Fa "Dwarf_Locdesc **llbuf" .Fa "Dwarf_Signed *listlen" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_loclist_from_expr_a .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Ptr bytes_in" .Fa "Dwarf_Unsigned bytes_len" .Fa "Dwarf_Half addr_size" .Fa "Dwarf_Locdesc **llbuf" .Fa "Dwarf_Signed *listlen" .Fa "Dwarf_Error *err" .Fc +.Ft int +.Fo dwarf_loclist_from_expr_b +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Ptr bytes_in" +.Fa "Dwarf_Unsigned bytes_len" +.Fa "Dwarf_Half addr_size" +.Fa "Dwarf_Half offset_size" +.Fa "Dwarf_Small version" +.Fa "Dwarf_Locdesc **llbuf" +.Fa "Dwarf_Signed *listlen" +.Fa "Dwarf_Error *error" +.Fc .Sh DESCRIPTION Function .Fn dwarf_loclist_from_expr translates DWARF location expression bytes into a .Vt Dwarf_Locdesc descriptor. The size for address related data is taken to be the default address size for the object being read. .Pp Argument .Ar dbg should reference a DWARF debug context allocated using .Xr dwarf_init 3 . .Pp Argument .Ar bytes_in should point to an array of DWARF location expression bytes. .Pp Argument .Ar bytes_len should specify the number of the location expression bytes to be translated. .Pp Argument .Ar llbuf should point to a location which will be set to a pointer to a returned .Vt Dwarf_Locdesc descriptor. .Pp Argument .Ar listlen should point to a location which will hold the number of the .Vt Dwarf_Locdesc descriptors returned. In this case it is always set to 1. .Pp If argument .Ar err is not NULL, it will be used to store error information in case of an error. .Pp Function .Fn dwarf_loclist_from_expr_a is identical to function .Fn dwarf_loclist_from_expr , except that it requires one additional argument .Ar addr_size , which specifies the address size to use when translating the location expression bytes. +.Pp +Function +.Fn dwarf_loclist_from_expr_b +is identical to function +.Fn dwarf_loclist_from_expr_a +except that it requires two additional arguments for translating the +location expression bytes. +Argument +.Ar offset_size +specifies the offset size, and argument +.Ar version +specifies the DWARF version. +These values are required to correctly translate the +.Dv DW_OP_GNU_implicit_pointer +opcode. .Ss Memory Management The memory area used for the descriptor returned in argument .Ar llbuf is allocated by .Lb libdwarf . When the descriptor is no longer needed, application code should use function .Xr dwarf_dealloc 3 to free the memory area in two steps: .Bl -enum -compact .It First, the array of .Vt Dwarf_Loc descriptors pointed to by the .Ar ld_s field of the .Vt Dwarf_Locdesc descriptor should be deallocated using the allocation type .Dv DW_DLA_LOC_BLOCK . .It Next, the application should free the .Ar llbuf pointer using the allocation type .Dv DW_DLA_LOCDESC . .El .Sh RETURN VALUES On success, these functions returns .Dv DW_DLV_OK . In case of an error, they return .Dv DW_DLV_ERROR and set the argument .Ar err . .Sh ERRORS These functions may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_LOC_EXPR_BAD" .It Bq Er DW_DLE_ARGUMENT One of the arguments .Va dbg , .Va bytes_in , .Va llbuf or .Va listlen was NULL. .It Bq Er DW_DLE_ARGUMENT Argument .Ar bytes_len was 0. .It Bq Er DW_DLE_ARGUMENT The value of argument .Ar addr_size was invalid. .It Bq Er DW_DLE_LOC_EXPR_BAD An unknown or invalid operation was found in the location expression bytes provided in argument .Ar bytes_in . .It Bq Er DW_DLE_MEMORY An out of memory condition was encountered during the execution of this function. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_dealloc 3 , .Xr dwarf_loclist_n 3 , .Xr dwarf_get_fde_info_for_all_regs3 3 , .Xr dwarf_get_fde_info_for_cfa_reg3 3 , .Xr dwarf_get_fde_info_for_reg3 3 , .Xr dwarf_get_loclist_entry 3 diff --git a/libdwarf/dwarf_next_cu_header.3 b/libdwarf/dwarf_next_cu_header.3 index 5be00b8ec4ee..f172322daa48 100644 --- a/libdwarf/dwarf_next_cu_header.3 +++ b/libdwarf/dwarf_next_cu_header.3 @@ -1,203 +1,289 @@ -.\" Copyright (c) 2010 Kai Wang +.\" Copyright (c) 2010,2014 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_next_cu_header.3 2074 2011-10-27 03:34:33Z jkoshy $ +.\" $Id: dwarf_next_cu_header.3 3128 2014-12-21 20:06:22Z jkoshy $ .\" -.Dd July 24, 2010 +.Dd December 21, 2014 .Os .Dt DWARF_NEXT_CU_HEADER 3 .Sh NAME .Nm dwarf_next_cu_header , -.Nm dwarf_next_cu_header_b +.Nm dwarf_next_cu_header_b , +.Nm dwarf_next_cu_header_c .Nd step through compilation units in a DWARF debug context .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_next_cu_header .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Unsigned *cu_length" .Fa "Dwarf_Half *cu_version" .Fa "Dwarf_Off *cu_abbrev_offset" .Fa "Dwarf_Half *cu_pointer_size" .Fa "Dwarf_Unsigned *cu_next_offset" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_next_cu_header_b .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Unsigned *cu_length" .Fa "Dwarf_Half *cu_version" .Fa "Dwarf_Off *cu_abbrev_offset" .Fa "Dwarf_Half *cu_pointer_size" .Fa "Dwarf_Half *cu_offset_size" .Fa "Dwarf_Half *cu_extension_size" .Fa "Dwarf_Unsigned *cu_next_offset" .Fa "Dwarf_Error *err" .Fc +.Ft int +.Fo dwarf_next_cu_header_c +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Bool is_info" +.Fa "Dwarf_Unsigned *cu_length" +.Fa "Dwarf_Half *cu_version" +.Fa "Dwarf_Off *cu_abbrev_offset" +.Fa "Dwarf_Half *cu_pointer_size" +.Fa "Dwarf_Half *cu_offset_size" +.Fa "Dwarf_Half *cu_extension_size" +.Fa "Dwarf_Sig8 *type_signature" +.Fa "Dwarf_Unsigned *type_offset" +.Fa "Dwarf_Unsigned *cu_next_offset" +.Fa "Dwarf_Error *err" +.Fc .Sh DESCRIPTION -These functions are used to step through compilation unit contexts +These functions are used to step through compilation or type units associated with a DWARF debug context, optionally returning information about the unit. .Pp Function -.Fn dwarf_next_cu_header_b +.Fn dwarf_next_cu_header_c is the API recommended for new application code. +Function +.Fn dwarf_next_cu_header +and +.Fn dwarf_next_cu_header_b +can only operate on compilation units associated with the +.Dq \&.debug_info +section. +They are less general than function +.Fn dwarf_next_cu_header_c , +and are deprecated for use by new application code. +.Pp Argument .Ar dbg should reference a DWARF debug context allocated using .Xr dwarf_init 3 . +If argument +.Ar is_info +is set to 1, +the function returns information for compilation units found in the +.Dq \&.debug_info +section. +If argument +.Ar is_info +is set to 0, +the function returns information for type units found in the +.Dq \&.debug_types +sections. Argument .Ar cu_length should point to a location that will be set to the -length of the compilation unit. +length of the compilation or type unit. Argument .Ar cu_version should point to a location that will be set to the -version number for the compilation unit. +version number for the compilation or type unit. Argument .Ar cu_abbrev_offset should point to a location that will be set to the starting offset (in the .Dq .debug_abbrev section) of the set of debugging information entry abbreviations -associated with this compilation unit. +associated with this compilation or type unit. Argument .Ar cu_pointer_size should point to a location that will be set to the size in bytes of an address for the machine architecture of the underlying object being debugged. Argument .Ar cu_offset_size should point to a location that will be set to the -size in bytes for a DWARF offset in the compilation unit. +size in bytes for a DWARF offset in the compilation or type unit. Argument .Ar cu_extension_size is only needed for processing MIPS/IRIX objects that use a non-standard DWARF format. It should point to a location that will be set to 4 for normal objects and to 0 for non-standard ones. Argument +.Ar type_signature +and +.Ar type_offset +is only needed for processing type units. +Argument +.Ar type_signature +should point to a location that will be set to the 64-bit unique signature +of the type described in the type unit. +Argument +.Ar type_offset +should point to a location that will be set to the offset of the debugging +information entry that describes the type. +Argument .Ar cu_next_offset should point to a location that will be set to the offset of the next compilation unit header in the .Dq \&.debug_info +section, +or the offset of the next type unit header in the +.Dq \&.debug_types section. Argument .Ar err should point to a location that will hold an error descriptor in case of an error. .Pp Function +.Fn dwarf_next_cu_header_b +is identical to function +.Fn dwarf_next_cu_header_c +except that it does not provide arguments +.Ar is_info , +.Ar type_signature +and +.Ar type_offset . +.Pp +Function .Fn dwarf_next_cu_header -is less general than -.Fn dwarf_next_cu_header_b , -and is deprecated for use by new application code. -Argument -.Ar dbg -should reference a DWARF debug context allocated using -.Xr dwarf_init 3 . -Argument -.Ar cu_length -should point to a location that will be set to the -length of the compilation unit. -Argument -.Ar cu_version -should point to a location that will be set to the -version number for the compilation unit. -Argument -.Ar cu_abbrev_offset -should point to a location that will be set to the -starting offset in the -.Dq .debug_abbrev -section of the set of debugging information entry abbreviations -associated with this compilation unit. -Argument -.Ar cu_pointer_size -should point to a location that will be set to the -size of an address in bytes for the machine architecture of the -underlying debugging object. -Argument -.Ar cu_next_offset -should point to a location that will be set to the -offset of the next compilation unit. -Argument -.Ar err -should point to a location that will hold an error descriptor in case -of an error. +is identical to function +.Fn dwarf_next_cu_header_b +except that it does not provide arguments +.Ar cu_offset_size +and +.Ar cu_extension_size . .Pp A value of NULL may be used for any of the arguments .Ar cu_length , .Ar cu_version , .Ar cu_abbrev_offset , .Ar cu_pointer_size , .Ar cu_offset_size , .Ar cu_extension_size , +.Ar type_signature , +.Ar type_offset , .Ar cu_next_offset and .Ar err if the caller is not interested in the respective value. .Ss Iterating Through Compilation Units in a Debug Context .Pp -The first call to functions -.Fn dwarf_next_cu_header_b -and -.Fn dwarf_next_cu_header -for a given debug context will return information about the first -compilation unit in the debug context. -Subsequent calls to these functions will iterate through the remaining -compilation units in the debug context. -On stepping past the last compilation unit in the debug context, -functions -.Fn dwarf_next_cu_header -and -.Fn dwarf_next_cu_header_b -return +The first call to function +.Fn dwarf_next_cu_header_c +for a given debug context with argument +.Ar is_info +set to 1 will return information about the first +compilation unit in the +.Dq \&.debug_info +section. +Subsequent calls to the function will iterate through the remaining +compilation units in the section. +On stepping past the last compilation unit in the section, +function +.Fn dwarf_next_cu_header_c +returns +.Dv DW_DLV_NO_ENTRY +and resets its internal state. +The next call to the function will restart from the first compilation +unit in the section. +.Ss Iterating Through Type Units in a Debug Context +When a DWARF debug context is allocated using +.Xr dwarf_init 3 , +an internal pointer assoicated with the context will point to the +fisrt +.Dq \&.debug_types +section found in the debug object. +The first call to function +.Fn dwarf_next_cu_header_c +for the debug context with argument +.Ar is_info +set to 0 will return information about the first +type unit in that +.Dq \&.debug_types +section. +Subsequent calls to the function will iterate through the remaining +type units in the section. +On stepping past the last type unit in the debug context, +function +.Fn dwarf_next_cu_header_c +returns +.Dv DW_DLV_NO_ENTRY +and resets its internal state. +The next call to the function will restart from the first type +unit in the +.Dq \&.debug_types +section. +.Pp +If the debug object contains multiple +.Dq \&.debug_types +sections, the function +.Fn dwarf_next_types_section +can be called to move the internal pointer to the next +.Dq \&.debug_types +section. +As a result, subsequent calls of the function +.Fn dwarf_next_cu_header_c +will operate on the new +.Dq \&.debug_types +section. +Function +.Fn dwarf_next_types_section +returns .Dv DW_DLV_NO_ENTRY -and reset their internal state. -The next call to these functions will restart from the first compilation -unit in the debug context. +when there are no more +.Dq \&.debug_types +sections left in the debug object. .Sh RETURN VALUES On success, these functions return .Dv DW_DLV_OK . In case of an error, they return .Dv DW_DLV_ERROR and set argument .Ar err . When there are no more compilation units left to traverse, they return .Dv DW_DLV_NO_ENTRY . .Sh ERRORS These functions can fail with the following error: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Argument .Va dbg was NULL. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_get_cu_die_offset_given_cu_header_offset 3 , .Xr dwarf_init 3 , +.Xr dwarf_next_types_section 3 , .Xr dwarf_siblingof 3 diff --git a/libdwarf/dwarf_next_types_section.3 b/libdwarf/dwarf_next_types_section.3 new file mode 100644 index 000000000000..98ff70d82668 --- /dev/null +++ b/libdwarf/dwarf_next_types_section.3 @@ -0,0 +1,134 @@ +.\" Copyright (c) 2014 Kai Wang +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: dwarf_next_types_section.3 3116 2014-12-20 18:26:55Z jkoshy $ +.\" +.Dd December 20, 2014 +.Os +.Dt DWARF_NEXT_TYPES_SECTION 3 +.Sh NAME +.Nm dwarf_next_types_section +.Nd step through .debug_types sections in a debug context +.Sh LIBRARY +.Lb libdwarf +.Sh SYNOPSIS +.In libdwarf.h +.Ft int +.Fo dwarf_next_types_section +.Fa "Dwarf_Debug dbg" +.Fa "Dwarf_Error *err" +.Fc +.Sh DESCRIPTION +Function +.Fn dwarf_next_types_section +steps through the +.Dq \&.debug_types +sections found in a debug context. +.Pp +Argument +.Ar dbg +should reference a DWARF debug context allocated using +.Xr dwarf_init 3 . +Argument +.Ar err +should point to a location that will hold an error descriptor in case +of an error. +.Pp +When a DWARF debug context is allocated using +.Xr dwarf_init 3 , +an internal pointer associated with the context will point to the +first +.Dq \&.debug_types +section present in the debug object. +When the application calls function +.Fn dwarf_next_types_section , +this internal pointer will move to the next +.Dq \&.debug_types +section present. +On stepping past the last +.Dq \&.debug_types +section left in the debug context, function +.Fn dwarf_next_types_section +returns +.Dv DW_DLV_NO_ENTRY . +The next call to the function will restart from the first +.Dq \&.debug_types +section in the debug context. +.Pp +Application code should call function +.Xr dwarf_next_cu_header_c 3 +to iterate though the type units associated with the current +.Dq \&.debug_types +section. +.Sh RETURN VALUES +On success, function +.Fn dwarf_next_types_section +returns +.Dv DW_DLV_OK . +.Pp +In case of an error, it returns +.Dv DW_DLV_ERROR +and sets argument +.Ar err . +When there are no more +.Dq \&.debug_types +sections left to traverse, it returns +.Dv DW_DLV_NO_ENTRY . +.Sh COMPATIBILITY +This function is an extension to the +.Xr DWARF 3 +API. +.Sh ERRORS +The +.Fn dwarf_next_types_section +function may fail with the following errors: +.Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" +.It Bq Er DW_DLE_ARGUMENT +Argument +.Va dbg +was NULL. +.El +.Sh EXAMPLES +To iterate though every type unit in all the +.Dq \&.debug_types +sections found in a debug context: +.Bd -literal -offset indent +Dwarf_Debug dbg; +Dwarf_Sig8 sig8; +Dwarf_Unsigned typeoff; +Dwarf_Error de; + +\&... allocate dbg using dwarf_init() etc ... + +do { + while ((ret = dwarf_next_cu_header_c(dbg, 0, NULL, NULL, NULL, + NULL, NULL, NULL, &sig8, &typeoff, NULL, &de)) == DW_DLV_OK) { + /* Access DIEs etc ... */ + } +} while (dwarf_next_types_section(dbg, &de) == DW_DLV_OK); +.Ed +.Sh SEE ALSO +.Xr dwarf 3 , +.Xr dwarf_init 3 , +.Xr dwarf_next_cu_header_c 3 diff --git a/libdwarf/dwarf_ranges.c b/libdwarf/dwarf_ranges.c index 9ad60832350d..2e01da553f7e 100644 --- a/libdwarf/dwarf_ranges.c +++ b/libdwarf/dwarf_ranges.c @@ -1,87 +1,87 @@ /*- * Copyright (c) 2009,2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_ranges.c 2075 2011-10-27 03:47:28Z jkoshy $"); +ELFTC_VCSID("$Id: dwarf_ranges.c 3029 2014-04-21 23:26:02Z kaiwang27 $"); static int _dwarf_get_ranges(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Off off, Dwarf_Ranges **ranges, Dwarf_Signed *ret_cnt, Dwarf_Unsigned *ret_byte_cnt, Dwarf_Error *error) { Dwarf_Rangelist rl; int ret; assert(cu != NULL); if (_dwarf_ranges_find(dbg, off, &rl) == DW_DLE_NO_ENTRY) { ret = _dwarf_ranges_add(dbg, cu, off, &rl, error); if (ret != DW_DLE_NONE) return (DW_DLV_ERROR); } *ranges = rl->rl_rgarray; *ret_cnt = rl->rl_rglen; if (ret_byte_cnt != NULL) *ret_byte_cnt = cu->cu_pointer_size * rl->rl_rglen * 2; return (DW_DLV_OK); } int dwarf_get_ranges(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Ranges **ranges, Dwarf_Signed *ret_cnt, Dwarf_Unsigned *ret_byte_cnt, Dwarf_Error *error) { if (dbg == NULL || ranges == NULL || ret_cnt == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } if (!dbg->dbg_info_loaded) { - if (_dwarf_info_load(dbg, 1, error) != DW_DLE_NONE) + if (_dwarf_info_load(dbg, 1, 1, error) != DW_DLE_NONE) return (DW_DLV_ERROR); } return (_dwarf_get_ranges(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset, ranges, ret_cnt, ret_byte_cnt, error)); } int dwarf_get_ranges_a(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die die, Dwarf_Ranges **ranges, Dwarf_Signed *ret_cnt, Dwarf_Unsigned *ret_byte_cnt, Dwarf_Error *error) { if (dbg == NULL || die == NULL || ranges == NULL || ret_cnt == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } return (_dwarf_get_ranges(dbg, die->die_cu, offset, ranges, ret_cnt, ret_byte_cnt, error)); } diff --git a/libdwarf/dwarf_sections.c b/libdwarf/dwarf_sections.c new file mode 100644 index 000000000000..d3c1379378fe --- /dev/null +++ b/libdwarf/dwarf_sections.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2014 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "_libdwarf.h" + +ELFTC_VCSID("$Id: dwarf_sections.c 3036 2014-05-05 19:19:31Z kaiwang27 $"); + +#define SET(N, V) \ + do { \ + if ((N) != NULL) \ + *(N) = (V); \ + } while (0) + +int +dwarf_get_section_max_offsets_b(Dwarf_Debug dbg, Dwarf_Unsigned *debug_info, + Dwarf_Unsigned *debug_abbrev, Dwarf_Unsigned *debug_line, + Dwarf_Unsigned *debug_loc, Dwarf_Unsigned *debug_aranges, + Dwarf_Unsigned *debug_macinfo, Dwarf_Unsigned *debug_pubnames, + Dwarf_Unsigned *debug_str, Dwarf_Unsigned *debug_frame, + Dwarf_Unsigned *debug_ranges, Dwarf_Unsigned *debug_pubtypes, + Dwarf_Unsigned *debug_types) +{ + const char *n; + Dwarf_Unsigned sz; + int i; + + if (dbg == NULL) + return (DW_DLV_ERROR); + + SET(debug_info, 0); + SET(debug_abbrev, 0); + SET(debug_line, 0); + SET(debug_loc, 0); + SET(debug_aranges, 0); + SET(debug_macinfo, 0); + SET(debug_pubnames, 0); + SET(debug_str, 0); + SET(debug_frame, 0); + SET(debug_ranges, 0); + SET(debug_pubtypes, 0); + SET(debug_types, 0); + + for (i = 0; (Dwarf_Unsigned) i < dbg->dbg_seccnt; i++) { + n = dbg->dbg_section[i].ds_name; + sz = dbg->dbg_section[i].ds_size; + if (!strcmp(n, ".debug_info")) + SET(debug_info, sz); + else if (!strcmp(n, ".debug_abbrev")) + SET(debug_abbrev, sz); + else if (!strcmp(n, ".debug_line")) + SET(debug_line, sz); + else if (!strcmp(n, ".debug_loc")) + SET(debug_loc, sz); + else if (!strcmp(n, ".debug_aranges")) + SET(debug_aranges, sz); + else if (!strcmp(n, ".debug_macinfo")) + SET(debug_macinfo, sz); + else if (!strcmp(n, ".debug_pubnames")) + SET(debug_pubnames, sz); + else if (!strcmp(n, ".debug_str")) + SET(debug_str, sz); + else if (!strcmp(n, ".debug_frame")) + SET(debug_frame, sz); + else if (!strcmp(n, ".debug_ranges")) + SET(debug_ranges, sz); + else if (!strcmp(n, ".debug_pubtypes")) + SET(debug_pubtypes, sz); + else if (!strcmp(n, ".debug_types")) + SET(debug_types, sz); + } + + return (DW_DLV_OK); +} + +int +dwarf_get_section_max_offsets(Dwarf_Debug dbg, Dwarf_Unsigned *debug_info, + Dwarf_Unsigned *debug_abbrev, Dwarf_Unsigned *debug_line, + Dwarf_Unsigned *debug_loc, Dwarf_Unsigned *debug_aranges, + Dwarf_Unsigned *debug_macinfo, Dwarf_Unsigned *debug_pubnames, + Dwarf_Unsigned *debug_str, Dwarf_Unsigned *debug_frame, + Dwarf_Unsigned *debug_ranges, Dwarf_Unsigned *debug_pubtypes) +{ + + return (dwarf_get_section_max_offsets(dbg, debug_info, debug_abbrev, + debug_line, debug_loc, debug_aranges, debug_macinfo, + debug_pubnames, debug_str, debug_frame, debug_ranges, + debug_pubtypes)); +} diff --git a/libdwarf/libdwarf.h b/libdwarf/libdwarf.h index 105a0e7d96d2..9a4a89984769 100644 --- a/libdwarf/libdwarf.h +++ b/libdwarf/libdwarf.h @@ -1,808 +1,835 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) - * Copyright (c) 2009-2011 Kai Wang + * Copyright (c) 2009-2011,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: libdwarf.h 2576 2012-09-13 09:16:11Z jkoshy $ + * $Id: libdwarf.h 3064 2014-06-06 19:35:55Z kaiwang27 $ */ #ifndef _LIBDWARF_H_ #define _LIBDWARF_H_ #include typedef int Dwarf_Bool; typedef off_t Dwarf_Off; typedef uint64_t Dwarf_Unsigned; typedef uint16_t Dwarf_Half; typedef uint8_t Dwarf_Small; typedef int64_t Dwarf_Signed; typedef uint64_t Dwarf_Addr; typedef void *Dwarf_Ptr; typedef struct _Dwarf_Abbrev *Dwarf_Abbrev; typedef struct _Dwarf_Arange *Dwarf_Arange; typedef struct _Dwarf_ArangeSet *Dwarf_ArangeSet; typedef struct _Dwarf_Attribute *Dwarf_Attribute; typedef struct _Dwarf_Attribute *Dwarf_P_Attribute; typedef struct _Dwarf_AttrDef *Dwarf_AttrDef; -typedef struct _Dwarf_CU *Dwarf_CU; typedef struct _Dwarf_Cie *Dwarf_Cie; typedef struct _Dwarf_Cie *Dwarf_P_Cie; typedef struct _Dwarf_Debug *Dwarf_Debug; typedef struct _Dwarf_Debug *Dwarf_P_Debug; typedef struct _Dwarf_Die *Dwarf_Die; typedef struct _Dwarf_Die *Dwarf_P_Die; typedef struct _Dwarf_Fde *Dwarf_Fde; typedef struct _Dwarf_Fde *Dwarf_P_Fde; typedef struct _Dwarf_FrameSec *Dwarf_FrameSec; typedef struct _Dwarf_Line *Dwarf_Line; typedef struct _Dwarf_LineFile *Dwarf_LineFile; typedef struct _Dwarf_LineInfo *Dwarf_LineInfo; -typedef struct _Dwarf_Loclist *Dwarf_Loclist; typedef struct _Dwarf_MacroSet *Dwarf_MacroSet; typedef struct _Dwarf_NamePair *Dwarf_NamePair; typedef struct _Dwarf_NamePair *Dwarf_Func; typedef struct _Dwarf_NamePair *Dwarf_Global; typedef struct _Dwarf_NamePair *Dwarf_Type; typedef struct _Dwarf_NamePair *Dwarf_Var; typedef struct _Dwarf_NamePair *Dwarf_Weak; typedef struct _Dwarf_NameTbl *Dwarf_NameTbl; typedef struct _Dwarf_NameSec *Dwarf_NameSec; typedef struct _Dwarf_P_Expr *Dwarf_P_Expr; typedef struct _Dwarf_Rangelist *Dwarf_Rangelist; typedef enum { DW_OBJECT_MSB, DW_OBJECT_LSB } Dwarf_Endianness; typedef struct { Dwarf_Addr addr; Dwarf_Unsigned size; const char *name; } Dwarf_Obj_Access_Section; typedef struct { int (*get_section_info)(void *_obj, Dwarf_Half _index, Dwarf_Obj_Access_Section *_ret_section, int *_error); Dwarf_Endianness (*get_byte_order)(void *_obj); Dwarf_Small (*get_length_size)(void *_obj); Dwarf_Small (*get_pointer_size)(void *_obj); Dwarf_Unsigned (*get_section_count)(void *_obj); int (*load_section)(void *_obj, Dwarf_Half _index, Dwarf_Small **_ret_data, int *_error); } Dwarf_Obj_Access_Methods; typedef struct { void *object; const Dwarf_Obj_Access_Methods *methods; } Dwarf_Obj_Access_Interface; typedef int (*Dwarf_Callback_Func)(char *_name, int _size, Dwarf_Unsigned _type, Dwarf_Unsigned _flags, Dwarf_Unsigned _link, Dwarf_Unsigned _info, int *_index, int *_error); typedef int (*Dwarf_Callback_Func_b)(char *_name, int _size, Dwarf_Unsigned _type, Dwarf_Unsigned _flags, Dwarf_Unsigned _link, Dwarf_Unsigned _info, Dwarf_Unsigned *_index, int *_error); typedef Dwarf_Unsigned Dwarf_Tag; typedef struct { Dwarf_Small lr_atom; Dwarf_Unsigned lr_number; Dwarf_Unsigned lr_number2; Dwarf_Unsigned lr_offset; } Dwarf_Loc; typedef struct { Dwarf_Addr ld_lopc; Dwarf_Addr ld_hipc; Dwarf_Half ld_cents; Dwarf_Loc *ld_s; } Dwarf_Locdesc; typedef struct { char signature[8]; } Dwarf_Sig8; typedef struct { Dwarf_Unsigned bl_len; Dwarf_Ptr bl_data; } Dwarf_Block; enum Dwarf_Ranges_Entry_Type { DW_RANGES_ENTRY, DW_RANGES_ADDRESS_SELECTION, DW_RANGES_END }; typedef struct { Dwarf_Unsigned dwr_addr1; Dwarf_Unsigned dwr_addr2; enum Dwarf_Ranges_Entry_Type dwr_type; } Dwarf_Ranges; enum Dwarf_Form_Class { DW_FORM_CLASS_UNKNOWN, DW_FORM_CLASS_ADDRESS, DW_FORM_CLASS_BLOCK, DW_FORM_CLASS_CONSTANT, DW_FORM_CLASS_EXPRLOC, DW_FORM_CLASS_FLAG, DW_FORM_CLASS_LINEPTR, DW_FORM_CLASS_LOCLISTPTR, DW_FORM_CLASS_MACPTR, DW_FORM_CLASS_RANGELISTPTR, DW_FORM_CLASS_REFERENCE, DW_FORM_CLASS_STRING }; #ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER #define DW_FRAME_HIGHEST_NORMAL_REGISTER 63 #endif #define DW_FRAME_RA_COL (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1) #define DW_FRAME_STATIC_LINK (DW_FRAME_HIGHEST_NORMAL_REGISTER + 2) #ifndef DW_FRAME_LAST_REG_NUM #define DW_FRAME_LAST_REG_NUM (DW_FRAME_HIGHEST_NORMAL_REGISTER + 3) #endif #ifndef DW_FRAME_REG_INITIAL_VALUE #define DW_FRAME_REG_INITIAL_VALUE DW_FRAME_SAME_VAL #endif #define DW_FRAME_UNDEFINED_VAL 1034 #define DW_FRAME_SAME_VAL 1035 #define DW_FRAME_CFA_COL3 1436 #define DW_EXPR_OFFSET 0 #define DW_EXPR_VAL_OFFSET 1 #define DW_EXPR_EXPRESSION 2 #define DW_EXPR_VAL_EXPRESSION 3 /* * Frame operation only for DWARF 2. */ #define DW_FRAME_CFA_COL 0 typedef struct { Dwarf_Small fp_base_op; Dwarf_Small fp_extended_op; Dwarf_Half fp_register; Dwarf_Signed fp_offset; Dwarf_Off fp_instr_offset; } Dwarf_Frame_Op; #ifndef DW_REG_TABLE_SIZE #define DW_REG_TABLE_SIZE 66 #endif typedef struct { struct { Dwarf_Small dw_offset_relevant; Dwarf_Half dw_regnum; Dwarf_Addr dw_offset; } rules[DW_REG_TABLE_SIZE]; } Dwarf_Regtable; /* * Frame operation for DWARF 3 and DWARF 2. */ typedef struct { Dwarf_Small fp_base_op; Dwarf_Small fp_extended_op; Dwarf_Half fp_register; Dwarf_Unsigned fp_offset_or_block_len; Dwarf_Small *fp_expr_block; Dwarf_Off fp_instr_offset; } Dwarf_Frame_Op3; typedef struct { Dwarf_Small dw_offset_relevant; Dwarf_Small dw_value_type; Dwarf_Half dw_regnum; Dwarf_Unsigned dw_offset_or_block_len; Dwarf_Ptr dw_block_ptr; } Dwarf_Regtable_Entry3; typedef struct { Dwarf_Regtable_Entry3 rt3_cfa_rule; Dwarf_Half rt3_reg_table_size; Dwarf_Regtable_Entry3 *rt3_rules; } Dwarf_Regtable3; typedef struct { Dwarf_Off dmd_offset; Dwarf_Small dmd_type; Dwarf_Signed dmd_lineno; Dwarf_Signed dmd_fileindex; char *dmd_macro; } Dwarf_Macro_Details; /* * Symbols denoting allocation types, for use with dwarf_dealloc(3). */ enum Dwarf_Allocation_Type { DW_DLA_ABBREV, DW_DLA_ADDR, DW_DLA_ARANGE, DW_DLA_ATTR, DW_DLA_BLOCK, DW_DLA_BOUNDS, DW_DLA_CIE, DW_DLA_DEBUG, DW_DLA_DIE, DW_DLA_ELLIST, DW_DLA_ERROR, DW_DLA_FDE, DW_DLA_FRAME_BLOCK, DW_DLA_FRAME_OP, DW_DLA_FUNC, DW_DLA_GLOBAL, DW_DLA_LINE, DW_DLA_LINEBUF, DW_DLA_LIST, DW_DLA_LOC, DW_DLA_LOCDESC, DW_DLA_LOC_BLOCK, DW_DLA_RANGES, DW_DLA_STRING, DW_DLA_SUBSCR, DW_DLA_TYPE, DW_DLA_TYPENAME, DW_DLA_VAR, DW_DLA_WEAK }; /* * Relocation Type. */ enum Dwarf_Rel_Type { dwarf_drt_none = 0, dwarf_drt_data_reloc, dwarf_drt_segment_rel, dwarf_drt_first_of_length_pair, dwarf_drt_second_of_length_pair }; /* * Relocation Entry. */ typedef struct Dwarf_Relocation_Data_s { unsigned char drd_type; unsigned char drd_length; Dwarf_Unsigned drd_offset; Dwarf_Unsigned drd_symbol_index; } *Dwarf_Relocation_Data; #define DWARF_DRD_BUFFER_VERSION 2 /* * Error numbers which are specific to this implementation. */ enum { DW_DLE_NONE, /* No error. */ DW_DLE_ERROR, /* An error! */ DW_DLE_ARGUMENT, /* Invalid argument. */ DW_DLE_DEBUG_INFO_NULL, /* Debug info NULL. */ DW_DLE_NO_ENTRY, /* No entry. */ DW_DLE_MEMORY, /* Insufficient memory. */ DW_DLE_ELF, /* ELF error. */ DW_DLE_CU_LENGTH_ERROR, /* Invalid compilation unit data. */ DW_DLE_VERSION_STAMP_ERROR, /* Invalid version. */ DW_DLE_DEBUG_ABBREV_NULL, /* Abbrev not found. */ DW_DLE_DIE_NO_CU_CONTEXT, /* No current compilation unit. */ DW_DLE_LOC_EXPR_BAD, /* Invalid location expression. */ DW_DLE_EXPR_LENGTH_BAD, /* Invalid DWARF expression. */ DW_DLE_DEBUG_LOC_SECTION_SHORT, /* Loclist section too short. */ DW_DLE_ATTR_FORM_BAD, /* Invalid attribute form. */ DW_DLE_DEBUG_LINE_LENGTH_BAD, /* Line info section too short. */ DW_DLE_LINE_FILE_NUM_BAD, /* Invalid file number. */ DW_DLE_DIR_INDEX_BAD, /* Invalid dir index. */ DW_DLE_DEBUG_FRAME_LENGTH_BAD, /* Frame section too short. */ DW_DLE_NO_CIE_FOR_FDE, /* CIE not found for certain FDE. */ DW_DLE_FRAME_AUGMENTATION_UNKNOWN, /* Unknown CIE augmentation. */ DW_DLE_FRAME_INSTR_EXEC_ERROR, /* Frame instruction exec error. */ DW_DLE_FRAME_VERSION_BAD, /* Invalid frame section version. */ DW_DLE_FRAME_TABLE_COL_BAD, /* Invalid table column. */ DW_DLE_DF_REG_NUM_TOO_HIGH, /* Insufficient regtable space. */ DW_DLE_PC_NOT_IN_FDE_RANGE, /* PC requested not in the FDE range. */ DW_DLE_ARANGE_OFFSET_BAD, /* Invalid arange offset. */ DW_DLE_DEBUG_MACRO_INCONSISTENT,/* Invalid macinfo data. */ DW_DLE_ELF_SECT_ERR, /* Application callback failed. */ DW_DLE_NUM /* Max error number. */ }; /* * Mapping of SGI libdwarf error codes for comptibility. */ #define DW_DLE_DBG_ALLOC DW_DLE_MEMORY #define DW_DLE_ALLOC_FAIL DW_DLE_MEMORY #define DW_DLE_SECT_ALLOC DW_DLE_MEMORY #define DW_DLE_FILE_ENTRY_ALLOC DW_DLE_MEMORY #define DW_DLE_LINE_ALLOC DW_DLE_MEMORY #define DW_DLE_FPGM_ALLOC DW_DLE_MEMORY #define DW_DLE_INCDIR_ALLOC DW_DLE_MEMORY #define DW_DLE_STRING_ALLOC DW_DLE_MEMORY #define DW_DLE_CHUNK_ALLOC DW_DLE_MEMORY #define DW_DLE_CIE_ALLOC DW_DLE_MEMORY #define DW_DLE_FDE_ALLOC DW_DLE_MEMORY #define DW_DLE_CIE_OFFS_ALLOC DW_DLE_MEMORY #define DW_DLE_DIE_ALLOC DW_DLE_MEMORY #define DW_DLE_ATTR_ALLOC DW_DLE_MEMORY #define DW_DLE_ABBREV_ALLOC DW_DLE_MEMORY #define DW_DLE_ADDR_ALLOC DW_DLE_MEMORY #define DW_DLE_REL_ALLOC DW_DLE_MEMORY #define DW_DLE_MACINFO_MALLOC_FAIL DW_DLE_MEMORY #define DW_DLE_DEBUG_MACRO_MALLOC_SPACE DW_DLE_MEMORY #define DW_DLE_DF_ALLOC_FAIL DW_DLE_MEMORY #define DW_DLE_RELOC_SECTION_MALLOC_FAIL DW_DLE_MEMORY #define DW_DLE_DBG_NULL DW_DLE_ARGUMENT #define DW_DLE_DIE_NULL DW_DLE_ARGUMENT #define DW_DLE_FDE_NULL DW_DLE_ARGUMENT #define DW_DLE_CIE_NULL DW_DLE_ARGUMENT #define DW_DLE_ATTR_NULL DW_DLE_ARGUMENT #define DW_DLE_GLOBAL_NULL DW_DLE_ARGUMENT #define DW_DLE_ARANGES_NULL DW_DLE_ARGUMENT #define DW_DLE_ARANGE_NULL DW_DLE_ARGUMENT #define DW_DLE_EXPR_NULL DW_DLE_ARGUMENT #define DW_DLE_FUNC_NULL DW_DLE_ARGUMENT #define DW_DLE_TYPE_NULL DW_DLE_ARGUMENT #define DW_DLE_VAR_NULL DW_DLE_ARGUMENT #define DW_DLE_WEAK_NULL DW_DLE_ARGUMENT #define DW_DLE_ELF_BEGIN_ERROR DW_DLE_ELF #define DW_DLE_ELF_GETEHDR_ERROR DW_DLE_ELF #define DW_DLE_ELF_GETSHDR_ERROR DW_DLE_ELF #define DW_DLE_ELF_STRPTR_ERROR DW_DLE_ELF #define DW_DLE_ELF_SECT_ERROR DW_DLE_ELF #define DW_DLE_ELF_GETIDENT_ERROR DW_DLE_ELF typedef struct _Dwarf_Error { int err_error; /* DWARF error. */ int err_elferror; /* ELF error. */ const char *err_func; /* Function name where error occurred. */ int err_line; /* Line number where error occurred. */ char err_msg[1024]; /* Formatted error message. */ } Dwarf_Error; /* * Dwarf error handler. */ typedef void (*Dwarf_Handler)(Dwarf_Error, Dwarf_Ptr); #define dwarf_errno(error) error.err_error #define dwarf_errmsg(error) dwarf_errmsg_(&error) /* * Return values which have to be compatible with other * implementations of libdwarf. */ #define DW_DLV_NO_ENTRY -1 #define DW_DLV_OK 0 #define DW_DLV_ERROR 1 #define DW_DLV_BADADDR NULL #define DW_DLV_NOCOUNT ((Dwarf_Signed) -1) /* * Access modes. */ #define DW_DLC_READ 0x0001 #define DW_DLC_WRITE 0x0002 #define DW_DLC_RDWR 0x0004 /* * Flags used by libdwarf producer. */ #define DW_DLC_SIZE_64 0x40000000 #define DW_DLC_SIZE_32 0x20000000 #define DW_DLC_OFFSET_SIZE_64 0x10000000 #define DW_DLC_ISA_MIPS 0x80000000 #define DW_DLC_ISA_IA64 0x01000000 #define DW_DLC_STREAM_RELOCATIONS 0x02000000 #define DW_DLC_SYMBOLIC_RELOCATIONS 0x04000000 #define DW_DLC_TARGET_BIGENDIAN 0x08000000 #define DW_DLC_TARGET_LITTLEENDIAN 0x00100000 /* * Instruction set architectures supported by this implementation. */ enum Dwarf_ISA { DW_ISA_ARM, DW_ISA_IA64, DW_ISA_MIPS, DW_ISA_PPC, DW_ISA_SPARC, DW_ISA_X86, DW_ISA_X86_64, DW_ISA_MAX }; /* Function prototype definitions. */ __BEGIN_DECLS Dwarf_P_Attribute dwarf_add_AT_comp_dir(Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_const_value_signedint(Dwarf_P_Die, Dwarf_Signed, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_const_value_string(Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_const_value_unsignedint(Dwarf_P_Die, Dwarf_Unsigned, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_dataref(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_flag(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Small, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_location_expr(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_P_Expr, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_producer(Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_ref_address(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_reference(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_P_Die, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_signed_const(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Signed, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_string(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, char *, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_targ_address(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Unsigned, Dwarf_Signed, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_targ_address_b(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_P_Attribute dwarf_add_AT_unsigned_const(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Half, Dwarf_Unsigned, Dwarf_Error *); Dwarf_Unsigned dwarf_add_arange(Dwarf_P_Debug, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Signed, Dwarf_Error *); Dwarf_Unsigned dwarf_add_arange_b(Dwarf_P_Debug, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Addr, Dwarf_Error *); Dwarf_Unsigned dwarf_add_die_to_debug(Dwarf_P_Debug, Dwarf_P_Die, Dwarf_Error *); Dwarf_Unsigned dwarf_add_directory_decl(Dwarf_P_Debug, char *, Dwarf_Error *); Dwarf_Unsigned dwarf_add_expr_addr(Dwarf_P_Expr, Dwarf_Unsigned, Dwarf_Signed, Dwarf_Error *); Dwarf_Unsigned dwarf_add_expr_addr_b(Dwarf_P_Expr, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_Unsigned dwarf_add_expr_gen(Dwarf_P_Expr, Dwarf_Small, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_P_Fde dwarf_add_fde_inst(Dwarf_P_Fde, Dwarf_Small, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_Unsigned dwarf_add_file_decl(Dwarf_P_Debug, char *, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_Unsigned dwarf_add_frame_cie(Dwarf_P_Debug, char *, Dwarf_Small, Dwarf_Small, Dwarf_Small, Dwarf_Ptr, Dwarf_Unsigned, Dwarf_Error *); Dwarf_Unsigned dwarf_add_frame_fde(Dwarf_P_Debug, Dwarf_P_Fde, Dwarf_P_Die, Dwarf_Unsigned, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); Dwarf_Unsigned dwarf_add_frame_fde_b(Dwarf_P_Debug, Dwarf_P_Fde, Dwarf_P_Die, Dwarf_Unsigned, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Addr, Dwarf_Error *); Dwarf_Unsigned dwarf_add_funcname(Dwarf_P_Debug, Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_Unsigned dwarf_add_line_entry(Dwarf_P_Debug, Dwarf_Unsigned, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Signed, Dwarf_Bool, Dwarf_Bool, Dwarf_Error *); Dwarf_Unsigned dwarf_add_pubname(Dwarf_P_Debug, Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_Unsigned dwarf_add_typename(Dwarf_P_Debug, Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_Unsigned dwarf_add_varname(Dwarf_P_Debug, Dwarf_P_Die, char *, Dwarf_Error *); Dwarf_Unsigned dwarf_add_weakname(Dwarf_P_Debug, Dwarf_P_Die, char *, Dwarf_Error *); int dwarf_arrayorder(Dwarf_Die, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_attr(Dwarf_Die, Dwarf_Half, Dwarf_Attribute *, Dwarf_Error *); int dwarf_attrlist(Dwarf_Die, Dwarf_Attribute **, Dwarf_Signed *, Dwarf_Error *); +int dwarf_attroffset(Dwarf_Attribute, Dwarf_Off *, Dwarf_Error *); int dwarf_attrval_flag(Dwarf_Die, Dwarf_Half, Dwarf_Bool *, Dwarf_Error *); int dwarf_attrval_signed(Dwarf_Die, Dwarf_Half, Dwarf_Signed *, Dwarf_Error *); int dwarf_attrval_string(Dwarf_Die, Dwarf_Half, const char **, Dwarf_Error *); int dwarf_attrval_unsigned(Dwarf_Die, Dwarf_Half, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_bitoffset(Dwarf_Die, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_bitsize(Dwarf_Die, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_bytesize(Dwarf_Die, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_child(Dwarf_Die, Dwarf_Die *, Dwarf_Error *); void dwarf_dealloc(Dwarf_Debug, Dwarf_Ptr, Dwarf_Unsigned); int dwarf_def_macro(Dwarf_P_Debug, Dwarf_Unsigned, char *, char *, Dwarf_Error *); int dwarf_die_CU_offset(Dwarf_Die, Dwarf_Off *, Dwarf_Error *); int dwarf_die_CU_offset_range(Dwarf_Die, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); int dwarf_die_abbrev_code(Dwarf_Die); Dwarf_P_Die dwarf_die_link(Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_Error *); int dwarf_diename(Dwarf_Die, char **, Dwarf_Error *); int dwarf_dieoffset(Dwarf_Die, Dwarf_Off *, Dwarf_Error *); int dwarf_elf_init(Elf *, int, Dwarf_Handler, Dwarf_Ptr, Dwarf_Debug *, Dwarf_Error *); int dwarf_end_macro_file(Dwarf_P_Debug, Dwarf_Error *); const char *dwarf_errmsg_(Dwarf_Error *); int dwarf_expand_frame_instructions(Dwarf_Cie, Dwarf_Ptr, Dwarf_Unsigned, Dwarf_Frame_Op **, Dwarf_Signed *, Dwarf_Error *); Dwarf_Unsigned dwarf_expr_current_offset(Dwarf_P_Expr, Dwarf_Error *); Dwarf_Addr dwarf_expr_into_block(Dwarf_P_Expr, Dwarf_Unsigned *, Dwarf_Error *); Dwarf_P_Fde dwarf_fde_cfa_offset(Dwarf_P_Fde, Dwarf_Unsigned, Dwarf_Signed, Dwarf_Error *); void dwarf_fde_cie_list_dealloc(Dwarf_Debug, Dwarf_Cie *, Dwarf_Signed, Dwarf_Fde *, Dwarf_Signed); char *dwarf_find_macro_value_start(char *); int dwarf_finish(Dwarf_Debug, Dwarf_Error *); int dwarf_formaddr(Dwarf_Attribute, Dwarf_Addr *, Dwarf_Error *); int dwarf_formblock(Dwarf_Attribute, Dwarf_Block **, Dwarf_Error *); int dwarf_formexprloc(Dwarf_Attribute, Dwarf_Unsigned *, Dwarf_Ptr *, Dwarf_Error *); int dwarf_formflag(Dwarf_Attribute, Dwarf_Bool *, Dwarf_Error *); int dwarf_formref(Dwarf_Attribute, Dwarf_Off *, Dwarf_Error *); int dwarf_formsdata(Dwarf_Attribute, Dwarf_Signed *, Dwarf_Error *); int dwarf_formsig8(Dwarf_Attribute, Dwarf_Sig8 *, Dwarf_Error *); int dwarf_formstring(Dwarf_Attribute, char **, Dwarf_Error *); int dwarf_formudata(Dwarf_Attribute, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_func_cu_offset(Dwarf_Func, Dwarf_Off *, Dwarf_Error *); int dwarf_func_die_offset(Dwarf_Func, Dwarf_Off *, Dwarf_Error *); int dwarf_func_name_offsets(Dwarf_Func, char **, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); int dwarf_funcname(Dwarf_Func, char **, Dwarf_Error *); void dwarf_funcs_dealloc(Dwarf_Debug, Dwarf_Func *, Dwarf_Signed); int dwarf_get_ACCESS_name(unsigned, const char **); int dwarf_get_ATE_name(unsigned, const char **); int dwarf_get_AT_name(unsigned, const char **); int dwarf_get_CC_name(unsigned, const char **); int dwarf_get_CFA_name(unsigned, const char **); int dwarf_get_CHILDREN_name(unsigned, const char **); int dwarf_get_DSC_name(unsigned, const char **); int dwarf_get_DS_name(unsigned, const char **); int dwarf_get_EH_name(unsigned, const char **); int dwarf_get_END_name(unsigned, const char **); int dwarf_get_FORM_name(unsigned, const char **); int dwarf_get_ID_name(unsigned, const char **); int dwarf_get_INL_name(unsigned, const char **); int dwarf_get_LANG_name(unsigned, const char **); int dwarf_get_LNE_name(unsigned, const char **); int dwarf_get_LNS_name(unsigned, const char **); int dwarf_get_MACINFO_name(unsigned, const char **); int dwarf_get_OP_name(unsigned, const char **); int dwarf_get_ORD_name(unsigned, const char **); int dwarf_get_TAG_name(unsigned, const char **); int dwarf_get_VIRTUALITY_name(unsigned, const char **); int dwarf_get_VIS_name(unsigned, const char **); int dwarf_get_abbrev(Dwarf_Debug, Dwarf_Unsigned, Dwarf_Abbrev *, Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_abbrev_children_flag(Dwarf_Abbrev, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_abbrev_code(Dwarf_Abbrev, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_abbrev_entry(Dwarf_Abbrev, Dwarf_Signed, Dwarf_Half *, Dwarf_Signed *, Dwarf_Off *, Dwarf_Error *); int dwarf_get_abbrev_tag(Dwarf_Abbrev, Dwarf_Half *, Dwarf_Error *); int dwarf_get_address_size(Dwarf_Debug, Dwarf_Half *, Dwarf_Error *); int dwarf_get_arange(Dwarf_Arange *, Dwarf_Unsigned, Dwarf_Addr, Dwarf_Arange *, Dwarf_Error *); int dwarf_get_arange_cu_header_offset(Dwarf_Arange, Dwarf_Off *, Dwarf_Error *); int dwarf_get_arange_info(Dwarf_Arange, Dwarf_Addr *, Dwarf_Unsigned *, Dwarf_Off *, Dwarf_Error *); int dwarf_get_aranges(Dwarf_Debug, Dwarf_Arange **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_cie_index(Dwarf_Cie, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_cie_info(Dwarf_Cie, Dwarf_Unsigned *, Dwarf_Small *, char **, Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Half *, Dwarf_Ptr *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_cie_of_fde(Dwarf_Fde, Dwarf_Cie *, Dwarf_Error *); int dwarf_get_cu_die_offset(Dwarf_Arange, Dwarf_Off *, Dwarf_Error *); int dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug, Dwarf_Off, Dwarf_Off *, Dwarf_Error *); +int dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug, + Dwarf_Off, Dwarf_Bool, Dwarf_Off *, Dwarf_Error *); +Dwarf_Bool dwarf_get_die_infotypes_flag(Dwarf_Die); int dwarf_get_elf(Dwarf_Debug, Elf **, Dwarf_Error *); int dwarf_get_fde_at_pc(Dwarf_Fde *, Dwarf_Addr, Dwarf_Fde *, Dwarf_Addr *, Dwarf_Addr *, Dwarf_Error *); int dwarf_get_fde_info_for_all_regs(Dwarf_Fde, Dwarf_Addr, Dwarf_Regtable *, Dwarf_Addr *, Dwarf_Error *); int dwarf_get_fde_info_for_all_regs3(Dwarf_Fde, Dwarf_Addr, Dwarf_Regtable3 *, Dwarf_Addr *, Dwarf_Error *); int dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde, Dwarf_Addr, Dwarf_Small *, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Ptr *, Dwarf_Addr *, Dwarf_Error *); int dwarf_get_fde_info_for_reg(Dwarf_Fde, Dwarf_Half, Dwarf_Addr, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Addr *, Dwarf_Error *); int dwarf_get_fde_info_for_reg3(Dwarf_Fde, Dwarf_Half, Dwarf_Addr, Dwarf_Small *, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Ptr *, Dwarf_Addr *, Dwarf_Error *); int dwarf_get_fde_instr_bytes(Dwarf_Fde, Dwarf_Ptr *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_fde_list(Dwarf_Debug, Dwarf_Cie **, Dwarf_Signed *, Dwarf_Fde **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_fde_list_eh(Dwarf_Debug, Dwarf_Cie **, Dwarf_Signed *, Dwarf_Fde **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_fde_n(Dwarf_Fde *, Dwarf_Unsigned, Dwarf_Fde *, Dwarf_Error *); int dwarf_get_fde_range(Dwarf_Fde, Dwarf_Addr *, Dwarf_Unsigned *, Dwarf_Ptr *, Dwarf_Unsigned *, Dwarf_Off *, Dwarf_Signed *, Dwarf_Off *, Dwarf_Error *); enum Dwarf_Form_Class dwarf_get_form_class(Dwarf_Half, Dwarf_Half, Dwarf_Half, Dwarf_Half); int dwarf_get_funcs(Dwarf_Debug, Dwarf_Func **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_globals(Dwarf_Debug, Dwarf_Global **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_loclist_entry(Dwarf_Debug, Dwarf_Unsigned, Dwarf_Addr *, Dwarf_Addr *, Dwarf_Ptr *, Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_macro_details(Dwarf_Debug, Dwarf_Off, Dwarf_Unsigned, Dwarf_Signed *, Dwarf_Macro_Details **, Dwarf_Error *); int dwarf_get_pubtypes(Dwarf_Debug, Dwarf_Type **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_ranges(Dwarf_Debug, Dwarf_Off, Dwarf_Ranges **, Dwarf_Signed *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_ranges_a(Dwarf_Debug, Dwarf_Off, Dwarf_Die, Dwarf_Ranges **, Dwarf_Signed *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_get_relocation_info(Dwarf_P_Debug, Dwarf_Signed *, Dwarf_Signed *, Dwarf_Unsigned *, Dwarf_Relocation_Data *, Dwarf_Error *); int dwarf_get_relocation_info_count(Dwarf_P_Debug, Dwarf_Unsigned *, int *, Dwarf_Error *); Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug, Dwarf_Signed, Dwarf_Signed *, Dwarf_Unsigned *, Dwarf_Error *); +int dwarf_get_section_max_offsets(Dwarf_Debug, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Unsigned *, + Dwarf_Unsigned *); +int dwarf_get_section_max_offsets_b(Dwarf_Debug, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Unsigned *); int dwarf_get_str(Dwarf_Debug, Dwarf_Off, char **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_types(Dwarf_Debug, Dwarf_Type **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_vars(Dwarf_Debug, Dwarf_Var **, Dwarf_Signed *, Dwarf_Error *); int dwarf_get_weaks(Dwarf_Debug, Dwarf_Weak **, Dwarf_Signed *, Dwarf_Error *); int dwarf_global_cu_offset(Dwarf_Global, Dwarf_Off *, Dwarf_Error *); int dwarf_global_die_offset(Dwarf_Global, Dwarf_Off *, Dwarf_Error *); int dwarf_global_formref(Dwarf_Attribute, Dwarf_Off *, Dwarf_Error *); int dwarf_global_name_offsets(Dwarf_Global, char **, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); void dwarf_globals_dealloc(Dwarf_Debug, Dwarf_Global *, Dwarf_Signed); int dwarf_globname(Dwarf_Global, char **, Dwarf_Error *); int dwarf_hasattr(Dwarf_Die, Dwarf_Half, Dwarf_Bool *, Dwarf_Error *); int dwarf_hasform(Dwarf_Attribute, Dwarf_Half, Dwarf_Bool *, Dwarf_Error *); int dwarf_highpc(Dwarf_Die, Dwarf_Addr *, Dwarf_Error *); +int dwarf_highpc_b(Dwarf_Die, Dwarf_Addr *, Dwarf_Half *, + enum Dwarf_Form_Class *, Dwarf_Error *); int dwarf_init(int, int, Dwarf_Handler, Dwarf_Ptr, Dwarf_Debug *, Dwarf_Error *); int dwarf_line_srcfileno(Dwarf_Line, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_lineaddr(Dwarf_Line, Dwarf_Addr *, Dwarf_Error *); int dwarf_linebeginstatement(Dwarf_Line, Dwarf_Bool *, Dwarf_Error *); int dwarf_lineblock(Dwarf_Line, Dwarf_Bool *, Dwarf_Error *); int dwarf_lineendsequence(Dwarf_Line, Dwarf_Bool *, Dwarf_Error *); int dwarf_lineno(Dwarf_Line, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_lineoff(Dwarf_Line, Dwarf_Signed *, Dwarf_Error *); int dwarf_linesrc(Dwarf_Line, char **, Dwarf_Error *); Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug, Dwarf_Addr, Dwarf_Error *); Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Error *); int dwarf_loclist(Dwarf_Attribute, Dwarf_Locdesc **, Dwarf_Signed *, Dwarf_Error *); int dwarf_loclist_from_expr(Dwarf_Debug, Dwarf_Ptr, Dwarf_Unsigned, Dwarf_Locdesc **, Dwarf_Signed *, Dwarf_Error *); int dwarf_loclist_from_expr_a(Dwarf_Debug, Dwarf_Ptr, Dwarf_Unsigned, Dwarf_Half, Dwarf_Locdesc **, Dwarf_Signed *, Dwarf_Error *); +int dwarf_loclist_from_expr_b(Dwarf_Debug, Dwarf_Ptr, + Dwarf_Unsigned, Dwarf_Half, Dwarf_Half, + Dwarf_Small, Dwarf_Locdesc **, Dwarf_Signed *, + Dwarf_Error *); int dwarf_loclist_n(Dwarf_Attribute, Dwarf_Locdesc ***, Dwarf_Signed *, Dwarf_Error *); int dwarf_lowpc(Dwarf_Die, Dwarf_Addr *, Dwarf_Error *); Dwarf_P_Die dwarf_new_die(Dwarf_P_Debug, Dwarf_Tag, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_P_Die, Dwarf_Error *); Dwarf_P_Expr dwarf_new_expr(Dwarf_P_Debug, Dwarf_Error *); Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug, Dwarf_Error *); int dwarf_next_cu_header(Dwarf_Debug, Dwarf_Unsigned *, Dwarf_Half *, Dwarf_Off *, Dwarf_Half *, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_next_cu_header_b(Dwarf_Debug, Dwarf_Unsigned *, Dwarf_Half *, Dwarf_Off *, Dwarf_Half *, Dwarf_Half *, Dwarf_Half *, Dwarf_Unsigned *, Dwarf_Error *); +int dwarf_next_cu_header_c(Dwarf_Debug, Dwarf_Bool, + Dwarf_Unsigned *, Dwarf_Half *, Dwarf_Off *, Dwarf_Half *, + Dwarf_Half *, Dwarf_Half *, Dwarf_Sig8 *, Dwarf_Unsigned *, + Dwarf_Unsigned *, Dwarf_Error *); +int dwarf_next_types_section(Dwarf_Debug, Dwarf_Error *); int dwarf_object_finish(Dwarf_Debug, Dwarf_Error *); int dwarf_object_init(Dwarf_Obj_Access_Interface *, Dwarf_Handler, Dwarf_Ptr, Dwarf_Debug *, Dwarf_Error *); int dwarf_offdie(Dwarf_Debug, Dwarf_Off, Dwarf_Die *, Dwarf_Error *); +int dwarf_offdie_b(Dwarf_Debug, Dwarf_Off, Dwarf_Bool, Dwarf_Die *, + Dwarf_Error *); Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug, Dwarf_Error *); Dwarf_P_Debug dwarf_producer_init(Dwarf_Unsigned, Dwarf_Callback_Func, Dwarf_Handler, Dwarf_Ptr, Dwarf_Error *); Dwarf_P_Debug dwarf_producer_init_b(Dwarf_Unsigned, Dwarf_Callback_Func_b, Dwarf_Handler, Dwarf_Ptr, Dwarf_Error *); int dwarf_producer_set_isa(Dwarf_P_Debug, enum Dwarf_ISA, Dwarf_Error *); int dwarf_pubtype_cu_offset(Dwarf_Type, Dwarf_Off *, Dwarf_Error *); int dwarf_pubtype_die_offset(Dwarf_Type, Dwarf_Off *, Dwarf_Error *); int dwarf_pubtype_name_offsets(Dwarf_Type, char **, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); int dwarf_pubtypename(Dwarf_Type, char **, Dwarf_Error *); void dwarf_pubtypes_dealloc(Dwarf_Debug, Dwarf_Type *, Dwarf_Signed); void dwarf_ranges_dealloc(Dwarf_Debug, Dwarf_Ranges *, Dwarf_Signed); void dwarf_reset_section_bytes(Dwarf_P_Debug); Dwarf_Half dwarf_set_frame_cfa_value(Dwarf_Debug, Dwarf_Half); Dwarf_Half dwarf_set_frame_rule_initial_value(Dwarf_Debug, Dwarf_Half); Dwarf_Half dwarf_set_frame_rule_table_size(Dwarf_Debug, Dwarf_Half); Dwarf_Half dwarf_set_frame_same_value(Dwarf_Debug, Dwarf_Half); Dwarf_Half dwarf_set_frame_undefined_value(Dwarf_Debug, Dwarf_Half); int dwarf_set_reloc_application(int); Dwarf_Ptr dwarf_seterrarg(Dwarf_Debug, Dwarf_Ptr); Dwarf_Handler dwarf_seterrhand(Dwarf_Debug, Dwarf_Handler); int dwarf_siblingof(Dwarf_Debug, Dwarf_Die, Dwarf_Die *, Dwarf_Error *); +int dwarf_siblingof_b(Dwarf_Debug, Dwarf_Die, Dwarf_Die *, Dwarf_Bool, + Dwarf_Error *); int dwarf_srcfiles(Dwarf_Die, char ***, Dwarf_Signed *, Dwarf_Error *); int dwarf_srclang(Dwarf_Die, Dwarf_Unsigned *, Dwarf_Error *); int dwarf_srclines(Dwarf_Die, Dwarf_Line **, Dwarf_Signed *, Dwarf_Error *); void dwarf_srclines_dealloc(Dwarf_Debug, Dwarf_Line *, Dwarf_Signed); int dwarf_start_macro_file(Dwarf_P_Debug, Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Error *); int dwarf_tag(Dwarf_Die, Dwarf_Half *, Dwarf_Error *); Dwarf_Signed dwarf_transform_to_disk_form(Dwarf_P_Debug, Dwarf_Error *); int dwarf_type_cu_offset(Dwarf_Type, Dwarf_Off *, Dwarf_Error *); int dwarf_type_die_offset(Dwarf_Type, Dwarf_Off *, Dwarf_Error *); int dwarf_type_name_offsets(Dwarf_Type, char **, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); int dwarf_typename(Dwarf_Type, char **, Dwarf_Error *); void dwarf_types_dealloc(Dwarf_Debug, Dwarf_Type *, Dwarf_Signed); int dwarf_undef_macro(Dwarf_P_Debug, Dwarf_Unsigned, char *, Dwarf_Error *); int dwarf_var_cu_offset(Dwarf_Var, Dwarf_Off *, Dwarf_Error *); int dwarf_var_die_offset(Dwarf_Var, Dwarf_Off *, Dwarf_Error *); int dwarf_var_name_offsets(Dwarf_Var, char **, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); int dwarf_varname(Dwarf_Var, char **, Dwarf_Error *); void dwarf_vars_dealloc(Dwarf_Debug, Dwarf_Var *, Dwarf_Signed); int dwarf_vendor_ext(Dwarf_P_Debug, Dwarf_Unsigned, char *, Dwarf_Error *); int dwarf_weak_cu_offset(Dwarf_Weak, Dwarf_Off *, Dwarf_Error *); int dwarf_weak_die_offset(Dwarf_Weak, Dwarf_Off *, Dwarf_Error *); int dwarf_weak_name_offsets(Dwarf_Weak, char **, Dwarf_Off *, Dwarf_Off *, Dwarf_Error *); int dwarf_weakname(Dwarf_Weak, char **, Dwarf_Error *); void dwarf_weaks_dealloc(Dwarf_Debug, Dwarf_Weak *, Dwarf_Signed); int dwarf_whatattr(Dwarf_Attribute, Dwarf_Half *, Dwarf_Error *); int dwarf_whatform(Dwarf_Attribute, Dwarf_Half *, Dwarf_Error *); int dwarf_whatform_direct(Dwarf_Attribute, Dwarf_Half *, Dwarf_Error *); __END_DECLS #endif /* !_LIBDWARF_H_ */ diff --git a/libdwarf/libdwarf_arange.c b/libdwarf/libdwarf_arange.c index 75434f6ae20b..eefb63ba6b10 100644 --- a/libdwarf/libdwarf_arange.c +++ b/libdwarf/libdwarf_arange.c @@ -1,260 +1,260 @@ /*- * Copyright (c) 2009-2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_arange.c 2070 2011-10-27 03:05:32Z jkoshy $"); +ELFTC_VCSID("$Id: libdwarf_arange.c 3029 2014-04-21 23:26:02Z kaiwang27 $"); void _dwarf_arange_cleanup(Dwarf_Debug dbg) { Dwarf_ArangeSet as, tas; Dwarf_Arange ar, tar; STAILQ_FOREACH_SAFE(as, &dbg->dbg_aslist, as_next, tas) { STAILQ_FOREACH_SAFE(ar, &as->as_arlist, ar_next, tar) { STAILQ_REMOVE(&as->as_arlist, ar, _Dwarf_Arange, ar_next); free(ar); } STAILQ_REMOVE(&dbg->dbg_aslist, as, _Dwarf_ArangeSet, as_next); free(as); } if (dbg->dbg_arange_array) free(dbg->dbg_arange_array); dbg->dbg_arange_array = NULL; dbg->dbg_arange_cnt = 0; } int _dwarf_arange_init(Dwarf_Debug dbg, Dwarf_Error *error) { Dwarf_CU cu; Dwarf_ArangeSet as; Dwarf_Arange ar; Dwarf_Section *ds; uint64_t offset, dwarf_size, length, addr, range; int i, ret; ret = DW_DLE_NONE; if ((ds = _dwarf_find_section(dbg, ".debug_aranges")) == NULL) return (DW_DLE_NONE); if (!dbg->dbg_info_loaded) { - ret = _dwarf_info_load(dbg, 1, error); + ret = _dwarf_info_load(dbg, 1, 1, error); if (ret != DW_DLE_NONE) return (ret); } offset = 0; while (offset < ds->ds_size) { if ((as = malloc(sizeof(struct _Dwarf_ArangeSet))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INIT(&as->as_arlist); STAILQ_INSERT_TAIL(&dbg->dbg_aslist, as, as_next); /* Read in the table header. */ length = dbg->read(ds->ds_data, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = dbg->read(ds->ds_data, &offset, 8); } else dwarf_size = 4; as->as_length = length; as->as_version = dbg->read(ds->ds_data, &offset, 2); if (as->as_version != 2) { DWARF_SET_ERROR(dbg, error, DW_DLE_VERSION_STAMP_ERROR); ret = DW_DLE_VERSION_STAMP_ERROR; goto fail_cleanup; } as->as_cu_offset = dbg->read(ds->ds_data, &offset, dwarf_size); STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { if (cu->cu_offset == as->as_cu_offset) break; } if (cu == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); ret = DW_DLE_ARANGE_OFFSET_BAD; goto fail_cleanup; } as->as_cu = cu; as->as_addrsz = dbg->read(ds->ds_data, &offset, 1); as->as_segsz = dbg->read(ds->ds_data, &offset, 1); /* Skip the padding bytes. */ offset = roundup(offset, 2 * as->as_addrsz); /* Read in address range descriptors. */ while (offset < ds->ds_size) { addr = dbg->read(ds->ds_data, &offset, as->as_addrsz); range = dbg->read(ds->ds_data, &offset, as->as_addrsz); if (addr == 0 && range == 0) break; if ((ar = calloc(1, sizeof(struct _Dwarf_Arange))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); goto fail_cleanup; } ar->ar_as = as; ar->ar_address = addr; ar->ar_range = range; STAILQ_INSERT_TAIL(&as->as_arlist, ar, ar_next); dbg->dbg_arange_cnt++; } } /* Build arange array. */ if (dbg->dbg_arange_cnt > 0) { - if ((dbg->dbg_arange_array = malloc(dbg->dbg_arange_cnt * - sizeof(struct _Dwarf_Arange))) == NULL) { + if ((dbg->dbg_arange_array = malloc(dbg->dbg_arange_cnt * + sizeof(Dwarf_Arange))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); ret = DW_DLE_MEMORY; goto fail_cleanup; } i = 0; STAILQ_FOREACH(as, &dbg->dbg_aslist, as_next) { STAILQ_FOREACH(ar, &as->as_arlist, ar_next) dbg->dbg_arange_array[i++] = ar; } assert((Dwarf_Unsigned)i == dbg->dbg_arange_cnt); } return (DW_DLE_NONE); fail_cleanup: _dwarf_arange_cleanup(dbg); return (ret); } int _dwarf_arange_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) { Dwarf_P_Section ds; Dwarf_Rel_Section drs; Dwarf_ArangeSet as; Dwarf_Arange ar; uint64_t offset; int ret; as = dbg->dbgp_as; assert(as != NULL); if (STAILQ_EMPTY(&as->as_arlist)) return (DW_DLE_NONE); as->as_length = 0; as->as_version = 2; as->as_cu_offset = 0; /* We have only one CU. */ as->as_addrsz = dbg->dbg_pointer_size; as->as_segsz = 0; /* XXX */ /* Create .debug_arange section. */ if ((ret = _dwarf_section_init(dbg, &ds, ".debug_aranges", 0, error)) != DW_DLE_NONE) goto gen_fail0; /* Create relocation section for .debug_aranges */ RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error)); /* Write section header. */ RCHECK(WRITE_VALUE(as->as_length, 4)); RCHECK(WRITE_VALUE(as->as_version, 2)); RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, ds->ds_size, 0, as->as_cu_offset, ".debug_info", error)); RCHECK(WRITE_VALUE(as->as_addrsz, 1)); RCHECK(WRITE_VALUE(as->as_segsz, 1)); /* Pad to (2 * address_size) */ offset = roundup(ds->ds_size, 2 * as->as_addrsz); if (offset > ds->ds_size) RCHECK(WRITE_PADDING(0, offset - ds->ds_size)); /* Write tuples. */ STAILQ_FOREACH(ar, &as->as_arlist, ar_next) { RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, dbg->dbg_pointer_size, ds->ds_size, ar->ar_symndx, ar->ar_address, NULL, error)); if (ar->ar_esymndx > 0) RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds, dbg->dbg_pointer_size, ds->ds_size, ar->ar_symndx, ar->ar_esymndx, ar->ar_address, ar->ar_eoff, error)); else RCHECK(WRITE_VALUE(ar->ar_range, dbg->dbg_pointer_size)); } RCHECK(WRITE_VALUE(0, dbg->dbg_pointer_size)); RCHECK(WRITE_VALUE(0, dbg->dbg_pointer_size)); /* Fill in the length field. */ as->as_length = ds->ds_size - 4; offset = 0; dbg->write(ds->ds_data, &offset, as->as_length, 4); /* Inform application the creation of .debug_aranges ELF section. */ RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); /* Finalize relocation section for .debug_aranges */ RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); return (DW_DLE_NONE); gen_fail: _dwarf_reloc_section_free(dbg, &drs); gen_fail0: _dwarf_section_free(dbg, &ds); return (ret); } void _dwarf_arange_pro_cleanup(Dwarf_P_Debug dbg) { Dwarf_ArangeSet as; Dwarf_Arange ar, tar; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); if (dbg->dbgp_as == NULL) return; as = dbg->dbgp_as; STAILQ_FOREACH_SAFE(ar, &as->as_arlist, ar_next, tar) { STAILQ_REMOVE(&as->as_arlist, ar, _Dwarf_Arange, ar_next); free(ar); } free(as); dbg->dbgp_as = NULL; } diff --git a/libdwarf/libdwarf_attr.c b/libdwarf/libdwarf_attr.c index a7fb71cd1f24..dfbbc484c352 100644 --- a/libdwarf/libdwarf_attr.c +++ b/libdwarf/libdwarf_attr.c @@ -1,458 +1,459 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * Copyright (c) 2009-2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_attr.c 2966 2013-09-21 14:40:14Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_attr.c 3064 2014-06-06 19:35:55Z kaiwang27 $"); int _dwarf_attr_alloc(Dwarf_Die die, Dwarf_Attribute *atp, Dwarf_Error *error) { Dwarf_Attribute at; assert(die != NULL); assert(atp != NULL); if ((at = calloc(1, sizeof(struct _Dwarf_Attribute))) == NULL) { DWARF_SET_ERROR(die->die_dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } *atp = at; return (DW_DLE_NONE); } static int _dwarf_attr_add(Dwarf_Die die, Dwarf_Attribute atref, Dwarf_Attribute *atp, Dwarf_Error *error) { Dwarf_Attribute at; int ret; if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE) return (ret); memcpy(at, atref, sizeof(struct _Dwarf_Attribute)); STAILQ_INSERT_TAIL(&die->die_attr, at, at_next); /* Save a pointer to the attribute name if this is one. */ if (at->at_attrib == DW_AT_name) { switch (at->at_form) { case DW_FORM_strp: die->die_name = at->u[1].s; break; case DW_FORM_string: die->die_name = at->u[0].s; break; default: break; } } if (atp != NULL) *atp = at; return (DW_DLE_NONE); } Dwarf_Attribute _dwarf_attr_find(Dwarf_Die die, Dwarf_Half attr) { Dwarf_Attribute at; STAILQ_FOREACH(at, &die->die_attr, at_next) { if (at->at_attrib == attr) break; } return (at); } int _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp, int dwarf_size, Dwarf_CU cu, Dwarf_Die die, Dwarf_AttrDef ad, uint64_t form, int indirect, Dwarf_Error *error) { struct _Dwarf_Attribute atref; Dwarf_Section *str; int ret; ret = DW_DLE_NONE; memset(&atref, 0, sizeof(atref)); atref.at_die = die; + atref.at_offset = *offsetp; atref.at_attrib = ad->ad_attrib; atref.at_form = indirect ? form : ad->ad_form; atref.at_indirect = indirect; atref.at_ld = NULL; switch (form) { case DW_FORM_addr: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, cu->cu_pointer_size); break; case DW_FORM_block: case DW_FORM_exprloc: atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp); atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp, atref.u[0].u64); break; case DW_FORM_block1: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1); atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp, atref.u[0].u64); break; case DW_FORM_block2: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2); atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp, atref.u[0].u64); break; case DW_FORM_block4: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4); atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp, atref.u[0].u64); break; case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1); break; case DW_FORM_data2: case DW_FORM_ref2: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2); break; case DW_FORM_data4: case DW_FORM_ref4: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4); break; case DW_FORM_data8: case DW_FORM_ref8: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 8); break; case DW_FORM_indirect: form = _dwarf_read_uleb128(ds->ds_data, offsetp); return (_dwarf_attr_init(dbg, ds, offsetp, dwarf_size, cu, die, ad, form, 1, error)); case DW_FORM_ref_addr: if (cu->cu_version == 2) atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, cu->cu_pointer_size); - else if (cu->cu_version == 3) + else atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size); break; case DW_FORM_ref_udata: case DW_FORM_udata: atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp); break; case DW_FORM_sdata: atref.u[0].s64 = _dwarf_read_sleb128(ds->ds_data, offsetp); break; case DW_FORM_sec_offset: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size); break; case DW_FORM_string: atref.u[0].s = _dwarf_read_string(ds->ds_data, ds->ds_size, offsetp); break; case DW_FORM_strp: atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size); str = _dwarf_find_section(dbg, ".debug_str"); assert(str != NULL); atref.u[1].s = (char *) str->ds_data + atref.u[0].u64; break; case DW_FORM_ref_sig8: atref.u[0].u64 = 8; atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp, atref.u[0].u64); break; case DW_FORM_flag_present: /* This form has no value encoded in the DIE. */ atref.u[0].u64 = 1; break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); ret = DW_DLE_ATTR_FORM_BAD; break; } if (ret == DW_DLE_NONE) { if (form == DW_FORM_block || form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4) { atref.at_block.bl_len = atref.u[0].u64; atref.at_block.bl_data = atref.u[1].u8p; } ret = _dwarf_attr_add(die, &atref, NULL, error); } return (ret); } static int _dwarf_attr_write(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs, Dwarf_CU cu, Dwarf_Attribute at, int pass2, Dwarf_Error *error) { struct _Dwarf_P_Expr_Entry *ee; uint64_t value, offset, bs; int ret; assert(dbg != NULL && ds != NULL && cu != NULL && at != NULL); /* Fill in reference to other DIE in the second pass. */ if (pass2) { if (at->at_form != DW_FORM_ref4 && at->at_form != DW_FORM_ref8) return (DW_DLE_NONE); if (at->at_refdie == NULL || at->at_offset == 0) return (DW_DLE_NONE); offset = at->at_offset; dbg->write(ds->ds_data, &offset, at->at_refdie->die_offset, at->at_form == DW_FORM_ref4 ? 4 : 8); return (DW_DLE_NONE); } switch (at->at_form) { case DW_FORM_addr: if (at->at_relsym) ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, cu->cu_pointer_size, ds->ds_size, at->at_relsym, at->u[0].u64, NULL, error); else ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size); break; case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: /* Write block size. */ if (at->at_form == DW_FORM_block) { ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap, &ds->ds_size, at->u[0].u64, error); if (ret != DW_DLE_NONE) break; } else { if (at->at_form == DW_FORM_block1) bs = 1; else if (at->at_form == DW_FORM_block2) bs = 2; else bs = 4; ret = WRITE_VALUE(at->u[0].u64, bs); if (ret != DW_DLE_NONE) break; } /* Keep block data offset for later use. */ offset = ds->ds_size; /* Write block data. */ ret = WRITE_BLOCK(at->u[1].u8p, at->u[0].u64); if (ret != DW_DLE_NONE) break; if (at->at_expr == NULL) break; /* Generate relocation entry for DW_OP_addr expressions. */ STAILQ_FOREACH(ee, &at->at_expr->pe_eelist, ee_next) { if (ee->ee_loc.lr_atom != DW_OP_addr || ee->ee_sym == 0) continue; ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, dbg->dbg_pointer_size, offset + ee->ee_loc.lr_offset + 1, ee->ee_sym, ee->ee_loc.lr_number, NULL, error); if (ret != DW_DLE_NONE) break; } break; case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: ret = WRITE_VALUE(at->u[0].u64, 1); break; case DW_FORM_data2: case DW_FORM_ref2: ret = WRITE_VALUE(at->u[0].u64, 2); break; case DW_FORM_data4: if (at->at_relsym || at->at_relsec != NULL) ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, ds->ds_size, at->at_relsym, at->u[0].u64, at->at_relsec, error); else ret = WRITE_VALUE(at->u[0].u64, 4); break; case DW_FORM_data8: if (at->at_relsym || at->at_relsec != NULL) ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 8, ds->ds_size, at->at_relsym, at->u[0].u64, at->at_relsec, error); else ret = WRITE_VALUE(at->u[0].u64, 8); break; case DW_FORM_ref4: case DW_FORM_ref8: /* * The value of ref4 and ref8 could be a reference to another * DIE within the CU. And if we don't know the ref DIE's * offset at the moement, then we remember at_offset and fill * it in the second pass. */ if (at->at_refdie) { value = at->at_refdie->die_offset; if (value == 0) { cu->cu_pass2 = 1; at->at_offset = ds->ds_size; } } else value = at->u[0].u64; ret = WRITE_VALUE(value, at->at_form == DW_FORM_ref4 ? 4 : 8); break; case DW_FORM_indirect: /* TODO. */ DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); ret = DW_DLE_ATTR_FORM_BAD; break; case DW_FORM_ref_addr: /* DWARF2 format. */ if (at->at_relsym) ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, cu->cu_pointer_size, ds->ds_size, at->at_relsym, at->u[0].u64, NULL, error); else ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size); break; case DW_FORM_ref_udata: case DW_FORM_udata: ret = WRITE_ULEB128(at->u[0].u64); break; case DW_FORM_sdata: ret = WRITE_SLEB128(at->u[0].s64); break; case DW_FORM_string: assert(at->u[0].s != NULL); ret = WRITE_STRING(at->u[0].s); break; case DW_FORM_strp: ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, ds->ds_size, 0, at->u[0].u64, ".debug_str", error); break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); ret = DW_DLE_ATTR_FORM_BAD; break; } return (ret); } int _dwarf_add_AT_dataref(Dwarf_P_Debug dbg, Dwarf_P_Die die, Dwarf_Half attr, Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, const char *secname, Dwarf_P_Attribute *atp, Dwarf_Error *error) { Dwarf_Attribute at; int ret; assert(dbg != NULL && die != NULL); if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE) return (ret); at->at_die = die; at->at_attrib = attr; if (dbg->dbg_pointer_size == 4) at->at_form = DW_FORM_data4; else at->at_form = DW_FORM_data8; at->at_relsym = sym_index; at->at_relsec = secname; at->u[0].u64 = pc_value; STAILQ_INSERT_TAIL(&die->die_attr, at, at_next); if (atp) *atp = at; return (DW_DLE_NONE); } int _dwarf_add_string_attr(Dwarf_P_Die die, Dwarf_P_Attribute *atp, Dwarf_Half attr, char *string, Dwarf_Error *error) { Dwarf_Attribute at; Dwarf_Debug dbg; int ret; dbg = die != NULL ? die->die_dbg : NULL; assert(atp != NULL); if (die == NULL || string == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLE_ARGUMENT); } if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE) return (ret); at->at_die = die; at->at_attrib = attr; at->at_form = DW_FORM_strp; if ((ret = _dwarf_strtab_add(dbg, string, &at->u[0].u64, error)) != DW_DLE_NONE) { free(at); return (ret); } at->u[1].s = _dwarf_strtab_get_table(dbg) + at->u[0].u64; *atp = at; STAILQ_INSERT_TAIL(&die->die_attr, at, at_next); return (DW_DLE_NONE); } int _dwarf_attr_gen(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs, Dwarf_CU cu, Dwarf_Die die, int pass2, Dwarf_Error *error) { Dwarf_Attribute at; int ret; assert(dbg != NULL && ds != NULL && cu != NULL && die != NULL); STAILQ_FOREACH(at, &die->die_attr, at_next) { ret = _dwarf_attr_write(dbg, ds, drs, cu, at, pass2, error); if (ret != DW_DLE_NONE) return (ret); } return (DW_DLE_NONE); } diff --git a/libdwarf/libdwarf_die.c b/libdwarf/libdwarf_die.c index 4572875ed0d7..b7796d3cb6b0 100644 --- a/libdwarf/libdwarf_die.c +++ b/libdwarf/libdwarf_die.c @@ -1,455 +1,457 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * Copyright (c) 2009-2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_die.c 2948 2013-05-30 21:25:52Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_die.c 3039 2014-05-18 15:10:56Z kaiwang27 $"); int _dwarf_die_alloc(Dwarf_Debug dbg, Dwarf_Die *ret_die, Dwarf_Error *error) { Dwarf_Die die; assert(ret_die != NULL); if ((die = calloc(1, sizeof(struct _Dwarf_Die))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INIT(&die->die_attr); *ret_die = die; return (DW_DLE_NONE); } static int _dwarf_die_add(Dwarf_CU cu, uint64_t offset, uint64_t abnum, Dwarf_Abbrev ab, Dwarf_Die *diep, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_Die die; int ret; assert(cu != NULL); assert(ab != NULL); dbg = cu->cu_dbg; if ((ret = _dwarf_die_alloc(dbg, &die, error)) != DW_DLE_NONE) return (ret); die->die_offset = offset; die->die_abnum = abnum; die->die_ab = ab; die->die_cu = cu; die->die_dbg = cu->cu_dbg; if (diep != NULL) *diep = die; return (DW_DLE_NONE); } /* Find die at offset 'off' within the same CU. */ Dwarf_Die _dwarf_die_find(Dwarf_Die die, Dwarf_Unsigned off) { Dwarf_Debug dbg; + Dwarf_Section *ds; Dwarf_CU cu; Dwarf_Die die1; Dwarf_Error de; int ret; cu = die->die_cu; dbg = die->die_dbg; + ds = cu->cu_is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; - ret = _dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size, - off, cu->cu_next_offset, &die1, 0, &de); + ret = _dwarf_die_parse(dbg, ds, cu, cu->cu_dwarf_size, off, + cu->cu_next_offset, &die1, 0, &de); if (ret == DW_DLE_NONE) return (die1); else return (NULL); } int _dwarf_die_parse(Dwarf_Debug dbg, Dwarf_Section *ds, Dwarf_CU cu, int dwarf_size, uint64_t offset, uint64_t next_offset, Dwarf_Die *ret_die, int search_sibling, Dwarf_Error *error) { Dwarf_Abbrev ab; Dwarf_AttrDef ad; Dwarf_Die die; uint64_t abnum; uint64_t die_offset; int ret, level; assert(cu != NULL); level = 1; die = NULL; while (offset < next_offset && offset < ds->ds_size) { die_offset = offset; abnum = _dwarf_read_uleb128(ds->ds_data, &offset); if (abnum == 0) { if (level == 0 || !search_sibling) return (DW_DLE_NO_ENTRY); /* * Return to previous DIE level. */ level--; continue; } if ((ret = _dwarf_abbrev_find(cu, abnum, &ab, error)) != DW_DLE_NONE) return (ret); if ((ret = _dwarf_die_add(cu, die_offset, abnum, ab, &die, error)) != DW_DLE_NONE) return (ret); STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) { if ((ret = _dwarf_attr_init(dbg, ds, &offset, dwarf_size, cu, die, ad, ad->ad_form, 0, error)) != DW_DLE_NONE) return (ret); } die->die_next_off = offset; if (search_sibling && level > 0) { dwarf_dealloc(dbg, die, DW_DLA_DIE); if (ab->ab_children == DW_CHILDREN_yes) { /* Advance to next DIE level. */ level++; } } else { *ret_die = die; return (DW_DLE_NONE); } } return (DW_DLE_NO_ENTRY); } void _dwarf_die_link(Dwarf_P_Die die, Dwarf_P_Die parent, Dwarf_P_Die child, Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling) { Dwarf_P_Die last_child; assert(die != NULL); if (parent) { /* Disconnect from old parent. */ if (die->die_parent) { if (die->die_parent != parent) { if (die->die_parent->die_child == die) die->die_parent->die_child = NULL; die->die_parent = NULL; } } /* Find the last child of this parent. */ last_child = parent->die_child; if (last_child) { while (last_child->die_right != NULL) last_child = last_child->die_right; } /* Connect to new parent. */ die->die_parent = parent; /* * Attach this DIE to the end of sibling list. If new * parent doesn't have any child, set this DIE as the * first child. */ if (last_child) { assert(last_child->die_right == NULL); last_child->die_right = die; die->die_left = last_child; } else parent->die_child = die; } if (child) { /* Disconnect from old child. */ if (die->die_child) { if (die->die_child != child) { die->die_child->die_parent = NULL; die->die_child = NULL; } } /* Connect to new child. */ die->die_child = child; child->die_parent = die; } if (left_sibling) { /* Disconnect from old left sibling. */ if (die->die_left) { if (die->die_left != left_sibling) { die->die_left->die_right = NULL; die->die_left = NULL; } } /* Connect to new right sibling. */ die->die_left = left_sibling; left_sibling->die_right = die; } if (right_sibling) { /* Disconnect from old right sibling. */ if (die->die_right) { if (die->die_right != right_sibling) { die->die_right->die_left = NULL; die->die_right = NULL; } } /* Connect to new right sibling. */ die->die_right = right_sibling; right_sibling->die_left = die; } } int _dwarf_die_count_links(Dwarf_P_Die parent, Dwarf_P_Die child, Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling) { int count; count = 0; if (parent) count++; if (child) count++; if (left_sibling) count++; if (right_sibling) count++; return (count); } static int _dwarf_die_gen_recursive(Dwarf_P_Debug dbg, Dwarf_CU cu, Dwarf_Rel_Section drs, Dwarf_P_Die die, int pass2, Dwarf_Error *error) { Dwarf_P_Section ds; Dwarf_Abbrev ab; Dwarf_Attribute at; Dwarf_AttrDef ad; int match, ret; ds = dbg->dbgp_info; assert(ds != NULL); if (pass2) goto attr_gen; /* * Add DW_AT_sibling attribute for DIEs with children, so consumers * can quickly scan chains of siblings, while ignoring the children * of individual siblings. */ if (die->die_child && die->die_right) { if (_dwarf_attr_find(die, DW_AT_sibling) == NULL) (void) dwarf_add_AT_reference(dbg, die, DW_AT_sibling, die->die_right, error); } /* * Search abbrev list to find a matching entry. */ die->die_ab = NULL; for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) { if (die->die_tag != ab->ab_tag) continue; if (ab->ab_children == DW_CHILDREN_no && die->die_child != NULL) continue; if (ab->ab_children == DW_CHILDREN_yes && die->die_child == NULL) continue; at = STAILQ_FIRST(&die->die_attr); ad = STAILQ_FIRST(&ab->ab_attrdef); match = 1; while (at != NULL && ad != NULL) { if (at->at_attrib != ad->ad_attrib || at->at_form != ad->ad_form) { match = 0; break; } at = STAILQ_NEXT(at, at_next); ad = STAILQ_NEXT(ad, ad_next); } if ((at == NULL && ad != NULL) || (at != NULL && ad == NULL)) match = 0; if (match) { die->die_ab = ab; break; } } /* * Create a new abbrev entry if we can not reuse any existing one. */ if (die->die_ab == NULL) { ret = _dwarf_abbrev_add(cu, ++cu->cu_abbrev_cnt, die->die_tag, die->die_child != NULL ? DW_CHILDREN_yes : DW_CHILDREN_no, 0, &ab, error); if (ret != DW_DLE_NONE) return (ret); STAILQ_FOREACH(at, &die->die_attr, at_next) { ret = _dwarf_attrdef_add(dbg, ab, at->at_attrib, at->at_form, 0, NULL, error); if (ret != DW_DLE_NONE) return (ret); } die->die_ab = ab; } die->die_offset = ds->ds_size; /* * Transform the DIE to bytes stream. */ ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap, &ds->ds_size, die->die_ab->ab_entry, error); if (ret != DW_DLE_NONE) return (ret); attr_gen: /* Transform the attributes of this DIE. */ ret = _dwarf_attr_gen(dbg, ds, drs, cu, die, pass2, error); if (ret != DW_DLE_NONE) return (ret); /* Proceed to child DIE. */ if (die->die_child != NULL) { ret = _dwarf_die_gen_recursive(dbg, cu, drs, die->die_child, pass2, error); if (ret != DW_DLE_NONE) return (ret); } /* Proceed to sibling DIE. */ if (die->die_right != NULL) { ret = _dwarf_die_gen_recursive(dbg, cu, drs, die->die_right, pass2, error); if (ret != DW_DLE_NONE) return (ret); } /* Write a null DIE indicating the end of current level. */ if (die->die_right == NULL) { ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap, &ds->ds_size, 0, error); if (ret != DW_DLE_NONE) return (ret); } return (DW_DLE_NONE); } int _dwarf_die_gen(Dwarf_P_Debug dbg, Dwarf_CU cu, Dwarf_Rel_Section drs, Dwarf_Error *error) { Dwarf_Abbrev ab, tab; Dwarf_AttrDef ad, tad; Dwarf_Die die; int ret; assert(dbg != NULL && cu != NULL); assert(dbg->dbgp_root_die != NULL); die = dbg->dbgp_root_die; /* * Insert a DW_AT_stmt_list attribute into root DIE, if there are * line number information. */ if (!STAILQ_EMPTY(&dbg->dbgp_lineinfo->li_lnlist)) RCHECK(_dwarf_add_AT_dataref(dbg, die, DW_AT_stmt_list, 0, 0, ".debug_line", NULL, error)); RCHECK(_dwarf_die_gen_recursive(dbg, cu, drs, die, 0, error)); if (cu->cu_pass2) RCHECK(_dwarf_die_gen_recursive(dbg, cu, drs, die, 1, error)); return (DW_DLE_NONE); gen_fail: HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) { HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab); STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) { STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef, ad_next); free(ad); } free(ab); } return (ret); } void _dwarf_die_pro_cleanup(Dwarf_P_Debug dbg) { Dwarf_P_Die die, tdie; Dwarf_P_Attribute at, tat; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); STAILQ_FOREACH_SAFE(die, &dbg->dbgp_dielist, die_pro_next, tdie) { STAILQ_FOREACH_SAFE(at, &die->die_attr, at_next, tat) { STAILQ_REMOVE(&die->die_attr, at, _Dwarf_Attribute, at_next); free(at); } free(die); } } diff --git a/libdwarf/libdwarf_frame.c b/libdwarf/libdwarf_frame.c index 375d64f5f66f..dd331379a4fd 100644 --- a/libdwarf/libdwarf_frame.c +++ b/libdwarf/libdwarf_frame.c @@ -1,1593 +1,1606 @@ /*- - * Copyright (c) 2009-2011 Kai Wang + * Copyright (c) 2009-2011,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_frame.c 2529 2012-07-29 23:31:12Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_frame.c 3106 2014-12-19 16:00:58Z kaiwang27 $"); static int _dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset, Dwarf_Cie *ret_cie) { Dwarf_Cie cie; STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) { if (cie->cie_offset == offset) break; } if (cie == NULL) return (DW_DLE_NO_ENTRY); if (ret_cie != NULL) *ret_cie = cie; return (DW_DLE_NONE); } static int -_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, uint64_t *val, uint8_t *data, - uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc, Dwarf_Error *error) +_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, Dwarf_Cie cie, uint64_t *val, + uint8_t *data, uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc, + Dwarf_Error *error) { uint8_t application; if (encode == DW_EH_PE_omit) return (DW_DLE_NONE); application = encode & 0xf0; encode &= 0x0f; switch (encode) { case DW_EH_PE_absptr: - *val = dbg->read(data, offsetp, dbg->dbg_pointer_size); + *val = dbg->read(data, offsetp, cie->cie_addrsize); break; case DW_EH_PE_uleb128: *val = _dwarf_read_uleb128(data, offsetp); break; case DW_EH_PE_udata2: *val = dbg->read(data, offsetp, 2); break; case DW_EH_PE_udata4: *val = dbg->read(data, offsetp, 4); break; case DW_EH_PE_udata8: *val = dbg->read(data, offsetp, 8); break; case DW_EH_PE_sleb128: *val = _dwarf_read_sleb128(data, offsetp); break; case DW_EH_PE_sdata2: *val = (int16_t) dbg->read(data, offsetp, 2); break; case DW_EH_PE_sdata4: *val = (int32_t) dbg->read(data, offsetp, 4); break; case DW_EH_PE_sdata8: *val = dbg->read(data, offsetp, 8); break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN); } if (application == DW_EH_PE_pcrel) { /* * Value is relative to .eh_frame section virtual addr. */ switch (encode) { case DW_EH_PE_uleb128: case DW_EH_PE_udata2: case DW_EH_PE_udata4: case DW_EH_PE_udata8: *val += pc; break; case DW_EH_PE_sleb128: case DW_EH_PE_sdata2: case DW_EH_PE_sdata4: case DW_EH_PE_sdata8: *val = pc + (int64_t) *val; break; default: /* DW_EH_PE_absptr is absolute value. */ break; } } /* XXX Applications other than DW_EH_PE_pcrel are not handled. */ return (DW_DLE_NONE); } static int _dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie, Dwarf_Error *error) { uint8_t *aug_p, *augdata_p; uint64_t val, offset; uint8_t encode; int ret; assert(cie->cie_augment != NULL && *cie->cie_augment == 'z'); /* * Here we're only interested in the presence of augment 'R' * and associated CIE augment data, which describes the * encoding scheme of FDE PC begin and range. */ aug_p = &cie->cie_augment[1]; augdata_p = cie->cie_augdata; while (*aug_p != '\0') { switch (*aug_p) { case 'L': /* Skip one augment in augment data. */ augdata_p++; break; case 'P': /* Skip two augments in augment data. */ encode = *augdata_p++; offset = 0; - ret = _dwarf_frame_read_lsb_encoded(dbg, &val, + ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val, augdata_p, &offset, encode, 0, error); if (ret != DW_DLE_NONE) return (ret); augdata_p += offset; break; case 'R': cie->cie_fde_encode = *augdata_p++; break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN); } aug_p++; } return (DW_DLE_NONE); } static int _dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds, Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error) { Dwarf_Cie cie; uint64_t length; int dwarf_size, ret; char *p; /* Check if we already added this CIE. */ if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) { *off += cie->cie_length + 4; return (DW_DLE_NONE); } if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next); cie->cie_dbg = dbg; cie->cie_index = fs->fs_cielen; cie->cie_offset = *off; length = dbg->read(ds->ds_data, off, 4); if (length == 0xffffffff) { dwarf_size = 8; length = dbg->read(ds->ds_data, off, 8); } else dwarf_size = 4; if (length > ds->ds_size - *off) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); return (DW_DLE_DEBUG_FRAME_LENGTH_BAD); } (void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */ cie->cie_length = length; cie->cie_version = dbg->read(ds->ds_data, off, 1); if (cie->cie_version != 1 && cie->cie_version != 3 && cie->cie_version != 4) { DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD); return (DW_DLE_FRAME_VERSION_BAD); } cie->cie_augment = ds->ds_data + *off; p = (char *) ds->ds_data; while (p[(*off)++] != '\0') ; /* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */ if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') { *off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) + cie->cie_length; return (DW_DLE_NONE); } /* Optional EH Data field for .eh_frame section. */ if (strstr((char *)cie->cie_augment, "eh") != NULL) cie->cie_ehdata = dbg->read(ds->ds_data, off, dbg->dbg_pointer_size); + /* DWARF4 added "address_size" and "segment_size". */ + if (cie->cie_version == 4) { + cie->cie_addrsize = dbg->read(ds->ds_data, off, 1); + cie->cie_segmentsize = dbg->read(ds->ds_data, off, 1); + } else { + /* + * Otherwise (DWARF[23]) we just set CIE addrsize to the + * debug context pointer size. + */ + cie->cie_addrsize = dbg->dbg_pointer_size; + } + cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off); cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off); /* Return address register. */ if (cie->cie_version == 1) cie->cie_ra = dbg->read(ds->ds_data, off, 1); else cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off); /* Optional CIE augmentation data for .eh_frame section. */ if (*cie->cie_augment == 'z') { cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off); cie->cie_augdata = ds->ds_data + *off; *off += cie->cie_auglen; /* * XXX Use DW_EH_PE_absptr for default FDE PC start/range, * in case _dwarf_frame_parse_lsb_cie_augment fails to * find out the real encode. */ cie->cie_fde_encode = DW_EH_PE_absptr; ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error); if (ret != DW_DLE_NONE) return (ret); } /* CIE Initial instructions. */ cie->cie_initinst = ds->ds_data + *off; if (dwarf_size == 4) cie->cie_instlen = cie->cie_offset + 4 + length - *off; else cie->cie_instlen = cie->cie_offset + 12 + length - *off; *off += cie->cie_instlen; #ifdef FRAME_DEBUG printf("cie:\n"); printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s" " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n", cie->cie_version, cie->cie_offset, cie->cie_length, (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf, cie->cie_daf, *off); #endif if (ret_cie != NULL) *ret_cie = cie; fs->fs_cielen++; return (DW_DLE_NONE); } static int _dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds, Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error) { Dwarf_Cie cie; Dwarf_Fde fde; Dwarf_Unsigned cieoff; uint64_t length, val; int dwarf_size, ret; if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next); fde->fde_dbg = dbg; fde->fde_fs = fs; fde->fde_addr = ds->ds_data + *off; fde->fde_offset = *off; length = dbg->read(ds->ds_data, off, 4); if (length == 0xffffffff) { dwarf_size = 8; length = dbg->read(ds->ds_data, off, 8); } else dwarf_size = 4; if (length > ds->ds_size - *off) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); return (DW_DLE_DEBUG_FRAME_LENGTH_BAD); } fde->fde_length = length; if (eh_frame) { fde->fde_cieoff = dbg->read(ds->ds_data, off, 4); cieoff = *off - (4 + fde->fde_cieoff); /* This delta should never be 0. */ if (cieoff == fde->fde_offset) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE); return (DW_DLE_NO_CIE_FOR_FDE); } } else { fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size); cieoff = fde->fde_cieoff; } if (_dwarf_frame_find_cie(fs, cieoff, &cie) == DW_DLE_NO_ENTRY) { ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie, error); if (ret != DW_DLE_NONE) return (ret); } fde->fde_cie = cie; if (eh_frame) { /* * The FDE PC start/range for .eh_frame is encoded according * to the LSB spec's extension to DWARF2. */ - ret = _dwarf_frame_read_lsb_encoded(dbg, &val, ds->ds_data, - off, cie->cie_fde_encode, ds->ds_addr + *off, error); + ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val, + ds->ds_data, off, cie->cie_fde_encode, ds->ds_addr + *off, + error); if (ret != DW_DLE_NONE) return (ret); fde->fde_initloc = val; /* * FDE PC range should not be relative value to anything. * So pass 0 for pc value. */ - ret = _dwarf_frame_read_lsb_encoded(dbg, &val, ds->ds_data, - off, cie->cie_fde_encode, 0, error); + ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val, + ds->ds_data, off, cie->cie_fde_encode, 0, error); if (ret != DW_DLE_NONE) return (ret); fde->fde_adrange = val; } else { fde->fde_initloc = dbg->read(ds->ds_data, off, - dbg->dbg_pointer_size); + cie->cie_addrsize); fde->fde_adrange = dbg->read(ds->ds_data, off, - dbg->dbg_pointer_size); + cie->cie_addrsize); } /* Optional FDE augmentation data for .eh_frame section. (ignored) */ if (eh_frame && *cie->cie_augment == 'z') { fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off); fde->fde_augdata = ds->ds_data + *off; *off += fde->fde_auglen; } fde->fde_inst = ds->ds_data + *off; if (dwarf_size == 4) fde->fde_instlen = fde->fde_offset + 4 + length - *off; else fde->fde_instlen = fde->fde_offset + 12 + length - *off; *off += fde->fde_instlen; #ifdef FRAME_DEBUG printf("fde:"); if (eh_frame) printf("(eh_frame)"); putchar('\n'); printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju" " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length, fde->fde_cieoff, fde->fde_instlen, *off); #endif fs->fs_fdelen++; return (DW_DLE_NONE); } static void _dwarf_frame_section_cleanup(Dwarf_FrameSec fs) { Dwarf_Cie cie, tcie; Dwarf_Fde fde, tfde; STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) { STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next); free(cie); } STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) { STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next); free(fde); } if (fs->fs_ciearray != NULL) free(fs->fs_ciearray); if (fs->fs_fdearray != NULL) free(fs->fs_fdearray); free(fs); } static int _dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec, Dwarf_Section *ds, int eh_frame, Dwarf_Error *error) { Dwarf_FrameSec fs; Dwarf_Cie cie; Dwarf_Fde fde; uint64_t length, offset, cie_id, entry_off; int dwarf_size, i, ret; assert(frame_sec != NULL); assert(*frame_sec == NULL); if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INIT(&fs->fs_cielist); STAILQ_INIT(&fs->fs_fdelist); offset = 0; while (offset < ds->ds_size) { entry_off = offset; length = dbg->read(ds->ds_data, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = dbg->read(ds->ds_data, &offset, 8); } else dwarf_size = 4; if (length > ds->ds_size - offset || (length == 0 && !eh_frame)) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); return (DW_DLE_DEBUG_FRAME_LENGTH_BAD); } /* Check terminator for .eh_frame */ if (eh_frame && length == 0) break; cie_id = dbg->read(ds->ds_data, &offset, dwarf_size); if (eh_frame) { /* GNU .eh_frame use CIE id 0. */ if (cie_id == 0) ret = _dwarf_frame_add_cie(dbg, fs, ds, &entry_off, NULL, error); else ret = _dwarf_frame_add_fde(dbg, fs, ds, &entry_off, 1, error); } else { /* .dwarf_frame use CIE id ~0 */ if ((dwarf_size == 4 && cie_id == ~0U) || (dwarf_size == 8 && cie_id == ~0ULL)) ret = _dwarf_frame_add_cie(dbg, fs, ds, &entry_off, NULL, error); else ret = _dwarf_frame_add_fde(dbg, fs, ds, &entry_off, 0, error); } if (ret != DW_DLE_NONE) goto fail_cleanup; offset = entry_off; } /* Create CIE array. */ if (fs->fs_cielen > 0) { if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) * fs->fs_cielen)) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } i = 0; STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) { fs->fs_ciearray[i++] = cie; } assert((Dwarf_Unsigned)i == fs->fs_cielen); } /* Create FDE array. */ if (fs->fs_fdelen > 0) { if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) * fs->fs_fdelen)) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } i = 0; STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) { fs->fs_fdearray[i++] = fde; } assert((Dwarf_Unsigned)i == fs->fs_fdelen); } *frame_sec = fs; return (DW_DLE_NONE); fail_cleanup: _dwarf_frame_section_cleanup(fs); return (ret); } static int -_dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t *insts, - Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, Dwarf_Addr pc, - Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error) +_dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t addr_size, + uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, + Dwarf_Addr pc, Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error) { Dwarf_Regtable3 *init_rt, *saved_rt; uint8_t *p, *pe; uint8_t high2, low6; uint64_t reg, reg2, uoff, soff; int ret; #define CFA rt->rt3_cfa_rule #define INITCFA init_rt->rt3_cfa_rule #define RL rt->rt3_rules #define INITRL init_rt->rt3_rules #define CHECK_TABLE_SIZE(x) \ do { \ if ((x) >= rt->rt3_reg_table_size) { \ DWARF_SET_ERROR(dbg, error, \ DW_DLE_DF_REG_NUM_TOO_HIGH); \ ret = DW_DLE_DF_REG_NUM_TOO_HIGH; \ goto program_done; \ } \ } while(0) #ifdef FRAME_DEBUG printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf); #endif ret = DW_DLE_NONE; init_rt = saved_rt = NULL; *row_pc = pc; /* Save a copy of the table as initial state. */ _dwarf_frame_regtable_copy(dbg, &init_rt, rt, error); p = insts; pe = p + len; while (p < pe) { #ifdef FRAME_DEBUG printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req); #endif if (*p == DW_CFA_nop) { #ifdef FRAME_DEBUG printf("DW_CFA_nop\n"); #endif p++; continue; } high2 = *p & 0xc0; low6 = *p & 0x3f; p++; if (high2 > 0) { switch (high2) { case DW_CFA_advance_loc: pc += low6 * caf; #ifdef FRAME_DEBUG printf("DW_CFA_advance_loc(%#jx(%u))\n", pc, low6); #endif if (pc_req < pc) goto program_done; break; case DW_CFA_offset: *row_pc = pc; CHECK_TABLE_SIZE(low6); RL[low6].dw_offset_relevant = 1; RL[low6].dw_value_type = DW_EXPR_OFFSET; RL[low6].dw_regnum = dbg->dbg_frame_cfa_value; RL[low6].dw_offset_or_block_len = _dwarf_decode_uleb128(&p) * daf; #ifdef FRAME_DEBUG printf("DW_CFA_offset(%jd)\n", RL[low6].dw_offset_or_block_len); #endif break; case DW_CFA_restore: *row_pc = pc; CHECK_TABLE_SIZE(low6); memcpy(&RL[low6], &INITRL[low6], sizeof(Dwarf_Regtable_Entry3)); #ifdef FRAME_DEBUG printf("DW_CFA_restore(%u)\n", low6); #endif break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); ret = DW_DLE_FRAME_INSTR_EXEC_ERROR; goto program_done; } continue; } switch (low6) { case DW_CFA_set_loc: - pc = dbg->decode(&p, dbg->dbg_pointer_size); + pc = dbg->decode(&p, addr_size); #ifdef FRAME_DEBUG printf("DW_CFA_set_loc(pc=%#jx)\n", pc); #endif if (pc_req < pc) goto program_done; break; case DW_CFA_advance_loc1: pc += dbg->decode(&p, 1) * caf; #ifdef FRAME_DEBUG printf("DW_CFA_set_loc1(pc=%#jx)\n", pc); #endif if (pc_req < pc) goto program_done; break; case DW_CFA_advance_loc2: pc += dbg->decode(&p, 2) * caf; #ifdef FRAME_DEBUG printf("DW_CFA_set_loc2(pc=%#jx)\n", pc); #endif if (pc_req < pc) goto program_done; break; case DW_CFA_advance_loc4: pc += dbg->decode(&p, 4) * caf; #ifdef FRAME_DEBUG printf("DW_CFA_set_loc4(pc=%#jx)\n", pc); #endif if (pc_req < pc) goto program_done; break; case DW_CFA_offset_extended: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); uoff = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 1; RL[reg].dw_value_type = DW_EXPR_OFFSET; RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; RL[reg].dw_offset_or_block_len = uoff * daf; #ifdef FRAME_DEBUG printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n", reg, uoff); #endif break; case DW_CFA_restore_extended: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); memcpy(&RL[reg], &INITRL[reg], sizeof(Dwarf_Regtable_Entry3)); #ifdef FRAME_DEBUG printf("DW_CFA_restore_extended(%ju)\n", reg); #endif break; case DW_CFA_undefined: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 0; RL[reg].dw_regnum = dbg->dbg_frame_undefined_value; #ifdef FRAME_DEBUG printf("DW_CFA_undefined(%ju)\n", reg); #endif break; case DW_CFA_same_value: reg = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 0; RL[reg].dw_regnum = dbg->dbg_frame_same_value; #ifdef FRAME_DEBUG printf("DW_CFA_same_value(%ju)\n", reg); #endif break; case DW_CFA_register: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); reg2 = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 0; RL[reg].dw_regnum = reg2; #ifdef FRAME_DEBUG printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg, reg2); #endif break; case DW_CFA_remember_state: _dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error); #ifdef FRAME_DEBUG printf("DW_CFA_remember_state\n"); #endif break; case DW_CFA_restore_state: *row_pc = pc; _dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error); #ifdef FRAME_DEBUG printf("DW_CFA_restore_state\n"); #endif break; case DW_CFA_def_cfa: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); uoff = _dwarf_decode_uleb128(&p); CFA.dw_offset_relevant = 1; CFA.dw_value_type = DW_EXPR_OFFSET; CFA.dw_regnum = reg; CFA.dw_offset_or_block_len = uoff; #ifdef FRAME_DEBUG printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff); #endif break; case DW_CFA_def_cfa_register: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); CFA.dw_regnum = reg; /* * Note that DW_CFA_def_cfa_register change the CFA * rule register while keep the old offset. So we * should not touch the CFA.dw_offset_relevant flag * here. */ #ifdef FRAME_DEBUG printf("DW_CFA_def_cfa_register(%ju)\n", reg); #endif break; case DW_CFA_def_cfa_offset: *row_pc = pc; uoff = _dwarf_decode_uleb128(&p); CFA.dw_offset_relevant = 1; CFA.dw_value_type = DW_EXPR_OFFSET; CFA.dw_offset_or_block_len = uoff; #ifdef FRAME_DEBUG printf("DW_CFA_def_cfa_offset(%ju)\n", uoff); #endif break; case DW_CFA_def_cfa_expression: *row_pc = pc; CFA.dw_offset_relevant = 0; CFA.dw_value_type = DW_EXPR_EXPRESSION; CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p); CFA.dw_block_ptr = p; p += CFA.dw_offset_or_block_len; #ifdef FRAME_DEBUG printf("DW_CFA_def_cfa_expression\n"); #endif break; case DW_CFA_expression: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 0; RL[reg].dw_value_type = DW_EXPR_EXPRESSION; RL[reg].dw_offset_or_block_len = _dwarf_decode_uleb128(&p); RL[reg].dw_block_ptr = p; p += RL[reg].dw_offset_or_block_len; #ifdef FRAME_DEBUG printf("DW_CFA_expression\n"); #endif break; case DW_CFA_offset_extended_sf: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); soff = _dwarf_decode_sleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 1; RL[reg].dw_value_type = DW_EXPR_OFFSET; RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; RL[reg].dw_offset_or_block_len = soff * daf; #ifdef FRAME_DEBUG printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n", reg, soff); #endif break; case DW_CFA_def_cfa_sf: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); soff = _dwarf_decode_sleb128(&p); CFA.dw_offset_relevant = 1; CFA.dw_value_type = DW_EXPR_OFFSET; CFA.dw_regnum = reg; CFA.dw_offset_or_block_len = soff * daf; #ifdef FRAME_DEBUG printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg, soff); #endif break; case DW_CFA_def_cfa_offset_sf: *row_pc = pc; soff = _dwarf_decode_sleb128(&p); CFA.dw_offset_relevant = 1; CFA.dw_value_type = DW_EXPR_OFFSET; CFA.dw_offset_or_block_len = soff * daf; #ifdef FRAME_DEBUG printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff); #endif break; case DW_CFA_val_offset: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); uoff = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 1; RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET; RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; RL[reg].dw_offset_or_block_len = uoff * daf; #ifdef FRAME_DEBUG printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg, uoff); #endif break; case DW_CFA_val_offset_sf: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); soff = _dwarf_decode_sleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 1; RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET; RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; RL[reg].dw_offset_or_block_len = soff * daf; #ifdef FRAME_DEBUG printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg, soff); #endif break; case DW_CFA_val_expression: *row_pc = pc; reg = _dwarf_decode_uleb128(&p); CHECK_TABLE_SIZE(reg); RL[reg].dw_offset_relevant = 0; RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION; RL[reg].dw_offset_or_block_len = _dwarf_decode_uleb128(&p); RL[reg].dw_block_ptr = p; p += RL[reg].dw_offset_or_block_len; #ifdef FRAME_DEBUG printf("DW_CFA_val_expression\n"); #endif break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); ret = DW_DLE_FRAME_INSTR_EXEC_ERROR; goto program_done; } } program_done: free(init_rt->rt3_rules); free(init_rt); if (saved_rt) { free(saved_rt->rt3_rules); free(saved_rt); } return (ret); #undef CFA #undef INITCFA #undef RL #undef INITRL #undef CHECK_TABLE_SIZE } static int -_dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t *insts, Dwarf_Unsigned len, - Dwarf_Unsigned *count, Dwarf_Frame_Op *fop, Dwarf_Frame_Op3 *fop3, - Dwarf_Error *error) +_dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts, + Dwarf_Unsigned len, Dwarf_Unsigned *count, Dwarf_Frame_Op *fop, + Dwarf_Frame_Op3 *fop3, Dwarf_Error *error) { uint8_t *p, *pe; uint8_t high2, low6; uint64_t reg, reg2, uoff, soff, blen; - int ret; #define SET_BASE_OP(x) \ do { \ if (fop != NULL) \ fop[*count].fp_base_op = (x) >> 6; \ if (fop3 != NULL) \ fop3[*count].fp_base_op = (x) >> 6; \ } while(0) #define SET_EXTENDED_OP(x) \ do { \ if (fop != NULL) \ fop[*count].fp_extended_op = (x); \ if (fop3 != NULL) \ fop3[*count].fp_extended_op = (x); \ } while(0) #define SET_REGISTER(x) \ do { \ if (fop != NULL) \ fop[*count].fp_register = (x); \ if (fop3 != NULL) \ fop3[*count].fp_register = (x); \ } while(0) #define SET_OFFSET(x) \ do { \ if (fop != NULL) \ fop[*count].fp_offset = (x); \ if (fop3 != NULL) \ fop3[*count].fp_offset_or_block_len = \ (x); \ } while(0) #define SET_INSTR_OFFSET(x) \ do { \ if (fop != NULL) \ fop[*count].fp_instr_offset = (x); \ if (fop3 != NULL) \ fop3[*count].fp_instr_offset = (x); \ } while(0) #define SET_BLOCK_LEN(x) \ do { \ if (fop3 != NULL) \ fop3[*count].fp_offset_or_block_len = \ (x); \ } while(0) #define SET_EXPR_BLOCK(addr, len) \ do { \ if (fop3 != NULL) { \ fop3[*count].fp_expr_block = \ malloc((size_t) (len)); \ if (fop3[*count].fp_expr_block == NULL) { \ DWARF_SET_ERROR(dbg, error, \ DW_DLE_MEMORY); \ return (DW_DLE_MEMORY); \ } \ memcpy(&fop3[*count].fp_expr_block, \ (addr), (len)); \ } \ } while(0) - ret = DW_DLE_NONE; *count = 0; p = insts; pe = p + len; while (p < pe) { SET_INSTR_OFFSET(p - insts); if (*p == DW_CFA_nop) { p++; (*count)++; continue; } high2 = *p & 0xc0; low6 = *p & 0x3f; p++; if (high2 > 0) { switch (high2) { case DW_CFA_advance_loc: SET_BASE_OP(high2); SET_OFFSET(low6); break; case DW_CFA_offset: SET_BASE_OP(high2); SET_REGISTER(low6); uoff = _dwarf_decode_uleb128(&p); SET_OFFSET(uoff); break; case DW_CFA_restore: SET_BASE_OP(high2); SET_REGISTER(low6); break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); return (DW_DLE_FRAME_INSTR_EXEC_ERROR); } (*count)++; continue; } SET_EXTENDED_OP(low6); switch (low6) { case DW_CFA_set_loc: - uoff = dbg->decode(&p, dbg->dbg_pointer_size); + uoff = dbg->decode(&p, addr_size); SET_OFFSET(uoff); break; case DW_CFA_advance_loc1: uoff = dbg->decode(&p, 1); SET_OFFSET(uoff); break; case DW_CFA_advance_loc2: uoff = dbg->decode(&p, 2); SET_OFFSET(uoff); break; case DW_CFA_advance_loc4: uoff = dbg->decode(&p, 4); SET_OFFSET(uoff); break; case DW_CFA_offset_extended: case DW_CFA_def_cfa: case DW_CFA_val_offset: reg = _dwarf_decode_uleb128(&p); uoff = _dwarf_decode_uleb128(&p); SET_REGISTER(reg); SET_OFFSET(uoff); break; case DW_CFA_restore_extended: case DW_CFA_undefined: case DW_CFA_same_value: case DW_CFA_def_cfa_register: reg = _dwarf_decode_uleb128(&p); SET_REGISTER(reg); break; case DW_CFA_register: reg = _dwarf_decode_uleb128(&p); reg2 = _dwarf_decode_uleb128(&p); SET_REGISTER(reg); SET_OFFSET(reg2); break; case DW_CFA_remember_state: case DW_CFA_restore_state: break; case DW_CFA_def_cfa_offset: uoff = _dwarf_decode_uleb128(&p); SET_OFFSET(uoff); break; case DW_CFA_def_cfa_expression: blen = _dwarf_decode_uleb128(&p); SET_BLOCK_LEN(blen); SET_EXPR_BLOCK(p, blen); p += blen; break; case DW_CFA_expression: case DW_CFA_val_expression: reg = _dwarf_decode_uleb128(&p); blen = _dwarf_decode_uleb128(&p); SET_REGISTER(reg); SET_BLOCK_LEN(blen); SET_EXPR_BLOCK(p, blen); p += blen; break; case DW_CFA_offset_extended_sf: case DW_CFA_def_cfa_sf: case DW_CFA_val_offset_sf: reg = _dwarf_decode_uleb128(&p); soff = _dwarf_decode_sleb128(&p); SET_REGISTER(reg); SET_OFFSET(soff); break; case DW_CFA_def_cfa_offset_sf: soff = _dwarf_decode_sleb128(&p); SET_OFFSET(soff); break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); return (DW_DLE_FRAME_INSTR_EXEC_ERROR); } (*count)++; } return (DW_DLE_NONE); } int -_dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t *insts, Dwarf_Unsigned len, - Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt, Dwarf_Error *error) +_dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts, + Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt, + Dwarf_Error *error) { Dwarf_Frame_Op *oplist; Dwarf_Unsigned count; int ret; - ret = _dwarf_frame_convert_inst(dbg, insts, len, &count, NULL, NULL, - error); + ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count, + NULL, NULL, error); if (ret != DW_DLE_NONE) return (ret); if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } - ret = _dwarf_frame_convert_inst(dbg, insts, len, &count, oplist, NULL, - error); + ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count, + oplist, NULL, error); if (ret != DW_DLE_NONE) { free(oplist); return (ret); } *ret_oplist = oplist; *ret_opcnt = count; return (DW_DLE_NONE); } int _dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest, Dwarf_Regtable3 *src, Dwarf_Error *error) { int i; assert(dest != NULL); assert(src != NULL); if (*dest == NULL) { if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } (*dest)->rt3_reg_table_size = src->rt3_reg_table_size; (*dest)->rt3_rules = malloc(src->rt3_reg_table_size * sizeof(Dwarf_Regtable_Entry3)); if ((*dest)->rt3_rules == NULL) { free(*dest); DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } } memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule, sizeof(Dwarf_Regtable_Entry3)); for (i = 0; i < (*dest)->rt3_reg_table_size && i < src->rt3_reg_table_size; i++) memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i], sizeof(Dwarf_Regtable_Entry3)); for (; i < (*dest)->rt3_reg_table_size; i++) (*dest)->rt3_rules[i].dw_regnum = dbg->dbg_frame_undefined_value; return (DW_DLE_NONE); } int _dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req, Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_Cie cie; Dwarf_Regtable3 *rt; Dwarf_Addr row_pc; int i, ret; assert(ret_rt != NULL); dbg = fde->fde_dbg; assert(dbg != NULL); rt = dbg->dbg_internal_reg_table; /* Clear the content of regtable from previous run. */ memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3)); memset(rt->rt3_rules, 0, rt->rt3_reg_table_size * sizeof(Dwarf_Regtable_Entry3)); /* Set rules to initial values. */ for (i = 0; i < rt->rt3_reg_table_size; i++) rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value; /* Run initial instructions in CIE. */ cie = fde->fde_cie; assert(cie != NULL); - ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_initinst, - cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0, ~0ULL, - &row_pc, error); + ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize, + cie->cie_initinst, cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0, + ~0ULL, &row_pc, error); if (ret != DW_DLE_NONE) return (ret); /* Run instructions in FDE. */ if (pc_req >= fde->fde_initloc) { - ret = _dwarf_frame_run_inst(dbg, rt, fde->fde_inst, - fde->fde_instlen, cie->cie_caf, cie->cie_daf, - fde->fde_initloc, pc_req, &row_pc, error); + ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize, + fde->fde_inst, fde->fde_instlen, cie->cie_caf, + cie->cie_daf, fde->fde_initloc, pc_req, &row_pc, error); if (ret != DW_DLE_NONE) return (ret); } *ret_rt = rt; *ret_row_pc = row_pc; return (DW_DLE_NONE); } void _dwarf_frame_cleanup(Dwarf_Debug dbg) { Dwarf_Regtable3 *rt; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); if (dbg->dbg_internal_reg_table) { rt = dbg->dbg_internal_reg_table; free(rt->rt3_rules); free(rt); dbg->dbg_internal_reg_table = NULL; } if (dbg->dbg_frame) { _dwarf_frame_section_cleanup(dbg->dbg_frame); dbg->dbg_frame = NULL; } if (dbg->dbg_eh_frame) { _dwarf_frame_section_cleanup(dbg->dbg_eh_frame); dbg->dbg_eh_frame = NULL; } } int _dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error) { Dwarf_Section *ds; if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) { return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame, ds, 0, error)); } return (DW_DLE_NONE); } int _dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error) { Dwarf_Section *ds; if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) { return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame, ds, 1, error)); } return (DW_DLE_NONE); } void _dwarf_frame_params_init(Dwarf_Debug dbg) { /* Initialise call frame related parameters. */ dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM; dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE; dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3; dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL; dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL; } int _dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error) { Dwarf_Regtable3 *rt; if (dbg->dbg_internal_reg_table != NULL) return (DW_DLE_NONE); /* Initialise internal register table. */ if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size; if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size, sizeof(Dwarf_Regtable_Entry3))) == NULL) { free(rt); DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } dbg->dbg_internal_reg_table = rt; return (DW_DLE_NONE); } #define _FDE_INST_INIT_SIZE 128 int _dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error) { Dwarf_P_Debug dbg; uint8_t high2, low6; int ret; #define ds fde #define ds_data fde_inst #define ds_cap fde_instcap #define ds_size fde_instlen assert(fde != NULL && fde->fde_dbg != NULL); dbg = fde->fde_dbg; if (fde->fde_inst == NULL) { fde->fde_instcap = _FDE_INST_INIT_SIZE; fde->fde_instlen = 0; if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } } assert(fde->fde_instcap != 0); RCHECK(WRITE_VALUE(op, 1)); if (op == DW_CFA_nop) return (DW_DLE_NONE); high2 = op & 0xc0; low6 = op & 0x3f; if (high2 > 0) { switch (high2) { case DW_CFA_advance_loc: case DW_CFA_restore: break; case DW_CFA_offset: RCHECK(WRITE_ULEB128(val1)); break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); return (DW_DLE_FRAME_INSTR_EXEC_ERROR); } return (DW_DLE_NONE); } switch (low6) { case DW_CFA_set_loc: RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size)); break; case DW_CFA_advance_loc1: RCHECK(WRITE_VALUE(val1, 1)); break; case DW_CFA_advance_loc2: RCHECK(WRITE_VALUE(val1, 2)); break; case DW_CFA_advance_loc4: RCHECK(WRITE_VALUE(val1, 4)); break; case DW_CFA_offset_extended: case DW_CFA_def_cfa: case DW_CFA_register: RCHECK(WRITE_ULEB128(val1)); RCHECK(WRITE_ULEB128(val2)); break; case DW_CFA_restore_extended: case DW_CFA_undefined: case DW_CFA_same_value: case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: RCHECK(WRITE_ULEB128(val1)); break; case DW_CFA_remember_state: case DW_CFA_restore_state: break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); return (DW_DLE_FRAME_INSTR_EXEC_ERROR); } return (DW_DLE_NONE); gen_fail: return (ret); #undef ds #undef ds_data #undef ds_cap #undef ds_size } static int _dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie, Dwarf_Error *error) { Dwarf_Unsigned len; uint64_t offset; int ret; assert(dbg != NULL && ds != NULL && cie != NULL); cie->cie_offset = offset = ds->ds_size; cie->cie_length = 0; cie->cie_version = 1; /* Length placeholder. */ RCHECK(WRITE_VALUE(cie->cie_length, 4)); /* .debug_frame use CIE id ~0. */ RCHECK(WRITE_VALUE(~0U, 4)); /* .debug_frame version is 1. (DWARF2) */ RCHECK(WRITE_VALUE(cie->cie_version, 1)); /* Write augmentation, if present. */ if (cie->cie_augment != NULL) RCHECK(WRITE_BLOCK(cie->cie_augment, strlen((char *) cie->cie_augment) + 1)); else RCHECK(WRITE_VALUE(0, 1)); /* Write caf, daf and ra. */ RCHECK(WRITE_ULEB128(cie->cie_caf)); RCHECK(WRITE_SLEB128(cie->cie_daf)); RCHECK(WRITE_VALUE(cie->cie_ra, 1)); /* Write initial instructions, if present. */ if (cie->cie_initinst != NULL) RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen)); /* Add padding. */ len = ds->ds_size - cie->cie_offset - 4; cie->cie_length = roundup(len, dbg->dbg_pointer_size); while (len++ < cie->cie_length) RCHECK(WRITE_VALUE(DW_CFA_nop, 1)); /* Fill in the length field. */ dbg->write(ds->ds_data, &offset, cie->cie_length, 4); return (DW_DLE_NONE); gen_fail: return (ret); } static int _dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error) { Dwarf_Unsigned len; uint64_t offset; int ret; assert(dbg != NULL && ds != NULL && drs != NULL); assert(fde != NULL && fde->fde_cie != NULL); fde->fde_offset = offset = ds->ds_size; fde->fde_length = 0; fde->fde_cieoff = fde->fde_cie->cie_offset; /* Length placeholder. */ RCHECK(WRITE_VALUE(fde->fde_length, 4)); /* Write CIE pointer. */ RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error)); /* Write FDE initial location. */ RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx, fde->fde_initloc, NULL, error)); /* * Write FDE address range. Use a pair of relocation entries if * application provided end symbol index. Otherwise write the * length without assoicating any relocation info. */ if (fde->fde_esymndx > 0) RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds, dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx, fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error)); else RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size)); /* Write FDE frame instructions. */ RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen)); /* Add padding. */ len = ds->ds_size - fde->fde_offset - 4; fde->fde_length = roundup(len, dbg->dbg_pointer_size); while (len++ < fde->fde_length) RCHECK(WRITE_VALUE(DW_CFA_nop, 1)); /* Fill in the length field. */ dbg->write(ds->ds_data, &offset, fde->fde_length, 4); return (DW_DLE_NONE); gen_fail: return (ret); } int _dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) { Dwarf_P_Section ds; Dwarf_Rel_Section drs; Dwarf_P_Cie cie; Dwarf_P_Fde fde; int ret; if (STAILQ_EMPTY(&dbg->dbgp_cielist)) return (DW_DLE_NONE); /* Create .debug_frame section. */ if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) != DW_DLE_NONE) goto gen_fail0; /* Create relocation section for .debug_frame */ RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error)); /* Generate list of CIE. */ STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next) RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error)); /* Generate list of FDE. */ STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next) RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error)); /* Inform application the creation of .debug_frame ELF section. */ RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); /* Finalize relocation section for .debug_frame */ RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); return (DW_DLE_NONE); gen_fail: _dwarf_reloc_section_free(dbg, &drs); gen_fail0: _dwarf_section_free(dbg, &ds); return (ret); } void _dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg) { Dwarf_P_Cie cie, tcie; Dwarf_P_Fde fde, tfde; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) { STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next); if (cie->cie_augment) free(cie->cie_augment); if (cie->cie_initinst) free(cie->cie_initinst); free(cie); } dbg->dbgp_cielen = 0; STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) { STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next); if (fde->fde_inst != NULL) free(fde->fde_inst); free(fde); } dbg->dbgp_fdelen = 0; } diff --git a/libdwarf/libdwarf_info.c b/libdwarf/libdwarf_info.c index dc82b7ddfde8..261bee6d933e 100644 --- a/libdwarf/libdwarf_info.c +++ b/libdwarf/libdwarf_info.c @@ -1,281 +1,382 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) - * Copyright (c) 2010,2011 Kai Wang + * Copyright (c) 2010,2011,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_info.c 2942 2013-05-04 23:03:54Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_info.c 3041 2014-05-18 15:11:03Z kaiwang27 $"); int _dwarf_info_first_cu(Dwarf_Debug dbg, Dwarf_Error *error) { Dwarf_CU cu; int ret; assert(dbg->dbg_cu_current == NULL); cu = STAILQ_FIRST(&dbg->dbg_cu); if (cu != NULL) { dbg->dbg_cu_current = cu; return (DW_DLE_NONE); } if (dbg->dbg_info_loaded) return (DW_DLE_NO_ENTRY); dbg->dbg_info_off = 0; - ret = _dwarf_info_load(dbg, 0, error); + ret = _dwarf_info_load(dbg, 0, 1, error); if (ret != DW_DLE_NONE) return (ret); dbg->dbg_cu_current = STAILQ_FIRST(&dbg->dbg_cu); return (DW_DLE_NONE); } +int +_dwarf_info_first_tu(Dwarf_Debug dbg, Dwarf_Error *error) +{ + Dwarf_CU tu; + int ret; + + assert(dbg->dbg_tu_current == NULL); + tu = STAILQ_FIRST(&dbg->dbg_tu); + if (tu != NULL) { + dbg->dbg_tu_current = tu; + return (DW_DLE_NONE); + } + + if (dbg->dbg_types_loaded) + return (DW_DLE_NO_ENTRY); + + dbg->dbg_types_off = 0; + ret = _dwarf_info_load(dbg, 0, 0, error); + if (ret != DW_DLE_NONE) + return (ret); + + dbg->dbg_tu_current = STAILQ_FIRST(&dbg->dbg_tu); + + return (DW_DLE_NONE); +} + int _dwarf_info_next_cu(Dwarf_Debug dbg, Dwarf_Error *error) { Dwarf_CU cu; int ret; assert(dbg->dbg_cu_current != NULL); cu = STAILQ_NEXT(dbg->dbg_cu_current, cu_next); if (cu != NULL) { dbg->dbg_cu_current = cu; return (DW_DLE_NONE); } if (dbg->dbg_info_loaded) { dbg->dbg_cu_current = NULL; return (DW_DLE_NO_ENTRY); } - ret = _dwarf_info_load(dbg, 0, error); + ret = _dwarf_info_load(dbg, 0, 1, error); if (ret != DW_DLE_NONE) return (ret); dbg->dbg_cu_current = STAILQ_NEXT(dbg->dbg_cu_current, cu_next); return (DW_DLE_NONE); } int -_dwarf_info_load(Dwarf_Debug dbg, int load_all, Dwarf_Error *error) +_dwarf_info_next_tu(Dwarf_Debug dbg, Dwarf_Error *error) +{ + Dwarf_CU cu; + int ret; + + assert(dbg->dbg_tu_current != NULL); + cu = STAILQ_NEXT(dbg->dbg_tu_current, cu_next); + if (cu != NULL) { + dbg->dbg_tu_current = cu; + return (DW_DLE_NONE); + } + + if (dbg->dbg_types_loaded) { + dbg->dbg_tu_current = NULL; + return (DW_DLE_NO_ENTRY); + } + + ret = _dwarf_info_load(dbg, 0, 0, error); + if (ret != DW_DLE_NONE) + return (ret); + + dbg->dbg_tu_current = STAILQ_NEXT(dbg->dbg_tu_current, cu_next); + + return (DW_DLE_NONE); +} + +int +_dwarf_info_load(Dwarf_Debug dbg, Dwarf_Bool load_all, Dwarf_Bool is_info, + Dwarf_Error *error) { Dwarf_CU cu; Dwarf_Section *ds; int dwarf_size, ret; uint64_t length; uint64_t next_offset; uint64_t offset; ret = DW_DLE_NONE; - if (dbg->dbg_info_loaded) - return (DW_DLE_NONE); - offset = dbg->dbg_info_off; - ds = dbg->dbg_info_sec; - assert(ds != NULL); + if (is_info) { + if (dbg->dbg_info_loaded) + return (ret); + offset = dbg->dbg_info_off; + ds = dbg->dbg_info_sec; + assert(ds != NULL); + } else { + if (dbg->dbg_types_loaded) + return (ret); + offset = dbg->dbg_types_off; + ds = dbg->dbg_types_sec; + if (ds == NULL) + return (DW_DLE_NO_ENTRY); + } + while (offset < ds->ds_size) { if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } cu->cu_dbg = dbg; + cu->cu_is_info = is_info; cu->cu_offset = offset; length = dbg->read(ds->ds_data, &offset, 4); if (length == 0xffffffff) { length = dbg->read(ds->ds_data, &offset, 8); dwarf_size = 8; } else dwarf_size = 4; cu->cu_dwarf_size = dwarf_size; /* * Check if there is enough ELF data for this CU. This assumes * that libelf gives us the entire section in one Elf_Data * object. */ if (length > ds->ds_size - offset) { free(cu); DWARF_SET_ERROR(dbg, error, DW_DLE_CU_LENGTH_ERROR); return (DW_DLE_CU_LENGTH_ERROR); } /* Compute the offset to the next compilation unit: */ next_offset = offset + length; - dbg->dbg_info_off = next_offset; + if (is_info) + dbg->dbg_info_off = next_offset; + else + dbg->dbg_types_off = next_offset; /* Initialise the compilation unit. */ cu->cu_length = length; cu->cu_length_size = (dwarf_size == 4 ? 4 : 12); cu->cu_version = dbg->read(ds->ds_data, &offset, 2); cu->cu_abbrev_offset = dbg->read(ds->ds_data, &offset, dwarf_size); cu->cu_abbrev_offset_cur = cu->cu_abbrev_offset; cu->cu_pointer_size = dbg->read(ds->ds_data, &offset, 1); cu->cu_next_offset = next_offset; + /* .debug_types extra fields. */ + if (!is_info) { + memcpy(cu->cu_type_sig.signature, + (char *) ds->ds_data + offset, 8); + offset += 8; + cu->cu_type_offset = dbg->read(ds->ds_data, &offset, + dwarf_size); + } + /* Add the compilation unit to the list. */ - STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); + if (is_info) + STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); + else + STAILQ_INSERT_TAIL(&dbg->dbg_tu, cu, cu_next); if (cu->cu_version < 2 || cu->cu_version > 4) { DWARF_SET_ERROR(dbg, error, DW_DLE_VERSION_STAMP_ERROR); ret = DW_DLE_VERSION_STAMP_ERROR; break; } cu->cu_1st_offset = offset; offset = next_offset; if (!load_all) break; } - if ((Dwarf_Unsigned) dbg->dbg_info_off >= ds->ds_size) - dbg->dbg_info_loaded = 1; + if (is_info) { + if ((Dwarf_Unsigned) dbg->dbg_info_off >= ds->ds_size) + dbg->dbg_info_loaded = 1; + } else { + if ((Dwarf_Unsigned) dbg->dbg_types_off >= ds->ds_size) + dbg->dbg_types_loaded = 1; + } return (ret); } void _dwarf_info_cleanup(Dwarf_Debug dbg) { Dwarf_CU cu, tcu; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); STAILQ_FOREACH_SAFE(cu, &dbg->dbg_cu, cu_next, tcu) { STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); _dwarf_abbrev_cleanup(cu); if (cu->cu_lineinfo != NULL) { _dwarf_lineno_cleanup(cu->cu_lineinfo); cu->cu_lineinfo = NULL; } free(cu); } + + _dwarf_type_unit_cleanup(dbg); +} + +void +_dwarf_type_unit_cleanup(Dwarf_Debug dbg) +{ + Dwarf_CU cu, tcu; + + assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); + + STAILQ_FOREACH_SAFE(cu, &dbg->dbg_tu, cu_next, tcu) { + STAILQ_REMOVE(&dbg->dbg_tu, cu, _Dwarf_CU, cu_next); + _dwarf_abbrev_cleanup(cu); + free(cu); + } } int _dwarf_info_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) { Dwarf_P_Section ds; Dwarf_Rel_Section drs; Dwarf_Unsigned offset; Dwarf_CU cu; int ret; assert(dbg != NULL && dbg->write_alloc != NULL); if (dbg->dbgp_root_die == NULL) return (DW_DLE_NONE); /* Create the single CU for this debugging object. */ if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } cu->cu_dbg = dbg; cu->cu_version = 2; /* DWARF2 */ cu->cu_pointer_size = dbg->dbg_pointer_size; STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); /* Create .debug_info section. */ if ((ret = _dwarf_section_init(dbg, &dbg->dbgp_info, ".debug_info", 0, error)) != DW_DLE_NONE) goto gen_fail1; ds = dbg->dbgp_info; /* Create relocation section for .debug_init */ if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) != DW_DLE_NONE) goto gen_fail0; /* Length placeholder. (We only use 32-bit DWARF format) */ RCHECK(WRITE_VALUE(cu->cu_length, 4)); /* Write CU version */ RCHECK(WRITE_VALUE(cu->cu_version, 2)); /* * Write abbrev offset. (always 0, we only support single CU) * Also generate a relocation entry for this offset. */ RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, ds->ds_size, 0, cu->cu_abbrev_offset, ".debug_abbrev", error)); /* Pointer size. */ RCHECK(WRITE_VALUE(cu->cu_pointer_size, 1)); /* Transform the DIE(s) of this CU. */ RCHECK(_dwarf_die_gen(dbg, cu, drs, error)); /* Now we can fill in the length of this CU. */ cu->cu_length = ds->ds_size - 4; offset = 0; dbg->write(ds->ds_data, &offset, cu->cu_length, 4); /* Inform application the creation of .debug_info ELF section. */ RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); /* * Inform application the creation of relocation section for * .debug_info. */ RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); return (DW_DLE_NONE); gen_fail: _dwarf_reloc_section_free(dbg, &drs); gen_fail0: _dwarf_section_free(dbg, &dbg->dbgp_info); gen_fail1: STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); free(cu); return (ret); } void _dwarf_info_pro_cleanup(Dwarf_P_Debug dbg) { Dwarf_CU cu; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); cu = STAILQ_FIRST(&dbg->dbg_cu); if (cu != NULL) { STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); _dwarf_abbrev_cleanup(cu); free(cu); } } diff --git a/libdwarf/libdwarf_init.c b/libdwarf/libdwarf_init.c index 71d596699d58..8e3fbbe5db36 100644 --- a/libdwarf/libdwarf_init.c +++ b/libdwarf/libdwarf_init.c @@ -1,316 +1,320 @@ /*- * Copyright (c) 2009,2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_init.c 2948 2013-05-30 21:25:52Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_init.c 3061 2014-06-02 00:42:41Z kaiwang27 $"); static int _dwarf_consumer_init(Dwarf_Debug dbg, Dwarf_Error *error) { const Dwarf_Obj_Access_Methods *m; Dwarf_Obj_Access_Section sec; void *obj; Dwarf_Unsigned cnt; Dwarf_Half i; int ret; assert(dbg != NULL); assert(dbg->dbg_iface != NULL); m = dbg->dbg_iface->methods; obj = dbg->dbg_iface->object; assert(m != NULL); assert(obj != NULL); if (m->get_byte_order(obj) == DW_OBJECT_MSB) { dbg->read = _dwarf_read_msb; dbg->write = _dwarf_write_msb; dbg->decode = _dwarf_decode_msb; } else { dbg->read = _dwarf_read_lsb; dbg->write = _dwarf_write_lsb; dbg->decode = _dwarf_decode_lsb; } dbg->dbg_pointer_size = m->get_pointer_size(obj); dbg->dbg_offset_size = m->get_length_size(obj); cnt = m->get_section_count(obj); if (cnt == 0) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_INFO_NULL); return (DW_DLE_DEBUG_INFO_NULL); } dbg->dbg_seccnt = cnt; - if ((dbg->dbg_section = calloc(cnt, sizeof(Dwarf_Section))) == NULL) { + if ((dbg->dbg_section = calloc(cnt + 1, sizeof(Dwarf_Section))) == + NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } for (i = 0; i < cnt; i++) { if (m->get_section_info(obj, i, &sec, &ret) != DW_DLV_OK) { DWARF_SET_ERROR(dbg, error, ret); return (ret); } dbg->dbg_section[i].ds_addr = sec.addr; dbg->dbg_section[i].ds_size = sec.size; dbg->dbg_section[i].ds_name = sec.name; if (m->load_section(obj, i, &dbg->dbg_section[i].ds_data, &ret) != DW_DLV_OK) { DWARF_SET_ERROR(dbg, error, ret); return (ret); } } + dbg->dbg_section[cnt].ds_name = NULL; if (_dwarf_find_section(dbg, ".debug_abbrev") == NULL || ((dbg->dbg_info_sec = _dwarf_find_section(dbg, ".debug_info")) == NULL)) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_INFO_NULL); return (DW_DLE_DEBUG_INFO_NULL); } + /* Try to find the optional DWARF4 .debug_types section. */ + dbg->dbg_types_sec = _dwarf_find_next_types_section(dbg, NULL); + /* Initialise call frame API related parameters. */ _dwarf_frame_params_init(dbg); return (DW_DLV_OK); } static int _dwarf_producer_init(Dwarf_Debug dbg, Dwarf_Unsigned pf, Dwarf_Error *error) { /* Producer only support DWARF2 which has fixed 32bit offset. */ dbg->dbg_offset_size = 4; if (pf & DW_DLC_SIZE_32 && pf & DW_DLC_SIZE_64) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLE_ARGUMENT); } if ((pf & DW_DLC_SIZE_32) == 0 && (pf & DW_DLC_SIZE_64) == 0) pf |= DW_DLC_SIZE_32; if (pf & DW_DLC_SIZE_64) dbg->dbg_pointer_size = 8; else dbg->dbg_pointer_size = 4; if (pf & DW_DLC_ISA_IA64 && pf & DW_DLC_ISA_MIPS) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLE_ARGUMENT); } if (pf & DW_DLC_ISA_IA64) dbg->dbgp_isa = DW_ISA_IA64; else dbg->dbgp_isa = DW_ISA_MIPS; if (pf & DW_DLC_TARGET_BIGENDIAN && pf & DW_DLC_TARGET_LITTLEENDIAN) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLE_ARGUMENT); } if ((pf & DW_DLC_TARGET_BIGENDIAN) == 0 && (pf & DW_DLC_TARGET_LITTLEENDIAN) == 0) { #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_BIG_ENDIAN pf |= DW_DLC_TARGET_BIGENDIAN; #else pf |= DW_DLC_TARGET_LITTLEENDIAN; #endif } if (pf & DW_DLC_TARGET_BIGENDIAN) { dbg->write = _dwarf_write_msb; dbg->write_alloc = _dwarf_write_msb_alloc; } else if (pf & DW_DLC_TARGET_LITTLEENDIAN) { dbg->write = _dwarf_write_lsb; dbg->write_alloc = _dwarf_write_lsb_alloc; } else assert(0); if (pf & DW_DLC_STREAM_RELOCATIONS && pf & DW_DLC_SYMBOLIC_RELOCATIONS) { DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); return (DW_DLE_ARGUMENT); } if ((pf & DW_DLC_STREAM_RELOCATIONS) == 0 && (pf & DW_DLC_SYMBOLIC_RELOCATIONS) == 0) pf |= DW_DLC_STREAM_RELOCATIONS; dbg->dbgp_flags = pf; STAILQ_INIT(&dbg->dbgp_dielist); STAILQ_INIT(&dbg->dbgp_pelist); STAILQ_INIT(&dbg->dbgp_seclist); STAILQ_INIT(&dbg->dbgp_drslist); STAILQ_INIT(&dbg->dbgp_cielist); STAILQ_INIT(&dbg->dbgp_fdelist); if ((dbg->dbgp_lineinfo = calloc(1, sizeof(struct _Dwarf_LineInfo))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INIT(&dbg->dbgp_lineinfo->li_lflist); STAILQ_INIT(&dbg->dbgp_lineinfo->li_lnlist); if ((dbg->dbgp_as = calloc(1, sizeof(struct _Dwarf_ArangeSet))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INIT(&dbg->dbgp_as->as_arlist); return (DW_DLE_NONE); } int _dwarf_init(Dwarf_Debug dbg, Dwarf_Unsigned pro_flags, Dwarf_Handler errhand, Dwarf_Ptr errarg, Dwarf_Error *error) { int ret; ret = DW_DLE_NONE; /* * Set the error handler fields early, so that the application * is notified of initialization errors. */ dbg->dbg_errhand = errhand; dbg->dbg_errarg = errarg; STAILQ_INIT(&dbg->dbg_cu); + STAILQ_INIT(&dbg->dbg_tu); STAILQ_INIT(&dbg->dbg_rllist); STAILQ_INIT(&dbg->dbg_aslist); STAILQ_INIT(&dbg->dbg_mslist); - TAILQ_INIT(&dbg->dbg_loclist); if (dbg->dbg_mode == DW_DLC_READ || dbg->dbg_mode == DW_DLC_RDWR) { ret = _dwarf_consumer_init(dbg, error); if (ret != DW_DLE_NONE) { _dwarf_deinit(dbg); return (ret); } } if (dbg->dbg_mode == DW_DLC_WRITE) { ret = _dwarf_producer_init(dbg, pro_flags, error); if (ret != DW_DLE_NONE) { _dwarf_deinit(dbg); return (ret); } } /* * Initialise internal string table. */ if ((ret = _dwarf_strtab_init(dbg, error)) != DW_DLE_NONE) return (ret); return (DW_DLE_NONE); } static void _dwarf_producer_deinit(Dwarf_P_Debug dbg) { assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); _dwarf_info_pro_cleanup(dbg); _dwarf_die_pro_cleanup(dbg); _dwarf_expr_cleanup(dbg); _dwarf_lineno_pro_cleanup(dbg); _dwarf_frame_pro_cleanup(dbg); _dwarf_arange_pro_cleanup(dbg); _dwarf_macinfo_pro_cleanup(dbg); _dwarf_strtab_cleanup(dbg); _dwarf_nametbl_pro_cleanup(&dbg->dbgp_pubs); _dwarf_nametbl_pro_cleanup(&dbg->dbgp_weaks); _dwarf_nametbl_pro_cleanup(&dbg->dbgp_funcs); _dwarf_nametbl_pro_cleanup(&dbg->dbgp_types); _dwarf_nametbl_pro_cleanup(&dbg->dbgp_vars); _dwarf_section_cleanup(dbg); _dwarf_reloc_cleanup(dbg); } static void _dwarf_consumer_deinit(Dwarf_Debug dbg) { assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); _dwarf_info_cleanup(dbg); - _dwarf_loclist_cleanup(dbg); _dwarf_ranges_cleanup(dbg); _dwarf_frame_cleanup(dbg); _dwarf_arange_cleanup(dbg); _dwarf_macinfo_cleanup(dbg); _dwarf_strtab_cleanup(dbg); _dwarf_nametbl_cleanup(&dbg->dbg_globals); _dwarf_nametbl_cleanup(&dbg->dbg_pubtypes); _dwarf_nametbl_cleanup(&dbg->dbg_weaks); _dwarf_nametbl_cleanup(&dbg->dbg_funcs); _dwarf_nametbl_cleanup(&dbg->dbg_vars); _dwarf_nametbl_cleanup(&dbg->dbg_types); free(dbg->dbg_section); } void _dwarf_deinit(Dwarf_Debug dbg) { assert(dbg != NULL); if (dbg->dbg_mode == DW_DLC_READ) _dwarf_consumer_deinit(dbg); else if (dbg->dbg_mode == DW_DLC_WRITE) _dwarf_producer_deinit(dbg); } int _dwarf_alloc(Dwarf_Debug *ret_dbg, int mode, Dwarf_Error *error) { Dwarf_Debug dbg; if ((dbg = calloc(sizeof(struct _Dwarf_Debug), 1)) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } dbg->dbg_mode = mode; *ret_dbg = dbg; return (DW_DLE_NONE); } diff --git a/libdwarf/libdwarf_lineno.c b/libdwarf/libdwarf_lineno.c index 8bb3c85f3dee..63627f736f7f 100644 --- a/libdwarf/libdwarf_lineno.c +++ b/libdwarf/libdwarf_lineno.c @@ -1,785 +1,775 @@ /*- * Copyright (c) 2009,2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_lineno.c 2972 2013-12-23 06:46:04Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_lineno.c 3100 2014-10-25 20:34:29Z jkoshy $"); static int _dwarf_lineno_add_file(Dwarf_LineInfo li, uint8_t **p, const char *compdir, Dwarf_Error *error, Dwarf_Debug dbg) { Dwarf_LineFile lf; const char *dirname; uint8_t *src; int slen; src = *p; if ((lf = malloc(sizeof(struct _Dwarf_LineFile))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } lf->lf_fullpath = NULL; lf->lf_fname = (char *) src; src += strlen(lf->lf_fname) + 1; lf->lf_dirndx = _dwarf_decode_uleb128(&src); if (lf->lf_dirndx > li->li_inclen) { free(lf); DWARF_SET_ERROR(dbg, error, DW_DLE_DIR_INDEX_BAD); return (DW_DLE_DIR_INDEX_BAD); } /* Make full pathname if need. */ if (*lf->lf_fname != '/') { dirname = compdir; if (lf->lf_dirndx > 0) dirname = li->li_incdirs[lf->lf_dirndx - 1]; if (dirname != NULL) { slen = strlen(dirname) + strlen(lf->lf_fname) + 2; if ((lf->lf_fullpath = malloc(slen)) == NULL) { free(lf); DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } snprintf(lf->lf_fullpath, slen, "%s/%s", dirname, lf->lf_fname); } } lf->lf_mtime = _dwarf_decode_uleb128(&src); lf->lf_size = _dwarf_decode_uleb128(&src); STAILQ_INSERT_TAIL(&li->li_lflist, lf, lf_next); li->li_lflen++; *p = src; return (DW_DLE_NONE); } static int _dwarf_lineno_run_program(Dwarf_CU cu, Dwarf_LineInfo li, uint8_t *p, uint8_t *pe, const char *compdir, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_Line ln, tln; - uint64_t address, file, line, column, isa, opsize; + uint64_t address, file, line, column, opsize; int is_stmt, basic_block, end_sequence; - int prologue_end, epilogue_begin; int ret; #define RESET_REGISTERS \ do { \ address = 0; \ file = 1; \ line = 1; \ column = 0; \ is_stmt = li->li_defstmt; \ basic_block = 0; \ end_sequence = 0; \ - prologue_end = 0; \ - epilogue_begin = 0; \ } while(0) #define APPEND_ROW \ do { \ ln = malloc(sizeof(struct _Dwarf_Line)); \ if (ln == NULL) { \ ret = DW_DLE_MEMORY; \ DWARF_SET_ERROR(dbg, error, ret); \ goto prog_fail; \ } \ ln->ln_li = li; \ ln->ln_addr = address; \ ln->ln_symndx = 0; \ ln->ln_fileno = file; \ ln->ln_lineno = line; \ ln->ln_column = column; \ ln->ln_bblock = basic_block; \ ln->ln_stmt = is_stmt; \ ln->ln_endseq = end_sequence; \ STAILQ_INSERT_TAIL(&li->li_lnlist, ln, ln_next);\ li->li_lnlen++; \ } while(0) #define LINE(x) (li->li_lbase + (((x) - li->li_opbase) % li->li_lrange)) #define ADDRESS(x) ((((x) - li->li_opbase) / li->li_lrange) * li->li_minlen) dbg = cu->cu_dbg; /* * Set registers to their default values. */ RESET_REGISTERS; /* * Start line number program. */ while (p < pe) { if (*p == 0) { /* * Extended Opcodes. */ p++; opsize = _dwarf_decode_uleb128(&p); switch (*p) { case DW_LNE_end_sequence: p++; end_sequence = 1; APPEND_ROW; RESET_REGISTERS; break; case DW_LNE_set_address: p++; address = dbg->decode(&p, cu->cu_pointer_size); break; case DW_LNE_define_file: p++; ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg); if (ret != DW_DLE_NONE) goto prog_fail; break; default: /* Unrecognized extened opcodes. */ p += opsize; } } else if (*p > 0 && *p < li->li_opbase) { /* * Standard Opcodes. */ switch (*p++) { case DW_LNS_copy: APPEND_ROW; basic_block = 0; - prologue_end = 0; - epilogue_begin = 0; break; case DW_LNS_advance_pc: address += _dwarf_decode_uleb128(&p) * li->li_minlen; break; case DW_LNS_advance_line: line += _dwarf_decode_sleb128(&p); break; case DW_LNS_set_file: file = _dwarf_decode_uleb128(&p); break; case DW_LNS_set_column: column = _dwarf_decode_uleb128(&p); break; case DW_LNS_negate_stmt: is_stmt = !is_stmt; break; case DW_LNS_set_basic_block: basic_block = 1; break; case DW_LNS_const_add_pc: address += ADDRESS(255); break; case DW_LNS_fixed_advance_pc: address += dbg->decode(&p, 2); break; case DW_LNS_set_prologue_end: - prologue_end = 1; break; case DW_LNS_set_epilogue_begin: - epilogue_begin = 1; break; case DW_LNS_set_isa: - isa = _dwarf_decode_uleb128(&p); + (void) _dwarf_decode_uleb128(&p); break; default: /* Unrecognized extened opcodes. What to do? */ break; } } else { /* * Special Opcodes. */ line += LINE(*p); address += ADDRESS(*p); APPEND_ROW; basic_block = 0; - prologue_end = 0; - epilogue_begin = 0; p++; } } return (DW_DLE_NONE); prog_fail: STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) { STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next); free(ln); } return (ret); #undef RESET_REGISTERS #undef APPEND_ROW #undef LINE #undef ADDRESS } int _dwarf_lineno_init(Dwarf_Die die, uint64_t offset, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_Section *ds; Dwarf_CU cu; Dwarf_Attribute at; Dwarf_LineInfo li; Dwarf_LineFile lf, tlf; const char *compdir; uint64_t length, hdroff, endoff; uint8_t *p; int dwarf_size, i, ret; cu = die->die_cu; assert(cu != NULL); dbg = cu->cu_dbg; assert(dbg != NULL); if ((ds = _dwarf_find_section(dbg, ".debug_line")) == NULL) return (DW_DLE_NONE); /* * Try to find out the dir where the CU was compiled. Later we * will use the dir to create full pathnames, if need. */ compdir = NULL; at = _dwarf_attr_find(die, DW_AT_comp_dir); if (at != NULL) { switch (at->at_form) { case DW_FORM_strp: compdir = at->u[1].s; break; case DW_FORM_string: compdir = at->u[0].s; break; default: break; } } length = dbg->read(ds->ds_data, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = dbg->read(ds->ds_data, &offset, 8); } else dwarf_size = 4; if (length > ds->ds_size - offset) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD); return (DW_DLE_DEBUG_LINE_LENGTH_BAD); } if ((li = calloc(1, sizeof(struct _Dwarf_LineInfo))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } /* * Read in line number program header. */ li->li_length = length; endoff = offset + length; li->li_version = dbg->read(ds->ds_data, &offset, 2); /* FIXME: verify version */ li->li_hdrlen = dbg->read(ds->ds_data, &offset, dwarf_size); hdroff = offset; li->li_minlen = dbg->read(ds->ds_data, &offset, 1); li->li_defstmt = dbg->read(ds->ds_data, &offset, 1); li->li_lbase = dbg->read(ds->ds_data, &offset, 1); li->li_lrange = dbg->read(ds->ds_data, &offset, 1); li->li_opbase = dbg->read(ds->ds_data, &offset, 1); STAILQ_INIT(&li->li_lflist); STAILQ_INIT(&li->li_lnlist); if ((int)li->li_hdrlen - 5 < li->li_opbase - 1) { ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } if ((li->li_oplen = malloc(li->li_opbase)) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } /* * Read in std opcode arg length list. Note that the first * element is not used. */ for (i = 1; i < li->li_opbase; i++) li->li_oplen[i] = dbg->read(ds->ds_data, &offset, 1); /* * Check how many strings in the include dir string array. */ length = 0; p = ds->ds_data + offset; while (*p != '\0') { while (*p++ != '\0') ; length++; } li->li_inclen = length; /* Sanity check. */ if (p - ds->ds_data > (int) ds->ds_size) { ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } if (length != 0) { if ((li->li_incdirs = malloc(length * sizeof(char *))) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } } /* Fill in include dir array. */ i = 0; p = ds->ds_data + offset; while (*p != '\0') { li->li_incdirs[i++] = (char *) p; while (*p++ != '\0') ; } p++; /* * Process file list. */ while (*p != '\0') { ret = _dwarf_lineno_add_file(li, &p, compdir, error, dbg); if (ret != DW_DLE_NONE) goto fail_cleanup; if (p - ds->ds_data > (int) ds->ds_size) { ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } } p++; /* Sanity check. */ if (p - ds->ds_data - hdroff != li->li_hdrlen) { ret = DW_DLE_DEBUG_LINE_LENGTH_BAD; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } /* * Process line number program. */ ret = _dwarf_lineno_run_program(cu, li, p, ds->ds_data + endoff, compdir, error); if (ret != DW_DLE_NONE) goto fail_cleanup; cu->cu_lineinfo = li; return (DW_DLE_NONE); fail_cleanup: STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) { STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next); if (lf->lf_fullpath) free(lf->lf_fullpath); free(lf); } if (li->li_oplen) free(li->li_oplen); if (li->li_incdirs) free(li->li_incdirs); free(li); return (ret); } void _dwarf_lineno_cleanup(Dwarf_LineInfo li) { Dwarf_LineFile lf, tlf; Dwarf_Line ln, tln; if (li == NULL) return; STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) { STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next); if (lf->lf_fullpath) free(lf->lf_fullpath); free(lf); } STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) { STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next); free(ln); } if (li->li_oplen) free(li->li_oplen); if (li->li_incdirs) free(li->li_incdirs); if (li->li_lnarray) free(li->li_lnarray); if (li->li_lfnarray) free(li->li_lfnarray); free(li); } static int _dwarf_lineno_gen_program(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs, Dwarf_Error * error) { Dwarf_LineInfo li; Dwarf_Line ln; Dwarf_Unsigned address, file, line, spc; Dwarf_Unsigned addr0, maddr; Dwarf_Signed line0, column; - int is_stmt, basic_block, end_sequence; + int is_stmt, basic_block; int need_copy; int ret; #define RESET_REGISTERS \ do { \ address = 0; \ file = 1; \ line = 1; \ column = 0; \ is_stmt = li->li_defstmt; \ basic_block = 0; \ - end_sequence = 0; \ } while(0) li = dbg->dbgp_lineinfo; maddr = (255 - li->li_opbase) / li->li_lrange; RESET_REGISTERS; STAILQ_FOREACH(ln, &li->li_lnlist, ln_next) { if (ln->ln_symndx > 0) { /* * Generate DW_LNE_set_address extended op. */ RCHECK(WRITE_VALUE(0, 1)); RCHECK(WRITE_ULEB128(dbg->dbg_pointer_size + 1)); RCHECK(WRITE_VALUE(DW_LNE_set_address, 1)); RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, dbg->dbg_pointer_size, ds->ds_size, ln->ln_symndx, ln->ln_addr, NULL, error)); address = ln->ln_addr; continue; } else if (ln->ln_endseq) { addr0 = (ln->ln_addr - address) / li->li_minlen; if (addr0 != 0) { RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1)); RCHECK(WRITE_ULEB128(addr0)); } /* * Generate DW_LNE_end_sequence. */ RCHECK(WRITE_VALUE(0, 1)); RCHECK(WRITE_ULEB128(1)); RCHECK(WRITE_VALUE(DW_LNE_end_sequence, 1)); RESET_REGISTERS; continue; } /* * Generate standard opcodes for file, column, is_stmt or * basic_block changes. */ if (ln->ln_fileno != file) { RCHECK(WRITE_VALUE(DW_LNS_set_file, 1)); RCHECK(WRITE_ULEB128(ln->ln_fileno)); file = ln->ln_fileno; } if (ln->ln_column != column) { RCHECK(WRITE_VALUE(DW_LNS_set_column, 1)); RCHECK(WRITE_ULEB128(ln->ln_column)); column = ln->ln_column; } if (ln->ln_stmt != is_stmt) { RCHECK(WRITE_VALUE(DW_LNS_negate_stmt, 1)); is_stmt = ln->ln_stmt; } if (ln->ln_bblock && !basic_block) { RCHECK(WRITE_VALUE(DW_LNS_set_basic_block, 1)); basic_block = 1; } /* * Calculate address and line number change. */ addr0 = (ln->ln_addr - address) / li->li_minlen; line0 = ln->ln_lineno - line; if (addr0 == 0 && line0 == 0) continue; /* * Check if line delta is with the range and if the special * opcode can be used. */ assert(li->li_lbase <= 0); if (line0 >= li->li_lbase && line0 <= li->li_lbase + li->li_lrange - 1) { spc = (line0 - li->li_lbase) + (li->li_lrange * addr0) + li->li_opbase; if (spc <= 255) { RCHECK(WRITE_VALUE(spc, 1)); basic_block = 0; goto next_line; } } /* Generate DW_LNS_advance_line for line number change. */ if (line0 != 0) { RCHECK(WRITE_VALUE(DW_LNS_advance_line, 1)); RCHECK(WRITE_SLEB128(line0)); line0 = 0; need_copy = 1; } else need_copy = basic_block; if (addr0 != 0) { /* See if it can be handled by DW_LNS_const_add_pc. */ spc = (line0 - li->li_lbase) + (li->li_lrange * (addr0 - maddr)) + li->li_opbase; if (addr0 >= maddr && spc <= 255) { RCHECK(WRITE_VALUE(DW_LNS_const_add_pc, 1)); RCHECK(WRITE_VALUE(spc, 1)); } else { /* Otherwise we use DW_LNS_advance_pc. */ RCHECK(WRITE_VALUE(DW_LNS_advance_pc, 1)); RCHECK(WRITE_ULEB128(addr0)); } } if (need_copy) { RCHECK(WRITE_VALUE(DW_LNS_copy, 1)); basic_block = 0; } next_line: address = ln->ln_addr; line = ln->ln_lineno; } return (DW_DLE_NONE); gen_fail: return (ret); #undef RESET_REGISTERS } static uint8_t _dwarf_get_minlen(Dwarf_P_Debug dbg) { assert(dbg != NULL); switch (dbg->dbgp_isa) { case DW_ISA_ARM: return (2); case DW_ISA_X86: case DW_ISA_X86_64: return (1); default: return (4); } } static uint8_t oplen[] = {0, 1, 1, 1, 1, 0, 0, 0, 1}; int _dwarf_lineno_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) { Dwarf_LineInfo li; Dwarf_LineFile lf; Dwarf_P_Section ds; Dwarf_Rel_Section drs; Dwarf_Unsigned offset; int i, ret; assert(dbg != NULL && dbg->dbgp_lineinfo != NULL); li = dbg->dbgp_lineinfo; if (STAILQ_EMPTY(&li->li_lnlist)) return (DW_DLE_NONE); li->li_length = 0; li->li_version = 2; li->li_hdrlen = 0; li->li_minlen = _dwarf_get_minlen(dbg); li->li_defstmt = 1; li->li_lbase = -5; li->li_lrange = 14; li->li_opbase = 10; /* Create .debug_line section. */ if ((ret = _dwarf_section_init(dbg, &ds, ".debug_line", 0, error)) != DW_DLE_NONE) return (ret); /* Create relocation section for .debug_line */ if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) != DW_DLE_NONE) goto gen_fail1; /* Length placeholder. (We only use 32-bit DWARF format) */ RCHECK(WRITE_VALUE(0, 4)); /* Write line number dwarf version. (DWARF2) */ RCHECK(WRITE_VALUE(li->li_version, 2)); /* Header length placeholder. */ offset = ds->ds_size; RCHECK(WRITE_VALUE(li->li_hdrlen, 4)); /* Write minimum instruction length. */ RCHECK(WRITE_VALUE(li->li_minlen, 1)); /* * Write initial value for is_stmt. XXX Which default value we * should use? */ RCHECK(WRITE_VALUE(li->li_defstmt, 1)); /* * Write line_base and line_range. FIXME These value needs to be * fine tuned. */ RCHECK(WRITE_VALUE(li->li_lbase, 1)); RCHECK(WRITE_VALUE(li->li_lrange, 1)); /* Write opcode_base. (DWARF2) */ RCHECK(WRITE_VALUE(li->li_opbase, 1)); /* Write standard op length array. */ RCHECK(WRITE_BLOCK(oplen, sizeof(oplen) / sizeof(oplen[0]))); /* Write the list of include directories. */ for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++) RCHECK(WRITE_STRING(li->li_incdirs[i])); RCHECK(WRITE_VALUE(0, 1)); /* Write the list of filenames. */ STAILQ_FOREACH(lf, &li->li_lflist, lf_next) { RCHECK(WRITE_STRING(lf->lf_fname)); RCHECK(WRITE_ULEB128(lf->lf_dirndx)); RCHECK(WRITE_ULEB128(lf->lf_mtime)); RCHECK(WRITE_ULEB128(lf->lf_size)); } RCHECK(WRITE_VALUE(0, 1)); /* Fill in the header length. */ li->li_hdrlen = ds->ds_size - offset - 4; dbg->write(ds->ds_data, &offset, li->li_hdrlen, 4); /* Generate the line number program. */ RCHECK(_dwarf_lineno_gen_program(dbg, ds, drs, error)); /* Fill in the length of this line info. */ li->li_length = ds->ds_size - 4; offset = 0; dbg->write(ds->ds_data, &offset, li->li_length, 4); /* Notify the creation of .debug_line ELF section. */ RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); /* Finalize relocation section for .debug_line. */ RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); return (DW_DLE_NONE); gen_fail: _dwarf_reloc_section_free(dbg, &drs); gen_fail1: _dwarf_section_free(dbg, &ds); return (ret); } void _dwarf_lineno_pro_cleanup(Dwarf_P_Debug dbg) { Dwarf_LineInfo li; Dwarf_LineFile lf, tlf; Dwarf_Line ln, tln; int i; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); if (dbg->dbgp_lineinfo == NULL) return; li = dbg->dbgp_lineinfo; STAILQ_FOREACH_SAFE(lf, &li->li_lflist, lf_next, tlf) { STAILQ_REMOVE(&li->li_lflist, lf, _Dwarf_LineFile, lf_next); if (lf->lf_fname) free(lf->lf_fname); free(lf); } STAILQ_FOREACH_SAFE(ln, &li->li_lnlist, ln_next, tln) { STAILQ_REMOVE(&li->li_lnlist, ln, _Dwarf_Line, ln_next); free(ln); } if (li->li_incdirs) { for (i = 0; (Dwarf_Unsigned) i < li->li_inclen; i++) free(li->li_incdirs[i]); free(li->li_incdirs); } free(li); dbg->dbgp_lineinfo = NULL; } diff --git a/libdwarf/libdwarf_loc.c b/libdwarf/libdwarf_loc.c index ea366fb0768e..c2d3f5cc6662 100644 --- a/libdwarf/libdwarf_loc.c +++ b/libdwarf/libdwarf_loc.c @@ -1,641 +1,701 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * Copyright (c) 2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_loc.c 2070 2011-10-27 03:05:32Z jkoshy $"); +ELFTC_VCSID("$Id: libdwarf_loc.c 3070 2014-06-23 03:08:33Z kaiwang27 $"); /* * Given an array of bytes of length 'len' representing a * DWARF expression, compute the number of operations based * on there being one byte describing the operation and * zero or more bytes of operands as defined in the standard * for each operation type. Also, if lbuf is non-null, store * the opcode and oprand in it. */ static int _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size, - uint8_t *p, int len) + uint8_t offset_size, uint8_t version, uint8_t *p, int len) { int count; uint64_t operand1; uint64_t operand2; - uint8_t *ps, *pe; + uint8_t *ps, *pe, s; count = 0; ps = p; pe = p + len; /* * Process each byte. If an error occurs, then the * count will be set to -1. */ while (p < pe) { operand1 = 0; operand2 = 0; if (lbuf != NULL) { lbuf->ld_s[count].lr_atom = *p; lbuf->ld_s[count].lr_offset = p - ps; } switch (*p++) { /* Operations with no operands. */ case DW_OP_deref: case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: case DW_OP_dup: case DW_OP_drop: case DW_OP_over: case DW_OP_swap: case DW_OP_rot: case DW_OP_xderef: case DW_OP_abs: case DW_OP_and: case DW_OP_div: case DW_OP_minus: case DW_OP_mod: case DW_OP_mul: case DW_OP_neg: case DW_OP_not: case DW_OP_or: case DW_OP_plus: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: case DW_OP_le: case DW_OP_lt: case DW_OP_ne: case DW_OP_nop: + case DW_OP_push_object_address: case DW_OP_form_tls_address: case DW_OP_call_frame_cfa: case DW_OP_stack_value: case DW_OP_GNU_push_tls_address: + case DW_OP_GNU_uninit: break; /* Operations with 1-byte operands. */ case DW_OP_const1u: - case DW_OP_const1s: case DW_OP_pick: case DW_OP_deref_size: case DW_OP_xderef_size: operand1 = *p++; break; + case DW_OP_const1s: + operand1 = (int8_t) *p++; + break; + /* Operations with 2-byte operands. */ case DW_OP_call2: case DW_OP_const2u: - case DW_OP_const2s: case DW_OP_bra: case DW_OP_skip: operand1 = dbg->decode(&p, 2); break; + case DW_OP_const2s: + operand1 = (int16_t) dbg->decode(&p, 2); + break; + /* Operations with 4-byte operands. */ case DW_OP_call4: case DW_OP_const4u: - case DW_OP_const4s: + case DW_OP_GNU_parameter_ref: operand1 = dbg->decode(&p, 4); break; + case DW_OP_const4s: + operand1 = (int32_t) dbg->decode(&p, 4); + break; + /* Operations with 8-byte operands. */ case DW_OP_const8u: case DW_OP_const8s: operand1 = dbg->decode(&p, 8); break; /* Operations with an unsigned LEB128 operand. */ case DW_OP_constu: case DW_OP_plus_uconst: case DW_OP_regx: case DW_OP_piece: + case DW_OP_GNU_deref_type: + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: operand1 = _dwarf_decode_uleb128(&p); break; /* Operations with a signed LEB128 operand. */ case DW_OP_consts: case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: case DW_OP_fbreg: operand1 = _dwarf_decode_sleb128(&p); break; /* * Oeration with two unsigned LEB128 operands. */ case DW_OP_bit_piece: + case DW_OP_GNU_regval_type: operand1 = _dwarf_decode_uleb128(&p); operand2 = _dwarf_decode_uleb128(&p); break; /* * Operations with an unsigned LEB128 operand * followed by a signed LEB128 operand. */ case DW_OP_bregx: operand1 = _dwarf_decode_uleb128(&p); operand2 = _dwarf_decode_sleb128(&p); break; /* * Operation with an unsigned LEB128 operand - * followed by a block. Store a pointer to the - * block in the operand2. + * representing the size of a block, followed + * by the block content. + * + * Store the size of the block in the operand1 + * and a pointer to the block in the operand2. */ case DW_OP_implicit_value: + case DW_OP_GNU_entry_value: operand1 = _dwarf_decode_uleb128(&p); operand2 = (Dwarf_Unsigned) (uintptr_t) p; p += operand1; break; /* Target address size operand. */ case DW_OP_addr: + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: operand1 = dbg->decode(&p, pointer_size); break; + /* Offset size operand. */ + case DW_OP_call_ref: + operand1 = dbg->decode(&p, offset_size); + break; + /* - * XXX Opcode DW_OP_call_ref has an operand with size - * "dwarf_size". Here we use dbg->dbg_offset_size - * as "dwarf_size" to be compatible with SGI libdwarf. - * However note that dbg->dbg_offset_size is just - * a "guess" value so the parsing result of - * DW_OP_call_ref might not be correct at all. XXX + * The first byte is address byte length, followed by + * the address value. If the length is 0, the address + * size is the same as target pointer size. */ - case DW_OP_call_ref: - operand1 = dbg->decode(&p, dbg->dbg_offset_size); + case DW_OP_GNU_encoded_addr: + s = *p++; + if (s == 0) + s = pointer_size; + operand1 = dbg->decode(&p, s); + break; + + /* + * Operand1: DIE offset (size depending on DWARF version) + * DWARF2: pointer size + * DWARF{3,4}: offset size + * + * Operand2: SLEB128 + */ + case DW_OP_GNU_implicit_pointer: + if (version == 2) + operand1 = dbg->decode(&p, pointer_size); + else + operand1 = dbg->decode(&p, offset_size); + operand2 = _dwarf_decode_sleb128(&p); + break; + + /* + * Operand1: DIE offset (ULEB128) + * Operand2: pointer to a block. The block's first byte + * is its size. + */ + case DW_OP_GNU_const_type: + operand1 = _dwarf_decode_uleb128(&p); + operand2 = (Dwarf_Unsigned) (uintptr_t) p; + s = *p++; + p += s; break; /* All other operations cause an error. */ default: count = -1; - break; + goto done; } if (lbuf != NULL) { lbuf->ld_s[count].lr_number = operand1; lbuf->ld_s[count].lr_number2 = operand2; } count++; } +done: return (count); } int _dwarf_loc_expr_add_atom(Dwarf_Debug dbg, uint8_t *out, uint8_t *end, Dwarf_Small atom, Dwarf_Unsigned operand1, Dwarf_Unsigned operand2, int *length, Dwarf_Error *error) { uint8_t buf[64]; uint8_t *p, *pe; uint64_t offset; int len; if (out != NULL && end != NULL) { p = out; pe = end; } else { p = out = buf; pe = &buf[sizeof(buf)]; } switch (atom) { /* Operations with no operands. */ case DW_OP_deref: case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: case DW_OP_dup: case DW_OP_drop: case DW_OP_over: case DW_OP_swap: case DW_OP_rot: case DW_OP_xderef: case DW_OP_abs: case DW_OP_and: case DW_OP_div: case DW_OP_minus: case DW_OP_mod: case DW_OP_mul: case DW_OP_neg: case DW_OP_not: case DW_OP_or: case DW_OP_plus: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: case DW_OP_le: case DW_OP_lt: case DW_OP_ne: case DW_OP_nop: case DW_OP_GNU_push_tls_address: *p++ = atom; break; /* Operations with 1-byte operands. */ case DW_OP_const1u: case DW_OP_const1s: case DW_OP_pick: case DW_OP_deref_size: case DW_OP_xderef_size: *p++ = atom; *p++ = (uint8_t) operand1; break; /* Operations with 2-byte operands. */ case DW_OP_const2u: case DW_OP_const2s: case DW_OP_bra: case DW_OP_skip: *p++ = atom; offset = 0; dbg->write(p, &offset, operand1, 2); p += 2; break; /* Operations with 4-byte operands. */ case DW_OP_const4u: case DW_OP_const4s: *p++ = atom; offset = 0; dbg->write(p, &offset, operand1, 4); p += 4; break; /* Operations with 8-byte operands. */ case DW_OP_const8u: case DW_OP_const8s: *p++ = atom; offset = 0; dbg->write(p, &offset, operand1, 8); p += 8; break; /* Operations with an unsigned LEB128 operand. */ case DW_OP_constu: case DW_OP_plus_uconst: case DW_OP_regx: case DW_OP_piece: *p++ = atom; len = _dwarf_write_uleb128(p, pe, operand1); assert(len > 0); p += len; break; /* Operations with a signed LEB128 operand. */ case DW_OP_consts: case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: case DW_OP_fbreg: *p++ = atom; len = _dwarf_write_sleb128(p, pe, operand1); assert(len > 0); p += len; break; /* * Operations with an unsigned LEB128 operand * followed by a signed LEB128 operand. */ case DW_OP_bregx: *p++ = atom; len = _dwarf_write_uleb128(p, pe, operand1); assert(len > 0); p += len; len = _dwarf_write_sleb128(p, pe, operand2); assert(len > 0); p += len; break; /* Target address size operand. */ case DW_OP_addr: *p++ = atom; offset = 0; dbg->write(p, &offset, operand1, dbg->dbg_pointer_size); p += dbg->dbg_pointer_size; break; /* All other operations cause an error. */ default: DWARF_SET_ERROR(dbg, error, DW_DLE_LOC_EXPR_BAD); return (DW_DLE_LOC_EXPR_BAD); } if (length) *length = p - out; return (DW_DLE_NONE); } int _dwarf_loc_fill_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *llbuf, uint8_t *in, - uint64_t in_len, uint8_t pointer_size, Dwarf_Error *error) + uint64_t in_len, uint8_t pointer_size, uint8_t offset_size, + uint8_t version, Dwarf_Error *error) { int num; assert(llbuf != NULL); assert(in != NULL); assert(in_len > 0); /* Compute the number of locations. */ - if ((num = _dwarf_loc_fill_loc(dbg, NULL, pointer_size, in, in_len)) < - 0) { + if ((num = _dwarf_loc_fill_loc(dbg, NULL, pointer_size, offset_size, + version, in, in_len)) < 0) { DWARF_SET_ERROR(dbg, error, DW_DLE_LOC_EXPR_BAD); return (DW_DLE_LOC_EXPR_BAD); } llbuf->ld_cents = num; if (num <= 0) return (DW_DLE_NONE); if ((llbuf->ld_s = calloc(num, sizeof(Dwarf_Loc))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } - (void) _dwarf_loc_fill_loc(dbg, llbuf, pointer_size, in, in_len); + (void) _dwarf_loc_fill_loc(dbg, llbuf, pointer_size, offset_size, + version, in, in_len); return (DW_DLE_NONE); } int _dwarf_loc_fill_locexpr(Dwarf_Debug dbg, Dwarf_Locdesc **ret_llbuf, uint8_t *in, - uint64_t in_len, uint8_t pointer_size, Dwarf_Error *error) + uint64_t in_len, uint8_t pointer_size, uint8_t offset_size, + uint8_t version, Dwarf_Error *error) { Dwarf_Locdesc *llbuf; int ret; if ((llbuf = malloc(sizeof(Dwarf_Locdesc))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } llbuf->ld_lopc = 0; llbuf->ld_hipc = ~0ULL; llbuf->ld_s = NULL; ret = _dwarf_loc_fill_locdesc(dbg, llbuf, in, in_len, pointer_size, - error); + offset_size, version, error); if (ret != DW_DLE_NONE) { free(llbuf); return (ret); } *ret_llbuf = llbuf; return (ret); } int _dwarf_loc_add(Dwarf_Die die, Dwarf_Attribute at, Dwarf_Error *error) { Dwarf_Debug dbg; Dwarf_CU cu; int ret; assert(at->at_ld == NULL); assert(at->u[1].u8p != NULL); assert(at->u[0].u64 > 0); cu = die->die_cu; assert(cu != NULL); dbg = cu->cu_dbg; assert(dbg != NULL); ret = _dwarf_loc_fill_locexpr(dbg, &at->at_ld, at->u[1].u8p, - at->u[0].u64, cu->cu_pointer_size, error); + at->u[0].u64, cu->cu_pointer_size, cu->cu_length_size == 4 ? 4 : 8, + cu->cu_version, error); return (ret); } diff --git a/libdwarf/libdwarf_loclist.c b/libdwarf/libdwarf_loclist.c index 8b599868d00d..bb3e39f6c899 100644 --- a/libdwarf/libdwarf_loclist.c +++ b/libdwarf/libdwarf_loclist.c @@ -1,224 +1,165 @@ /*- * Copyright (c) 2009,2011 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_loclist.c 2972 2013-12-23 06:46:04Z kaiwang27 $"); +ELFTC_VCSID("$Id: libdwarf_loclist.c 3061 2014-06-02 00:42:41Z kaiwang27 $"); static int _dwarf_loclist_add_locdesc(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Section *ds, - uint64_t *off, Dwarf_Locdesc **ld, uint64_t *ldlen, + Dwarf_Unsigned *off, Dwarf_Locdesc **ld, Dwarf_Signed *ldlen, Dwarf_Unsigned *total_len, Dwarf_Error *error) { uint64_t start, end; int i, len, ret; if (total_len != NULL) *total_len = 0; for (i = 0; *off < ds->ds_size; i++) { start = dbg->read(ds->ds_data, off, cu->cu_pointer_size); end = dbg->read(ds->ds_data, off, cu->cu_pointer_size); if (ld != NULL) { ld[i]->ld_lopc = start; ld[i]->ld_hipc = end; } if (total_len != NULL) *total_len += 2 * cu->cu_pointer_size; /* Check if it is the end entry. */ if (start == 0 && end ==0) { i++; break; } /* Check if it is base-select entry. */ if ((cu->cu_pointer_size == 4 && start == ~0U) || (cu->cu_pointer_size == 8 && start == ~0ULL)) continue; /* Otherwise it's normal entry. */ len = dbg->read(ds->ds_data, off, 2); if (*off + len > ds->ds_size) { DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); return (DW_DLE_DEBUG_LOC_SECTION_SHORT); } if (total_len != NULL) *total_len += len; if (ld != NULL) { ret = _dwarf_loc_fill_locdesc(dbg, ld[i], ds->ds_data + *off, len, cu->cu_pointer_size, + cu->cu_length_size == 4 ? 4 : 8, cu->cu_version, error); if (ret != DW_DLE_NONE) return (ret); } *off += len; } if (ldlen != NULL) *ldlen = i; return (DW_DLE_NONE); } int _dwarf_loclist_find(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, - Dwarf_Loclist *ret_ll, Dwarf_Error *error) -{ - Dwarf_Loclist ll; - int ret; - - assert(ret_ll != NULL); - ret = DW_DLE_NONE; - - TAILQ_FOREACH(ll, &dbg->dbg_loclist, ll_next) - if (ll->ll_offset == lloff) - break; - - if (ll == NULL) - ret = _dwarf_loclist_add(dbg, cu, lloff, ret_ll, error); - else - *ret_ll = ll; - - return (ret); -} - -int -_dwarf_loclist_add(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, - Dwarf_Loclist *ret_ll, Dwarf_Error *error) + Dwarf_Locdesc ***ret_llbuf, Dwarf_Signed *listlen, + Dwarf_Unsigned *entry_len, Dwarf_Error *error) { + Dwarf_Locdesc **llbuf; Dwarf_Section *ds; - Dwarf_Loclist ll, tll; - uint64_t ldlen; + Dwarf_Signed ldlen; + Dwarf_Unsigned off; int i, ret; - ret = DW_DLE_NONE; - if ((ds = _dwarf_find_section(dbg, ".debug_loc")) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); return (DW_DLE_NO_ENTRY); } - if ((ll = malloc(sizeof(struct _Dwarf_Loclist))) == NULL) { - DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); - return (DW_DLE_MEMORY); + if (lloff >= ds->ds_size) { + DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); + return (DW_DLE_NO_ENTRY); } - ll->ll_offset = lloff; - /* Get the number of locdesc the first round. */ - ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &lloff, NULL, &ldlen, + off = lloff; + ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &off, NULL, &ldlen, NULL, error); if (ret != DW_DLE_NONE) - goto fail_cleanup; + return (ret); + + if (ldlen == 0) + return (DW_DLE_NO_ENTRY); /* * Dwarf_Locdesc list memory is allocated in this way (one more level * of indirect) to make the loclist API be compatible with SGI libdwarf. */ - ll->ll_ldlen = ldlen; - if (ldlen != 0) { - if ((ll->ll_ldlist = calloc(ldlen, sizeof(Dwarf_Locdesc *))) == - NULL) { + if ((llbuf = calloc(ldlen, sizeof(Dwarf_Locdesc *))) == NULL) { + DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); + return (DW_DLE_MEMORY); + } + for (i = 0; i < ldlen; i++) { + if ((llbuf[i] = calloc(1, sizeof(Dwarf_Locdesc))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); ret = DW_DLE_MEMORY; goto fail_cleanup; } - for (i = 0; (uint64_t) i < ldlen; i++) { - if ((ll->ll_ldlist[i] = - calloc(1, sizeof(Dwarf_Locdesc))) == NULL) { - DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); - ret = DW_DLE_MEMORY; - goto fail_cleanup; - } - } - } else - ll->ll_ldlist = NULL; + } - lloff = ll->ll_offset; + off = lloff; /* Fill in locdesc. */ - ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &lloff, ll->ll_ldlist, - NULL, &ll->ll_length, error); + ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &off, llbuf, NULL, + entry_len, error); if (ret != DW_DLE_NONE) goto fail_cleanup; - /* Insert to the queue. Sort by offset. */ - TAILQ_FOREACH(tll, &dbg->dbg_loclist, ll_next) - if (tll->ll_offset > ll->ll_offset) { - TAILQ_INSERT_BEFORE(tll, ll, ll_next); - break; - } - - if (tll == NULL) - TAILQ_INSERT_TAIL(&dbg->dbg_loclist, ll, ll_next); + *ret_llbuf = llbuf; + *listlen = ldlen; - *ret_ll = ll; return (DW_DLE_NONE); fail_cleanup: - _dwarf_loclist_free(ll); - - return (ret); -} - -void -_dwarf_loclist_free(Dwarf_Loclist ll) -{ - int i; - - if (ll == NULL) - return; - - if (ll->ll_ldlist != NULL) { - for (i = 0; i < ll->ll_ldlen; i++) { - if (ll->ll_ldlist[i]->ld_s) - free(ll->ll_ldlist[i]->ld_s); - free(ll->ll_ldlist[i]); + if (llbuf != NULL) { + for (i = 0; i < ldlen; i++) { + if (llbuf[i]->ld_s) + free(llbuf[i]->ld_s); + free(llbuf[i]); } - free(ll->ll_ldlist); + free(llbuf); } - free(ll); -} -void -_dwarf_loclist_cleanup(Dwarf_Debug dbg) -{ - Dwarf_Loclist ll, tll; - - assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); - - TAILQ_FOREACH_SAFE(ll, &dbg->dbg_loclist, ll_next, tll) { - TAILQ_REMOVE(&dbg->dbg_loclist, ll, ll_next); - _dwarf_loclist_free(ll); - } + return (ret); } diff --git a/libdwarf/libdwarf_nametbl.c b/libdwarf/libdwarf_nametbl.c index 158aca34ad43..661b56f1c9c8 100644 --- a/libdwarf/libdwarf_nametbl.c +++ b/libdwarf/libdwarf_nametbl.c @@ -1,253 +1,253 @@ /*- * Copyright (c) 2009,2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_nametbl.c 2070 2011-10-27 03:05:32Z jkoshy $"); +ELFTC_VCSID("$Id: libdwarf_nametbl.c 3029 2014-04-21 23:26:02Z kaiwang27 $"); void _dwarf_nametbl_cleanup(Dwarf_NameSec *nsp) { Dwarf_NameSec ns; Dwarf_NameTbl nt, tnt; Dwarf_NamePair np, tnp; assert(nsp != NULL); if ((ns = *nsp) == NULL) return; STAILQ_FOREACH_SAFE(nt, &ns->ns_ntlist, nt_next, tnt) { STAILQ_FOREACH_SAFE(np, &nt->nt_nplist, np_next, tnp) { STAILQ_REMOVE(&nt->nt_nplist, np, _Dwarf_NamePair, np_next); free(np); } STAILQ_REMOVE(&ns->ns_ntlist, nt, _Dwarf_NameTbl, nt_next); free(nt); } if (ns->ns_array) free(ns->ns_array); free(ns); *nsp = NULL; } int _dwarf_nametbl_init(Dwarf_Debug dbg, Dwarf_NameSec *namesec, Dwarf_Section *ds, Dwarf_Error *error) { Dwarf_CU cu; Dwarf_NameSec ns; Dwarf_NameTbl nt; Dwarf_NamePair np; uint64_t offset, dwarf_size, length, cuoff; char *p; int i, ret; assert(*namesec == NULL); if ((ns = malloc(sizeof(struct _Dwarf_NameSec))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INIT(&ns->ns_ntlist); ns->ns_array = NULL; ns->ns_len = 0; offset = 0; while (offset < ds->ds_size) { /* Allocate a new name table. */ if ((nt = malloc(sizeof(struct _Dwarf_NameTbl))) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } STAILQ_INIT(&nt->nt_nplist); STAILQ_INSERT_TAIL(&ns->ns_ntlist, nt, nt_next); /* Read in the table header. */ length = dbg->read(ds->ds_data, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = dbg->read(ds->ds_data, &offset, 8); } else dwarf_size = 4; nt->nt_length = length; /* FIXME: verify version */ nt->nt_version = dbg->read(ds->ds_data, &offset, 2); nt->nt_cu_offset = dbg->read(ds->ds_data, &offset, dwarf_size); nt->nt_cu_length = dbg->read(ds->ds_data, &offset, dwarf_size); if (!dbg->dbg_info_loaded) { - ret = _dwarf_info_load(dbg, 1, error); + ret = _dwarf_info_load(dbg, 1, 1, error); if (ret != DW_DLE_NONE) goto fail_cleanup; } /* Find the referenced CU. */ STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { if (cu->cu_offset == nt->nt_cu_offset) break; } nt->nt_cu = cu; /* FIXME: Check if NULL here */ /* Add name pairs. */ while (offset < ds->ds_size) { cuoff = dbg->read(ds->ds_data, &offset, dwarf_size); if (cuoff == 0) break; if ((np = malloc(sizeof(struct _Dwarf_NamePair))) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } np->np_nt = nt; np->np_offset = cuoff; p = (char *) ds->ds_data; np->np_name = &p[offset]; while (p[offset++] != '\0') ; STAILQ_INSERT_TAIL(&nt->nt_nplist, np, np_next); ns->ns_len++; } } /* Build array of name pairs from all tables. */ if (ns->ns_len > 0) { if ((ns->ns_array = malloc(sizeof(Dwarf_NamePair) * ns->ns_len)) == NULL) { ret = DW_DLE_MEMORY; DWARF_SET_ERROR(dbg, error, ret); goto fail_cleanup; } i = 0; STAILQ_FOREACH(nt, &ns->ns_ntlist, nt_next) { STAILQ_FOREACH(np, &nt->nt_nplist, np_next) ns->ns_array[i++] = np; } assert((Dwarf_Unsigned)i == ns->ns_len); } *namesec = ns; return (DW_DLE_NONE); fail_cleanup: _dwarf_nametbl_cleanup(&ns); return (ret); } int _dwarf_nametbl_gen(Dwarf_P_Debug dbg, const char *name, Dwarf_NameTbl nt, Dwarf_Error *error) { Dwarf_P_Section ds; Dwarf_Rel_Section drs; Dwarf_NamePair np; uint64_t offset; int ret; assert(dbg != NULL && name != NULL); if (nt == NULL || STAILQ_EMPTY(&nt->nt_nplist)) return (DW_DLE_NONE); nt->nt_length = 0; nt->nt_version = 2; nt->nt_cu = STAILQ_FIRST(&dbg->dbg_cu); assert(nt->nt_cu != NULL); nt->nt_cu_offset = nt->nt_cu->cu_offset; nt->nt_cu_length = nt->nt_cu->cu_length; /* Create name lookup section. */ if ((ret = _dwarf_section_init(dbg, &ds, name, 0, error)) != DW_DLE_NONE) goto gen_fail0; /* Create relocation section for the name lookup section. */ RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error)); /* Write table header. */ RCHECK(WRITE_VALUE(nt->nt_length, 4)); RCHECK(WRITE_VALUE(nt->nt_version, 2)); RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, ds->ds_size, 0, nt->nt_cu_offset, ".debug_info", error)); RCHECK(WRITE_VALUE(nt->nt_cu_length, 4)); /* Write tuples. */ STAILQ_FOREACH(np, &nt->nt_nplist, np_next) { assert(np->np_die != NULL); np->np_offset = np->np_die->die_offset; RCHECK(WRITE_VALUE(np->np_offset, 4)); RCHECK(WRITE_STRING(np->np_name)); } RCHECK(WRITE_VALUE(0, 4)); /* Fill in the length field. */ nt->nt_length = ds->ds_size - 4; offset = 0; dbg->write(ds->ds_data, &offset, nt->nt_length, 4); /* Inform application the creation of name lookup ELF section. */ RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); /* Finalize relocation section for the name lookup section. */ RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); return (DW_DLE_NONE); gen_fail: _dwarf_reloc_section_free(dbg, &drs); gen_fail0: _dwarf_section_free(dbg, &ds); return (ret); } void _dwarf_nametbl_pro_cleanup(Dwarf_NameTbl *ntp) { Dwarf_NameTbl nt; Dwarf_NamePair np, tnp; assert(ntp != NULL); if ((nt = *ntp) == NULL) return; STAILQ_FOREACH_SAFE(np, &nt->nt_nplist, np_next, tnp) { STAILQ_REMOVE(&nt->nt_nplist, np, _Dwarf_NamePair, np_next); if (np->np_name) free(np->np_name); free(np); } free(nt); *ntp = NULL; } diff --git a/libdwarf/libdwarf_sections.c b/libdwarf/libdwarf_sections.c index 3ac30b251e02..24d5db839e49 100644 --- a/libdwarf/libdwarf_sections.c +++ b/libdwarf/libdwarf_sections.c @@ -1,259 +1,280 @@ /*- * Copyright (c) 2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_sections.c 2379 2012-01-05 02:08:20Z jkoshy $"); +ELFTC_VCSID("$Id: libdwarf_sections.c 3041 2014-05-18 15:11:03Z kaiwang27 $"); #define _SECTION_INIT_SIZE 128 int _dwarf_section_init(Dwarf_P_Debug dbg, Dwarf_P_Section *dsp, const char *name, int pseudo, Dwarf_Error *error) { Dwarf_P_Section ds; assert(dbg != NULL && dsp != NULL && name != NULL); if ((ds = calloc(1, sizeof(struct _Dwarf_P_Section))) == NULL) { DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } if ((ds->ds_name = strdup(name)) == NULL) { free(ds); DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } if (!pseudo) { ds->ds_cap = _SECTION_INIT_SIZE; if ((ds->ds_data = malloc((size_t) ds->ds_cap)) == NULL) { free(ds->ds_name); free(ds); DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); return (DW_DLE_MEMORY); } STAILQ_INSERT_TAIL(&dbg->dbgp_seclist, ds, ds_next); dbg->dbgp_seccnt++; } *dsp = ds; return (DW_DLE_NONE); } void _dwarf_section_free(Dwarf_P_Debug dbg, Dwarf_P_Section *dsp) { Dwarf_P_Section ds, tds; assert(dbg != NULL && dsp != NULL); if (*dsp == NULL) return; STAILQ_FOREACH_SAFE(ds, &dbg->dbgp_seclist, ds_next, tds) { if (ds == *dsp) { STAILQ_REMOVE(&dbg->dbgp_seclist, ds, _Dwarf_P_Section, ds_next); dbg->dbgp_seccnt--; break; } } ds = *dsp; if (ds->ds_name) free(ds->ds_name); if (ds->ds_data) free(ds->ds_data); free(ds); *dsp = NULL; } int _dwarf_pro_callback(Dwarf_P_Debug dbg, char *name, int size, Dwarf_Unsigned type, Dwarf_Unsigned flags, Dwarf_Unsigned link, Dwarf_Unsigned info, Dwarf_Unsigned *symndx, int *error) { int e, ret, isymndx; assert(dbg != NULL && name != NULL && symndx != NULL); if (dbg->dbgp_func_b) ret = dbg->dbgp_func_b(name, size, type, flags, link, info, symndx, &e); else { ret = dbg->dbgp_func(name, size, type, flags, link, info, &isymndx, &e); *symndx = isymndx; } if (ret < 0) { if (error) *error = e; } return (ret); } int _dwarf_section_callback(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Unsigned type, Dwarf_Unsigned flags, Dwarf_Unsigned link, Dwarf_Unsigned info, Dwarf_Error *error) { int ret, ndx; ndx = _dwarf_pro_callback(dbg, ds->ds_name, (int) ds->ds_size, type, flags, link, info, &ds->ds_symndx, NULL); if (ndx < 0) { ret = DW_DLE_ELF_SECT_ERR; DWARF_SET_ERROR(dbg, error, ret); return (ret); } ds->ds_ndx = ndx; return (DW_DLE_NONE); } int _dwarf_generate_sections(Dwarf_P_Debug dbg, Dwarf_Error *error) { int ret; /* Produce .debug_info section. */ if ((ret = _dwarf_info_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_abbrev section. */ if ((ret = _dwarf_abbrev_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_line section. */ if ((ret = _dwarf_lineno_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_frame section. */ if ((ret = _dwarf_frame_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_aranges section. */ if ((ret = _dwarf_arange_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_macinfo section. */ if ((ret = _dwarf_macinfo_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_pubnames section. */ if ((ret = _dwarf_nametbl_gen(dbg, ".debug_pubnames", dbg->dbgp_pubs, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_weaknames section. */ if ((ret = _dwarf_nametbl_gen(dbg, ".debug_weaknames", dbg->dbgp_weaks, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_funcnames section. */ if ((ret = _dwarf_nametbl_gen(dbg, ".debug_funcnames", dbg->dbgp_funcs, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_typenames section. */ if ((ret = _dwarf_nametbl_gen(dbg, ".debug_typenames", dbg->dbgp_types, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_varnames section. */ if ((ret = _dwarf_nametbl_gen(dbg, ".debug_varnames", dbg->dbgp_vars, error)) != DW_DLE_NONE) return (ret); /* Produce .debug_str section. */ if ((ret = _dwarf_strtab_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Finally, update and generate all relocation sections. */ if ((ret = _dwarf_reloc_gen(dbg, error)) != DW_DLE_NONE) return (ret); /* Set section/relocation iterator to the first element. */ dbg->dbgp_secpos = STAILQ_FIRST(&dbg->dbgp_seclist); dbg->dbgp_drspos = STAILQ_FIRST(&dbg->dbgp_drslist); return (DW_DLE_NONE); } Dwarf_Section * _dwarf_find_section(Dwarf_Debug dbg, const char *name) { Dwarf_Section *ds; Dwarf_Half i; - assert(name != NULL); + assert(dbg != NULL && name != NULL); for (i = 0; i < dbg->dbg_seccnt; i++) { ds = &dbg->dbg_section[i]; if (ds->ds_name != NULL && !strcmp(ds->ds_name, name)) return (ds); } return (NULL); } +Dwarf_Section * +_dwarf_find_next_types_section(Dwarf_Debug dbg, Dwarf_Section *ds) +{ + + assert(dbg != NULL); + + if (ds == NULL) + return (_dwarf_find_section(dbg, ".debug_types")); + + assert(ds->ds_name != NULL); + + do { + ds++; + if (ds->ds_name != NULL && + !strcmp(ds->ds_name, ".debug_types")) + return (ds); + } while (ds->ds_name != NULL); + + return (NULL); +} + Dwarf_P_Section _dwarf_pro_find_section(Dwarf_P_Debug dbg, const char *name) { Dwarf_P_Section ds; assert(dbg != NULL && name != NULL); STAILQ_FOREACH(ds, &dbg->dbgp_seclist, ds_next) { if (ds->ds_name != NULL && !strcmp(ds->ds_name ,name)) return (ds); } return (NULL); } void _dwarf_section_cleanup(Dwarf_P_Debug dbg) { Dwarf_P_Section ds, tds; assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); STAILQ_FOREACH_SAFE(ds, &dbg->dbgp_seclist, ds_next, tds) { STAILQ_REMOVE(&dbg->dbgp_seclist, ds, _Dwarf_P_Section, ds_next); if (ds->ds_name) free(ds->ds_name); if (ds->ds_data) free(ds->ds_data); free(ds); } dbg->dbgp_seccnt = 0; dbg->dbgp_secpos = 0; } diff --git a/libelf/_libelf.h b/libelf/_libelf.h index fba2f97fd670..d5803a4e44ff 100644 --- a/libelf/_libelf.h +++ b/libelf/_libelf.h @@ -1,225 +1,235 @@ /*- * Copyright (c) 2006,2008-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: _libelf.h 2365 2011-12-29 04:36:44Z jkoshy $ + * $Id: _libelf.h 3011 2014-03-23 03:32:42Z jkoshy $ */ #ifndef __LIBELF_H_ #define __LIBELF_H_ #include #include "_libelf_config.h" #include "_elftc.h" /* * Library-private data structures. */ #define LIBELF_MSG_SIZE 256 struct _libelf_globals { int libelf_arch; unsigned int libelf_byteorder; int libelf_class; int libelf_error; int libelf_fillchar; unsigned int libelf_version; - char libelf_msg[LIBELF_MSG_SIZE]; + unsigned char libelf_msg[LIBELF_MSG_SIZE]; }; extern struct _libelf_globals _libelf; #define LIBELF_PRIVATE(N) (_libelf.libelf_##N) #define LIBELF_ELF_ERROR_MASK 0xFF #define LIBELF_OS_ERROR_SHIFT 8 #define LIBELF_ERROR(E, O) (((E) & LIBELF_ELF_ERROR_MASK) | \ ((O) << LIBELF_OS_ERROR_SHIFT)) #define LIBELF_SET_ERROR(E, O) do { \ LIBELF_PRIVATE(error) = LIBELF_ERROR(ELF_E_##E, (O)); \ } while (0) #define LIBELF_ADJUST_AR_SIZE(S) (((S) + 1U) & ~1U) /* * Flags for library internal use. These use the upper 16 bits of the * `e_flags' field. */ -#define LIBELF_F_API_MASK 0x00FFFF /* Flags defined by the API. */ -#define LIBELF_F_AR_HEADER 0x010000 /* translated header available */ -#define LIBELF_F_AR_VARIANT_SVR4 0x020000 /* BSD style ar(1) archive */ -#define LIBELF_F_DATA_MALLOCED 0x040000 /* whether data was malloc'ed */ -#define LIBELF_F_RAWFILE_MALLOC 0x080000 /* whether e_rawfile was malloc'ed */ -#define LIBELF_F_RAWFILE_MMAP 0x100000 /* whether e_rawfile was mmap'ed */ -#define LIBELF_F_SHDRS_LOADED 0x200000 /* whether all shdrs were read in */ -#define LIBELF_F_SPECIAL_FILE 0x400000 /* non-regular file */ +#define LIBELF_F_API_MASK 0x00FFFFU /* Flags defined by the API. */ +#define LIBELF_F_AR_HEADER 0x010000U /* translated header available */ +#define LIBELF_F_AR_VARIANT_SVR4 0x020000U /* BSD style ar(1) archive */ +#define LIBELF_F_DATA_MALLOCED 0x040000U /* whether data was malloc'ed */ +#define LIBELF_F_RAWFILE_MALLOC 0x080000U /* whether e_rawfile was malloc'ed */ +#define LIBELF_F_RAWFILE_MMAP 0x100000U /* whether e_rawfile was mmap'ed */ +#define LIBELF_F_SHDRS_LOADED 0x200000U /* whether all shdrs were read in */ +#define LIBELF_F_SPECIAL_FILE 0x400000U /* non-regular file */ struct _Elf { int e_activations; /* activation count */ unsigned int e_byteorder; /* ELFDATA* */ int e_class; /* ELFCLASS* */ Elf_Cmd e_cmd; /* ELF_C_* used at creation time */ int e_fd; /* associated file descriptor */ unsigned int e_flags; /* ELF_F_* & LIBELF_F_* flags */ Elf_Kind e_kind; /* ELF_K_* */ Elf *e_parent; /* non-NULL for archive members */ - char *e_rawfile; /* uninterpreted bytes */ + unsigned char *e_rawfile; /* uninterpreted bytes */ size_t e_rawsize; /* size of uninterpreted bytes */ unsigned int e_version; /* file version */ /* * Header information for archive members. See the * LIBELF_F_AR_HEADER flag. */ union { Elf_Arhdr *e_arhdr; /* translated header */ - char *e_rawhdr; /* untranslated header */ + unsigned char *e_rawhdr; /* untranslated header */ } e_hdr; union { struct { /* ar(1) archives */ off_t e_next; /* set by elf_rand()/elf_next() */ int e_nchildren; - char *e_rawstrtab; /* file name strings */ + unsigned char *e_rawstrtab; /* file name strings */ size_t e_rawstrtabsz; - char *e_rawsymtab; /* symbol table */ + unsigned char *e_rawsymtab; /* symbol table */ size_t e_rawsymtabsz; Elf_Arsym *e_symtab; size_t e_symtabsz; } e_ar; struct { /* regular ELF files */ union { Elf32_Ehdr *e_ehdr32; Elf64_Ehdr *e_ehdr64; } e_ehdr; union { Elf32_Phdr *e_phdr32; Elf64_Phdr *e_phdr64; } e_phdr; STAILQ_HEAD(, _Elf_Scn) e_scn; /* section list */ size_t e_nphdr; /* number of Phdr entries */ size_t e_nscn; /* number of sections */ size_t e_strndx; /* string table section index */ } e_elf; } e_u; }; /* * The internal descriptor wrapping the "Elf_Data" type. */ struct _Libelf_Data { Elf_Data d_data; /* The exported descriptor. */ Elf_Scn *d_scn; /* The containing section */ unsigned int d_flags; STAILQ_ENTRY(_Libelf_Data) d_next; }; struct _Elf_Scn { union { Elf32_Shdr s_shdr32; Elf64_Shdr s_shdr64; } s_shdr; STAILQ_HEAD(, _Libelf_Data) s_data; /* translated data */ STAILQ_HEAD(, _Libelf_Data) s_rawdata; /* raw data */ STAILQ_ENTRY(_Elf_Scn) s_next; struct _Elf *s_elf; /* parent ELF descriptor */ unsigned int s_flags; /* flags for the section as a whole */ size_t s_ndx; /* index# for this section */ uint64_t s_offset; /* managed by elf_update() */ uint64_t s_rawoff; /* original offset in the file */ uint64_t s_size; /* managed by elf_update() */ }; enum { ELF_TOFILE, ELF_TOMEMORY }; -#define LIBELF_COPY_U32(DST,SRC,NAME) do { \ - if ((SRC)->NAME > UINT_MAX) { \ - LIBELF_SET_ERROR(RANGE, 0); \ - return (0); \ - } \ - (DST)->NAME = (SRC)->NAME; \ + +/* + * The LIBELF_COPY macros are used to copy fields from a GElf_* + * structure to their 32-bit counterparts, while checking for out of + * range values. + * + * - LIBELF_COPY_U32 :: copy an unsigned 32 bit field. + * - LIBELF_COPY_S32 :: copy a signed 32 bit field. + */ + +#define LIBELF_COPY_U32(DST, SRC, NAME) do { \ + if ((SRC)->NAME > UINT32_MAX) { \ + LIBELF_SET_ERROR(RANGE, 0); \ + return (0); \ + } \ + (DST)->NAME = (SRC)->NAME & 0xFFFFFFFFU; \ } while (0) -#define LIBELF_COPY_S32(DST,SRC,NAME) do { \ - if ((SRC)->NAME > INT_MAX || \ - (SRC)->NAME < INT_MIN) { \ - LIBELF_SET_ERROR(RANGE, 0); \ - return (0); \ - } \ - (DST)->NAME = (SRC)->NAME; \ +#define LIBELF_COPY_S32(DST, SRC, NAME) do { \ + if ((SRC)->NAME > INT32_MAX || \ + (SRC)->NAME < INT32_MIN) { \ + LIBELF_SET_ERROR(RANGE, 0); \ + return (0); \ + } \ + (DST)->NAME = (int32_t) (SRC)->NAME; \ } while (0) /* * Function Prototypes. */ __BEGIN_DECLS struct _Libelf_Data *_libelf_allocate_data(Elf_Scn *_s); Elf *_libelf_allocate_elf(void); Elf_Scn *_libelf_allocate_scn(Elf *_e, size_t _ndx); Elf_Arhdr *_libelf_ar_gethdr(Elf *_e); Elf *_libelf_ar_open(Elf *_e, int _reporterror); Elf *_libelf_ar_open_member(int _fd, Elf_Cmd _c, Elf *_ar); -int _libelf_ar_get_member(char *_s, size_t _sz, int _base, size_t *_ret); Elf_Arsym *_libelf_ar_process_bsd_symtab(Elf *_ar, size_t *_dst); Elf_Arsym *_libelf_ar_process_svr4_symtab(Elf *_ar, size_t *_dst); -unsigned long _libelf_checksum(Elf *_e, int _elfclass); +long _libelf_checksum(Elf *_e, int _elfclass); void *_libelf_ehdr(Elf *_e, int _elfclass, int _allocate); -int _libelf_falign(Elf_Type _t, int _elfclass); +unsigned int _libelf_falign(Elf_Type _t, int _elfclass); size_t _libelf_fsize(Elf_Type _t, int _elfclass, unsigned int _version, size_t count); int (*_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass)) - (char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap); + (unsigned char *_dst, size_t dsz, unsigned char *_src, + size_t _cnt, int _byteswap); void *_libelf_getphdr(Elf *_e, int _elfclass); void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass); void _libelf_init_elf(Elf *_e, Elf_Kind _kind); int _libelf_load_section_headers(Elf *e, void *ehdr); -int _libelf_malign(Elf_Type _t, int _elfclass); -Elf *_libelf_memory(char *_image, size_t _sz, int _reporterror); +unsigned int _libelf_malign(Elf_Type _t, int _elfclass); +Elf *_libelf_memory(unsigned char *_image, size_t _sz, int _reporterror); size_t _libelf_msize(Elf_Type _t, int _elfclass, unsigned int _version); void *_libelf_newphdr(Elf *_e, int _elfclass, size_t _count); Elf *_libelf_open_object(int _fd, Elf_Cmd _c, int _reporterror); struct _Libelf_Data *_libelf_release_data(struct _Libelf_Data *_d); Elf *_libelf_release_elf(Elf *_e); Elf_Scn *_libelf_release_scn(Elf_Scn *_s); int _libelf_setphnum(Elf *_e, void *_eh, int _elfclass, size_t _phnum); int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum); int _libelf_setshstrndx(Elf *_e, void *_eh, int _elfclass, size_t _shstrndx); Elf_Data *_libelf_xlate(Elf_Data *_d, const Elf_Data *_s, unsigned int _encoding, int _elfclass, int _direction); int _libelf_xlate_shtype(uint32_t _sht); __END_DECLS #endif /* __LIBELF_H_ */ diff --git a/libelf/_libelf_ar.h b/libelf/_libelf_ar.h index d6b15a7501ef..45a7e16be863 100644 --- a/libelf/_libelf_ar.h +++ b/libelf/_libelf_ar.h @@ -1,56 +1,57 @@ /*- * Copyright (c) 2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: _libelf_ar.h 2032 2011-10-23 09:07:00Z jkoshy $ + * $Id: _libelf_ar.h 3013 2014-03-23 06:16:59Z jkoshy $ */ #ifndef __LIBELF_AR_H_ #define __LIBELF_AR_H_ /* * Prototypes and declarations needed by libelf's ar(1) archive * handling code. */ #include #define LIBELF_AR_BSD_EXTENDED_NAME_PREFIX "#1/" #define LIBELF_AR_BSD_SYMTAB_NAME "__.SYMDEF" #define LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE \ (sizeof(LIBELF_AR_BSD_EXTENDED_NAME_PREFIX) - 1) #define IS_EXTENDED_BSD_NAME(NAME) \ - (strncmp((NAME), LIBELF_AR_BSD_EXTENDED_NAME_PREFIX, \ + (strncmp((const char *) (NAME), \ + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX, \ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE) == 0) -char *_libelf_ar_get_string(const char *_buf, size_t _sz, int _rawname, - int _svr4names); +unsigned char *_libelf_ar_get_string(const char *_buf, size_t _sz, + unsigned int _rawname, int _svr4names); char *_libelf_ar_get_raw_name(const struct ar_hdr *_arh); char *_libelf_ar_get_translated_name(const struct ar_hdr *_arh, Elf *_ar); -int _libelf_ar_get_number(const char *_buf, size_t _sz, int _base, - size_t *_ret); +int _libelf_ar_get_number(const char *_buf, size_t _sz, + unsigned int _base, size_t *_ret); #endif /* __LIBELF_AR_H_ */ diff --git a/libelf/elf.3 b/libelf/elf.3 index 462e72854177..97677eb205d6 100644 --- a/libelf/elf.3 +++ b/libelf/elf.3 @@ -1,589 +1,613 @@ .\" Copyright (c) 2006-2008,2011 Joseph Koshy. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" This software is provided by Joseph Koshy ``as is'' and .\" any express or implied warranties, including, but not limited to, the .\" implied warranties of merchantability and fitness for a particular purpose .\" are disclaimed. in no event shall Joseph Koshy be liable .\" for any direct, indirect, incidental, special, exemplary, or consequential .\" damages (including, but not limited to, procurement of substitute goods .\" or services; loss of use, data, or profits; or business interruption) .\" however caused and on any theory of liability, whether in contract, strict .\" liability, or tort (including negligence or otherwise) arising in any way .\" out of the use of this software, even if advised of the possibility of .\" such damage. .\" -.\" $Id: elf.3 2885 2013-01-11 02:11:28Z jkoshy $ +.\" $Id: elf.3 3082 2014-07-28 09:13:33Z jkoshy $ .\" -.Dd August 14, 2011 +.Dd July 28, 2014 .Os .Dt ELF 3 .Sh NAME .Nm elf .Nd API for manipulating ELF objects .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Sh DESCRIPTION The .Lb libelf provides functions that allow an application to read and manipulate ELF object files, and to read .Xr ar 1 archives. The library allows the manipulation of ELF objects in a byte ordering and word-size independent way, allowing an application to read and create ELF objects for 32 and 64 bit architectures and for little- and big-endian machines. The library is capable of processing ELF objects that use extended section numbering. .Pp This manual page serves to provide an overview of the functionality in the ELF library. Further information may found in the manual pages for individual .Xr ELF 3 functions that comprise the library. .Ss ELF Concepts As described in .Xr elf 5 , ELF files contain several data structures that are laid out in a specific way. ELF files begin with an .Dq Executable Header , and may contain an optional .Dq Program Header Table , and optional data in the form of ELF .Dq sections . A .Dq Section Header Table describes the content of the data in these sections. .Pp ELF objects have an associated .Dq "ELF class" which denotes the natural machine word size for the architecture the object is associated with. Objects for 32 bit architectures have an ELF class of .Dv ELFCLASS32 . Objects for 64 bit architectures have an ELF class of .Dv ELFCLASS64 . .Pp ELF objects also have an associated .Dq endianness which denotes the endianness of the machine architecture associated with the object. This may be .Dv ELFDATA2LSB for little-endian architectures and .Dv ELFDATA2MSB for big-endian architectures. .Pp ELF objects are also associated with an API version number. This version number determines the layout of the individual components of an ELF file and the semantics associated with these. .Ss Data Representation And Translation The .Xr ELF 3 library distinguishes between .Dq native representations of ELF data structures and their .Dq file representations. .Pp An application would work with ELF data in its .Dq native representation, i.e., using the native byteorder and alignment mandated by the processor the application is running on. The .Dq file representation of the same data could use a different byte ordering and follow different constraints on object alignment than these native constraints. .Pp Accordingly, the .Xr ELF 3 library offers translation facilities .Xr ( elf32_xlatetof 3 , .Xr elf32_xlatetom 3 , .Xr elf64_xlatetof 3 and .Xr elf64_xlatetom 3 ) to and from these representations and also provides higher-level APIs that retrieve and store data from the ELF object in a transparent manner. .Ss Library Working Version Conceptually, there are three version numbers associated with an application using the ELF library to manipulate ELF objects: .Bl -bullet -compact -offset indent .It The ELF version that the application was compiled against. This version determines the ABI expected by the application. .It The ELF version of the ELF object being manipulated by the application through the ELF library. .It The ELF version (or set of versions) supported by the ELF library itself. .El .Pp In order to facilitate working with ELF objects of differing versions, the ELF library requires the application to call the .Fn elf_version function before invoking many of its operations, in order to inform the library of the application's desired working version. .Pp In the current implementation, all three versions have to be .Dv EV_CURRENT . .Ss Namespace use The ELF library uses the following prefixes: .Bl -tag -width "ELF_F_*" .It Dv elf_ Used for class-independent functions. .It Dv elf32_ Used for functions working with 32 bit ELF objects. .It Dv elf64_ Used for functions working with 64 bit ELF objects. .It Dv Elf_ Used for class-independent data types. .It Dv ELF_C_ Used for command values used in a few functions. These symbols are defined as members of the .Vt Dv Elf_Cmd enumeration. .It Dv ELF_E_ Used for error numbers. .It Dv ELF_F_ Used for flags. .It Dv ELF_K_ These constants define the kind of file associated with an ELF descriptor. See .Xr elf_kind 3 . The symbols are defined by the .Vt Elf_Kind enumeration. .It Dv ELF_T_ These values are defined by the .Vt Elf_Type enumeration, and denote the types of ELF data structures that can be present in an ELF object. .El .Pp In addition, the library uses symbols with prefixes .Dv _ELF and .Dv _libelf for its internal use. .Ss Descriptors Applications communicate with the library using descriptors. These are: .Bl -tag -width ".Vt Elf_Data" .It Vt Elf An .Vt Elf descriptor represents an ELF object or an .Xr ar 1 archive. It is allocated using one of the .Fn elf_begin or .Fn elf_memory functions. An .Vt Elf descriptor can be used to read and write data to an ELF file. An .Vt Elf descriptor can be associated with zero or more .Vt Elf_Scn section descriptors. .Pp Given an ELF descriptor, the application may retrieve the ELF object's class-dependent .Dq "Executable Header" structures using the .Fn elf32_getehdr or .Fn elf64_getehdr functions. A new Ehdr structure may be allocated using the .Fn elf64_newehdr or .Fn elf64_newehdr functions. .Pp The .Dq "Program Header Table" associated with an ELF descriptor may be allocated using the .Fn elf32_getphdr or .Fn elf64_getphdr functions. A new program header table may be allocated or an existing table resized using the .Fn elf32_newphdr or .Fn elf64_newphdr functions. .Pp The .Vt Elf structure is opaque and has no members visible to the application. .\" TODO describe the Elf_Arhdr and Elf_Arsym structures. .It Vt Elf_Data An .Vt Elf_Data data structure describes an individual chunk of a ELF file as represented in memory. It has the following application-visible members: .Bl -tag -width ".Vt unsigned int d_version" -compact .It Vt "uint64_t d_align" The in-file alignment of the data buffer within its containing ELF section. This value must be non-zero and a power of two. .It Vt "void *d_buf" A pointer to data in memory. .It Vt "uint64_t d_off" The offset within the containing section where this descriptor's data would be placed. This field will be computed by the library unless the application requests full control of the ELF object's layout. .It Vt "uint64_t d_size" The number of bytes of data in this descriptor. .It Vt "Elf_Type d_type" The ELF type (see below) of the data in this descriptor. .It Vt "unsigned int d_version" The operating version for the data in this buffer. .El .Pp .Vt Elf_Data descriptors are usually associated with .Vt Elf_Scn descriptors. Existing data descriptors associated with an ELF section may be structures are retrieved using the .Fn elf_getdata and .Fn elf_rawdata functions. The .Fn elf_newdata function may be used to attach new data descriptors to an ELF section. .It Vt Elf_Scn .Vt Elf_Scn descriptors represent a section in an ELF object. .Pp They are retrieved using the .Fn elf_getscn function. An application may iterate through the existing sections of an ELF object using the .Fn elf_nextscn function. New sections may be allocated using the .Fn elf_newscn function. .Pp The .Vt Elf_Scn descriptor is opaque and contains no application modifiable fields. .El .Ss Supported Elf Types The following ELF datatypes are supported by the library. .Pp .Bl -tag -width ".Dv ELF_T_SYMINFO" -compact .It Dv ELF_T_ADDR Machine addresses. .It Dv ELF_T_BYTE Byte data. The library will not attempt to translate byte data. .It Dv ELF_T_CAP Software and hardware capability records. .It Dv ELF_T_DYN Records used in a section of type .Dv SHT_DYNAMIC . .It Dv ELF_T_EHDR ELF executable header. .It Dv ELF_T_GNUHASH GNU-style hash tables. .It Dv ELF_T_HALF 16-bit unsigned words. .It Dv ELF_T_LWORD 64 bit unsigned words. .It Dv ELF_T_MOVE ELF Move records. .\".It Dv ELF_T_MOVEP .\" As yet unsupported. .It Dv ELF_T_NOTE ELF Note structures. .It Dv ELF_T_OFF File offsets. .It Dv ELF_T_PHDR ELF program header table entries. .It Dv ELF_T_REL ELF relocation entries. .It Dv ELF_T_RELA ELF relocation entries with addends. .It Dv ELF_T_SHDR ELF section header entries. .It Dv ELF_T_SWORD Signed 32-bit words. .It Dv ELF_T_SXWORD Signed 64-bit words. .It Dv ELF_T_SYMINFO ELF symbol information. .It Dv ELF_T_SYM ELF symbol table entries. .It Dv ELF_T_VDEF Symbol version definition records. .It Dv ELF_T_VNEED Symbol version requirement records. .It Dv ELF_T_WORD Unsigned 32-bit words. .It Dv ELF_T_XWORD Unsigned 64-bit words. .El .Pp The symbol .Dv ELF_T_NUM denotes the number of Elf types known to the library. .Pp The following table shows the mapping between ELF section types defined in .Xr elf 5 and the types supported by the library. .Bl -column ".Dv SHT_PREINIT_ARRAY" ".Dv ELF_T_SYMINFO" .It Em Section Type Ta Em "Library Type" Ta Em Description .It Dv SHT_DYNAMIC Ta Dv ELF_T_DYN Ta Xo .Sq .dynamic section entries. .Xc .It Dv SHT_DYNSYM Ta Dv ELF_T_SYM Ta Symbols for dynamic linking. .It Dv SHT_FINI_ARRAY Ta Dv ELF_T_ADDR Ta Termination function pointers. +.It Dv SHT_GNU_HASH Ta Dv ELF_T_GNUHASH Ta GNU hash sections. +.It Dv SHT_GNU_LIBLIST Ta Dv ELF_T_WORD Ta List of libraries to be pre-linked. +.It Dv SHT_GNU_verdef Ta Dv ELF_T_VDEF Ta Symbol version definitions. +.It Dv SHT_GNU_verneed Ta Dv ELF_T_VNEED Ta Symbol versioning requirements. +.It Dv SHT_GNU_versym Ta Dv ELF_T_HALF Ta Version symbols. .It Dv SHT_GROUP Ta Dv ELF_T_WORD Ta Section group marker. .It Dv SHT_HASH Ta Dv ELF_T_HASH Ta Symbol hashes. .It Dv SHT_INIT_ARRAY Ta Dv ELF_T_ADDR Ta Initialization function pointers. .It Dv SHT_NOBITS Ta Dv ELF_T_BYTE Ta Xo Empty sections. See .Xr elf 5 . .Xc .It Dv SHT_NOTE Ta Dv ELF_T_NOTE Ta ELF note records. .It Dv SHT_PREINIT_ARRAY Ta Dv ELF_T_ADDR Ta Pre-initialization function pointers. .It Dv SHT_PROGBITS Ta Dv ELF_T_BYTE Ta Machine code. .It Dv SHT_REL Ta Dv ELF_T_REL Ta ELF relocation records. .It Dv SHT_RELA Ta Dv ELF_T_RELA Ta Relocation records with addends. .It Dv SHT_STRTAB Ta Dv ELF_T_BYTE Ta String tables. .It Dv SHT_SYMTAB Ta Dv ELF_T_SYM Ta Symbol tables. .It Dv SHT_SYMTAB_SHNDX Ta Dv ELF_T_WORD Ta Used with extended section numbering. -.It Dv SHT_GNU_verdef Ta Dv ELF_T_VDEF Ta Symbol version definitions. -.It Dv SHT_GNU_verneed Ta Dv ELF_T_VNEED Ta Symbol versioning requirements. -.It Dv SHT_GNU_versym Ta Dv ELF_T_HALF Ta Version symbols. +.It Dv SHT_SUNW_dof Ta Dv ELF_T_BYTE Ta Xo +Used by +.Xr dtrace 1 . +.Xc .It Dv SHT_SUNW_move Ta Dv ELF_T_MOVE Ta ELF move records. .It Dv SHT_SUNW_syminfo Ta Dv ELF_T_SYMINFO Ta Additional symbol flags. +.It Dv SHT_SUNW_verdef Ta Dv ELF_T_VDEF Ta Xo +Same as +.Dv SHT_GNU_verdef . +.Xc +.It Dv SHT_SUNW_verneed Ta Dv ELF_T_VNEED Ta Xo +Same as +.Dv SHT_GNU_verneed . +.Xc +.It Dv SHT_SUNW_versym Ta Dv ELF_T_HALF Ta Xo +Same as +.Dv SHT_GNU_versym . +.Xc .El +.Pp +Section types in the range +.Ns [ Dv SHT_LOOS , +.Dv SHT_HIUSER ] +are otherwise considered to be of type +.Dv ELF_T_BYTE . .TE .Ss Functional Grouping This section contains a brief overview of the available functionality in the ELF library. Each function listed here is described further in its own manual page. .Bl -tag -width indent .It "Archive Access" .Bl -tag -compact .It Fn elf_getarsym Retrieve the archive symbol table. .It Fn elf_getarhdr Retrieve the archive header for an object. .It Fn elf_getbase Retrieve the offset of a member inside an archive. .It Fn elf_next Iterate through an .Xr ar 1 archive. .It Fn elf_rand Random access inside an .Xr ar 1 archive. .El .It "Data Structures" .Bl -tag -compact .It Fn elf_getdata Retrieve translated data for an ELF section. .It Fn elf_getscn Retrieve the section descriptor for a named section. .It Fn elf_ndxscn Retrieve the index for a section. .It Fn elf_newdata Add a new .Vt Elf_Data descriptor to an ELF section. .It Fn elf_newscn Add a new section descriptor to an ELF descriptor. .It Fn elf_nextscn Iterate through the sections in an ELF object. .It Fn elf_rawdata Retrieve untranslated data for an ELF section. .It Fn elf_rawfile Return a pointer to the untranslated file contents for an ELF object. .It Fn elf32_getehdr , Fn elf64_getehdr Retrieve the Executable Header in an ELF object. .It Fn elf32_getphdr , Fn elf64_getphdr Retrieve the Program Header Table in an ELF object. .It Fn elf32_getshdr , Fn elf64_getshdr Retrieve the ELF section header associated with an .Vt Elf_Scn descriptor. .It Fn elf32_newehdr , Fn elf64_newehdr Allocate an Executable Header in an ELF object. .It Fn elf32_newphdr , Fn elf64_newphdr Allocate or resize the Program Header Table in an ELF object. .El .It "Data Translation" .Bl -tag -compact .It Fn elf32_xlatetof , Fn elf64_xlatetof Translate an ELF data structure from its native representation to its file representation. .It Fn elf32_xlatetom , Fn elf64_xlatetom Translate an ELF data structure from its file representation to a native representation. .El .It "Error Reporting" .Bl -tag -compact .It Fn elf_errno Retrieve the current error. .It Fn elf_errmsg Retrieve a human readable description of the current error. .El .It "Initialization" .Bl -tag -compact .It Fn elf_begin Opens an .Xr ar 1 archive or ELF object given a file descriptor. .It Fn elf_end Close an ELF descriptor and release all its resources. .It Fn elf_memory Opens an .Xr ar 1 archive or ELF object present in a memory arena. .It Fn elf_version Sets the operating version. .El .It "IO Control" .Bl -tag -width ".Fn elf_setshstrndx" -compact .It Fn elf_cntl Manage the association between and ELF descriptor and its underlying file. .It Fn elf_flagdata Mark an .Vt Elf_Data descriptor as dirty. .It Fn elf_flagehdr Mark the ELF Executable Header in an ELF descriptor as dirty. .It Fn elf_flagphdr Mark the ELF Program Header Table in an ELF descriptor as dirty. .It Fn elf_flagscn Mark an .Vt Elf_Scn descriptor as dirty. .It Fn elf_flagshdr Mark an ELF Section Header as dirty. .It Fn elf_setshstrndx Set the index of the section name string table for the ELF object. .It Fn elf_update Recompute ELF object layout and optionally write the modified object back to the underlying file. .El .It "Queries" .Bl -tag -width ".Fn elf_getshstrndx" -compact .It Fn elf32_checksum , Fn elf64_checkum Compute checksum of an ELF object. .It Fn elf_getident Retrieve the identification bytes for an ELF object. .It Fn elf_getshnum Retrieve the number of sections in an ELF object. .It Fn elf_getshstrndx Retrieve the section index of the section name string table in an ELF object. .It Fn elf_hash Compute the ELF hash value of a string. .It Fn elf_kind Query the kind of object associated with an ELF descriptor. .It Fn elf32_fsize , Fn elf64_fsize Return the size of the file representation of an ELF type. .El .El .Ss Controlling ELF Object Layout In the usual mode of operation, library will compute section offsets and alignments based on the contents of an ELF descriptor's sections without need for further intervention by the application. .Pp However, if the application wishes to take complete charge of the layout of the ELF file, it may set the .Dv ELF_F_LAYOUT flag on an ELF descriptor using .Xr elf_flagelf 3 , following which the library will use the data offsets and alignments specified by the application when laying out the file. Application control of file layout is described further in the .Xr elf_update 3 manual page. .Pp Gaps in between sections will be filled with the fill character set by function .Fn elf_fill . .Ss Error Handling In case an error is encountered, these library functions set an internal error number and signal the presence of the error by returning an special return value. The application can check the current error number by calling .Xr elf_errno 3 . A human readable description of the recorded error is available by calling .Xr elf_errmsg 3 . .Ss Memory Management Rules The library keeps track of all .Vt Elf_Scn and .Vt Elf_Data descriptors associated with an ELF descriptor and recovers them when the descriptor is closed using .Xr elf_end 3 . Thus the application must not call .Xr free 3 on data structures allocated by the ELF library. .Pp Conversely the library will not free data that it has not allocated. As an example, an application may call .Xr elf_newdata 3 to allocate a new .Vt Elf_Data descriptor and can set the .Va d_off member of the descriptor to point to a region of memory allocated using .Xr malloc 3 . It is the applications responsibility to free this arena, though the library will reclaim the space used by the .Vt Elf_Data descriptor itself. .Sh SEE ALSO .Xr gelf 3 , .Xr elf 5 .Sh HISTORY The original ELF(3) API was developed for Unix System V. The current implementation of the ELF(3) API appeared in .Fx 7.0 . .Sh AUTHORS The ELF library was written by .An "Joseph Koshy" .Aq jkoshy@FreeBSD.org . diff --git a/libelf/elf_data.c b/libelf/elf_data.c index 06a3577dc5dd..9960b77bea27 100644 --- a/libelf/elf_data.c +++ b/libelf/elf_data.c @@ -1,256 +1,269 @@ /*- * Copyright (c) 2006,2008,2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_data.c 2921 2013-03-04 16:19:22Z jkoshy $"); +ELFTC_VCSID("$Id: elf_data.c 3009 2014-03-23 01:49:59Z jkoshy $"); Elf_Data * elf_getdata(Elf_Scn *s, Elf_Data *ed) { Elf *e; unsigned int sh_type; int elfclass, elftype; - size_t fsz, msz, count; + size_t count, fsz, msz; struct _Libelf_Data *d; uint64_t sh_align, sh_offset, sh_size; - int (*xlate)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s, + size_t _c, int _swap); d = (struct _Libelf_Data *) ed; if (s == NULL || (e = s->s_elf) == NULL || (d != NULL && s != d->d_scn)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(e->e_kind == ELF_K_ELF); if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) return (&d->d_data); if (d != NULL) return (&STAILQ_NEXT(d, d_next)->d_data); if (e->e_rawfile == NULL) { /* * In the ELF_C_WRITE case, there is no source that * can provide data for the section. */ LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } elfclass = e->e_class; assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); if (elfclass == ELFCLASS32) { sh_type = s->s_shdr.s_shdr32.sh_type; sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; } else { sh_type = s->s_shdr.s_shdr64.sh_type; sh_offset = s->s_shdr.s_shdr64.sh_offset; sh_size = s->s_shdr.s_shdr64.sh_size; sh_align = s->s_shdr.s_shdr64.sh_addralign; } if (sh_type == SHT_NULL) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && sh_offset + sh_size > (uint64_t) e->e_rawsize)) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) (elftype, (size_t) 1, e->e_version)) == 0) { LIBELF_SET_ERROR(UNIMPL, 0); return (NULL); } if (sh_size % fsz) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } - count = sh_size / fsz; + if (sh_size / fsz > SIZE_MAX) { + LIBELF_SET_ERROR(RANGE, 0); + return (NULL); + } + + count = (size_t) (sh_size / fsz); msz = _libelf_msize(elftype, elfclass, e->e_version); + if (count > 0 && msz > SIZE_MAX / count) { + LIBELF_SET_ERROR(RANGE, 0); + return (NULL); + } + assert(msz > 0); + assert(count <= SIZE_MAX); + assert(msz * count <= SIZE_MAX); if ((d = _libelf_allocate_data(s)) == NULL) return (NULL); d->d_data.d_buf = NULL; d->d_data.d_off = 0; d->d_data.d_align = sh_align; d->d_data.d_size = msz * count; d->d_data.d_type = elftype; d->d_data.d_version = e->e_version; if (sh_type == SHT_NOBITS || sh_size == 0) { STAILQ_INSERT_TAIL(&s->s_data, d, d_next); return (&d->d_data); } - if ((d->d_data.d_buf = malloc(msz*count)) == NULL) { + if ((d->d_data.d_buf = malloc(msz * count)) == NULL) { (void) _libelf_release_data(d); LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } d->d_flags |= LIBELF_F_DATA_MALLOCED; xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); - if (!(*xlate)(d->d_data.d_buf, d->d_data.d_size, + if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size, e->e_rawfile + sh_offset, count, e->e_byteorder != LIBELF_PRIVATE(byteorder))) { _libelf_release_data(d); LIBELF_SET_ERROR(DATA, 0); return (NULL); } STAILQ_INSERT_TAIL(&s->s_data, d, d_next); return (&d->d_data); } Elf_Data * elf_newdata(Elf_Scn *s) { Elf *e; struct _Libelf_Data *d; if (s == NULL || (e = s->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(e->e_kind == ELF_K_ELF); /* * elf_newdata() has to append a data descriptor, so * bring in existing section data if not already present. */ if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) if (elf_getdata(s, NULL) == NULL) return (NULL); if ((d = _libelf_allocate_data(s)) == NULL) return (NULL); STAILQ_INSERT_TAIL(&s->s_data, d, d_next); d->d_data.d_align = 1; d->d_data.d_buf = NULL; d->d_data.d_off = (uint64_t) ~0; d->d_data.d_size = 0; d->d_data.d_type = ELF_T_BYTE; d->d_data.d_version = LIBELF_PRIVATE(version); (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); return (&d->d_data); } /* * Retrieve a data descriptor for raw (untranslated) data for section * `s'. */ Elf_Data * elf_rawdata(Elf_Scn *s, Elf_Data *ed) { Elf *e; int elf_class; uint32_t sh_type; struct _Libelf_Data *d; uint64_t sh_align, sh_offset, sh_size; if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(e->e_kind == ELF_K_ELF); d = (struct _Libelf_Data *) ed; if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL) return (&d->d_data); if (d != NULL) return (&STAILQ_NEXT(d, d_next)->d_data); elf_class = e->e_class; assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64); if (elf_class == ELFCLASS32) { sh_type = s->s_shdr.s_shdr32.sh_type; sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; } else { sh_type = s->s_shdr.s_shdr64.sh_type; sh_offset = s->s_shdr.s_shdr64.sh_offset; sh_size = s->s_shdr.s_shdr64.sh_size; sh_align = s->s_shdr.s_shdr64.sh_addralign; } if (sh_type == SHT_NULL) { LIBELF_SET_ERROR(SECTION, 0); return (NULL); } if ((d = _libelf_allocate_data(s)) == NULL) return (NULL); d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL : e->e_rawfile + sh_offset; d->d_data.d_off = 0; d->d_data.d_align = sh_align; d->d_data.d_size = sh_size; d->d_data.d_type = ELF_T_BYTE; d->d_data.d_version = e->e_version; STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next); return (&d->d_data); } diff --git a/libelf/elf_errmsg.c b/libelf/elf_errmsg.c index adcaa74b29ba..409862cc1557 100644 --- a/libelf/elf_errmsg.c +++ b/libelf/elf_errmsg.c @@ -1,85 +1,85 @@ /*- * Copyright (c) 2006,2008,2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_errmsg.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: elf_errmsg.c 3012 2014-03-23 03:41:38Z jkoshy $"); /* * Retrieve a human readable translation for an error message. */ -const char *_libelf_errors[] = { +static const char *_libelf_errors[] = { #define DEFINE_ERROR(N,S) [ELF_E_##N] = S DEFINE_ERROR(NONE, "No Error"), DEFINE_ERROR(ARCHIVE, "Malformed ar(1) archive"), DEFINE_ERROR(ARGUMENT, "Invalid argument"), DEFINE_ERROR(CLASS, "ELF class mismatch"), DEFINE_ERROR(DATA, "Invalid data buffer descriptor"), DEFINE_ERROR(HEADER, "Missing or malformed ELF header"), DEFINE_ERROR(IO, "I/O error"), DEFINE_ERROR(LAYOUT, "Layout constraint violation"), DEFINE_ERROR(MODE, "Incorrect ELF descriptor mode"), DEFINE_ERROR(RANGE, "Value out of range of target"), DEFINE_ERROR(RESOURCE, "Resource exhaustion"), DEFINE_ERROR(SECTION, "Invalid section descriptor"), DEFINE_ERROR(SEQUENCE, "API calls out of sequence"), DEFINE_ERROR(UNIMPL, "Unimplemented feature"), DEFINE_ERROR(VERSION, "Unknown ELF API version"), DEFINE_ERROR(NUM, "Unknown error") #undef DEFINE_ERROR }; const char * elf_errmsg(int error) { int oserr; if (error == ELF_E_NONE && (error = LIBELF_PRIVATE(error)) == 0) return NULL; else if (error == -1) error = LIBELF_PRIVATE(error); oserr = error >> LIBELF_OS_ERROR_SHIFT; error &= LIBELF_ELF_ERROR_MASK; if (error < ELF_E_NONE || error >= ELF_E_NUM) return _libelf_errors[ELF_E_NUM]; if (oserr) { - (void) snprintf(LIBELF_PRIVATE(msg), + (void) snprintf((char *) LIBELF_PRIVATE(msg), sizeof(LIBELF_PRIVATE(msg)), "%s: %s", _libelf_errors[error], strerror(oserr)); return (const char *)&LIBELF_PRIVATE(msg); } return _libelf_errors[error]; } diff --git a/libelf/elf_flag.c b/libelf/elf_flag.c index ab9d24a0ecea..89af3160da6a 100644 --- a/libelf/elf_flag.c +++ b/libelf/elf_flag.c @@ -1,198 +1,198 @@ /*- * Copyright (c) 2006,2008-2009,2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_flag.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: elf_flag.c 2988 2014-03-17 08:51:49Z jkoshy $"); unsigned int elf_flagarhdr(Elf_Arhdr *a, Elf_Cmd c, unsigned int flags) { unsigned int r; if (a == NULL) return (0); if ((c != ELF_C_SET && c != ELF_C_CLR) || (flags & ~ELF_F_DIRTY) != 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (c == ELF_C_SET) r = a->ar_flags |= flags; else r = a->ar_flags &= ~flags; return (r & LIBELF_F_API_MASK); } unsigned int elf_flagdata(Elf_Data *d, Elf_Cmd c, unsigned int flags) { unsigned int r; struct _Libelf_Data *ld; if (d == NULL) return (0); if ((c != ELF_C_SET && c != ELF_C_CLR) || (flags & ~ELF_F_DIRTY) != 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ld = (struct _Libelf_Data *) d; if (c == ELF_C_SET) r = ld->d_flags |= flags; else r = ld->d_flags &= ~flags; return (r & LIBELF_F_API_MASK); } unsigned int elf_flagehdr(Elf *e, Elf_Cmd c, unsigned int flags) { int ec; void *ehdr; if (e == NULL) return (0); if ((c != ELF_C_SET && c != ELF_C_CLR) || (e->e_kind != ELF_K_ELF) || (flags & ~ELF_F_DIRTY) != 0 || ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) ehdr = e->e_u.e_elf.e_ehdr.e_ehdr32; else ehdr = e->e_u.e_elf.e_ehdr.e_ehdr64; if (ehdr == NULL) { LIBELF_SET_ERROR(SEQUENCE, 0); return (0); } return (elf_flagelf(e, c, flags)); } unsigned int elf_flagelf(Elf *e, Elf_Cmd c, unsigned int flags) { - int r; + unsigned int r; if (e == NULL) return (0); if ((c != ELF_C_SET && c != ELF_C_CLR) || (e->e_kind != ELF_K_ELF) || (flags & ~(ELF_F_ARCHIVE | ELF_F_ARCHIVE_SYSV | ELF_F_DIRTY | ELF_F_LAYOUT)) != 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if ((flags & ELF_F_ARCHIVE_SYSV) && (flags & ELF_F_ARCHIVE) == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if ((flags & ELF_F_ARCHIVE) && e->e_cmd != ELF_C_WRITE) { LIBELF_SET_ERROR(MODE, 0); return (0); } if (c == ELF_C_SET) r = e->e_flags |= flags; else r = e->e_flags &= ~flags; return (r & LIBELF_F_API_MASK); } unsigned int elf_flagphdr(Elf *e, Elf_Cmd c, unsigned int flags) { int ec; void *phdr; if (e == NULL) return (0); if ((c != ELF_C_SET && c != ELF_C_CLR) || (e->e_kind != ELF_K_ELF) || (flags & ~ELF_F_DIRTY) != 0 || ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) phdr = e->e_u.e_elf.e_phdr.e_phdr32; else phdr = e->e_u.e_elf.e_phdr.e_phdr64; if (phdr == NULL) { LIBELF_SET_ERROR(SEQUENCE, 0); return (0); } return (elf_flagelf(e, c, flags)); } unsigned int elf_flagscn(Elf_Scn *s, Elf_Cmd c, unsigned int flags) { - int r; + unsigned int r; if (s == NULL) return (0); if ((c != ELF_C_SET && c != ELF_C_CLR) || (flags & ~ELF_F_DIRTY) != 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (c == ELF_C_SET) r = s->s_flags |= flags; else r = s->s_flags &= ~flags; return (r & LIBELF_F_API_MASK); } unsigned int elf_flagshdr(Elf_Scn *s, Elf_Cmd c, unsigned int flags) { return (elf_flagscn(s, c, flags)); } diff --git a/libelf/elf_memory.c b/libelf/elf_memory.c index 9c4755d0f59b..d70f6e094912 100644 --- a/libelf/elf_memory.c +++ b/libelf/elf_memory.c @@ -1,47 +1,47 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_memory.c 2368 2011-12-29 06:34:28Z jkoshy $"); +ELFTC_VCSID("$Id: elf_memory.c 3013 2014-03-23 06:16:59Z jkoshy $"); Elf * elf_memory(char *image, size_t sz) { if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } if (image == NULL || sz == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } - return (_libelf_memory(image, sz, 1)); + return (_libelf_memory((unsigned char *) image, sz, 1)); } diff --git a/libelf/elf_next.c b/libelf/elf_next.c index 605a593dd9e3..7da8ba6fe857 100644 --- a/libelf/elf_next.c +++ b/libelf/elf_next.c @@ -1,62 +1,66 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_next.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: elf_next.c 2989 2014-03-17 09:56:46Z jkoshy $"); Elf_Cmd elf_next(Elf *e) { off_t next; Elf *parent; if (e == NULL) return (ELF_C_NULL); if ((parent = e->e_parent) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (ELF_C_NULL); } - assert (parent->e_kind == ELF_K_AR); - assert (parent->e_cmd == ELF_C_READ); + assert(parent->e_kind == ELF_K_AR); + assert(parent->e_cmd == ELF_C_READ); assert(e->e_rawfile > parent->e_rawfile); - next = e->e_rawfile - parent->e_rawfile + e->e_rawsize; + next = e->e_rawfile - parent->e_rawfile + (off_t) e->e_rawsize; next = (next + 1) & ~1; /* round up to an even boundary */ + /* + * Setup the 'e_next' field of the archive descriptor for the + * next call to 'elf_begin()'. + */ parent->e_u.e_ar.e_next = (next >= (off_t) parent->e_rawsize) ? (off_t) 0 : next; return (ELF_C_READ); } diff --git a/libelf/elf_open.c b/libelf/elf_open.c index b039431571fb..5aad459f4002 100644 --- a/libelf/elf_open.c +++ b/libelf/elf_open.c @@ -1,67 +1,67 @@ /*- * Copyright (c) 2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "_libelf.h" ELFTC_VCSID("$Id$"); /* * Extension API: open a file for reading, ignoring parse errors. */ Elf * elf_open(int fd) { if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } return (_libelf_open_object(fd, ELF_C_READ, 0)); } /* * Extension API: create an ELF descriptor for an in-memory object, * ignoring parse errors. */ Elf * elf_openmemory(char *image, size_t sz) { if (LIBELF_PRIVATE(version) == EV_NONE) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } if (image == NULL || sz == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } - return (_libelf_memory(image, sz, 0)); + return (_libelf_memory((unsigned char *) image, sz, 0)); } diff --git a/libelf/elf_rand.c b/libelf/elf_rand.c index f48f01745802..8c36ff809702 100644 --- a/libelf/elf_rand.c +++ b/libelf/elf_rand.c @@ -1,59 +1,59 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_rand.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: elf_rand.c 2991 2014-03-17 09:57:04Z jkoshy $"); off_t elf_rand(Elf *ar, off_t offset) { struct ar_hdr *arh; if (ar == NULL || ar->e_kind != ELF_K_AR || (offset & 1) || offset < SARMAG || - offset + sizeof(struct ar_hdr) >= ar->e_rawsize) { + (size_t) offset + sizeof(struct ar_hdr) >= ar->e_rawsize) { LIBELF_SET_ERROR(ARGUMENT, 0); return 0; } arh = (struct ar_hdr *) (ar->e_rawfile + offset); /* a too simple sanity check */ if (arh->ar_fmag[0] != '`' || arh->ar_fmag[1] != '\n') { LIBELF_SET_ERROR(ARCHIVE, 0); return 0; } ar->e_u.e_ar.e_next = offset; return (offset); } diff --git a/libelf/elf_rawfile.c b/libelf/elf_rawfile.c index 76cfd7fa3435..a5b5b3ed5f7f 100644 --- a/libelf/elf_rawfile.c +++ b/libelf/elf_rawfile.c @@ -1,53 +1,53 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_rawfile.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: elf_rawfile.c 3013 2014-03-23 06:16:59Z jkoshy $"); char * elf_rawfile(Elf *e, size_t *sz) { - char *ptr; size_t size; + unsigned char *ptr; size = e ? e->e_rawsize : 0; ptr = NULL; if (e == NULL) LIBELF_SET_ERROR(ARGUMENT, 0); else if ((ptr = e->e_rawfile) == NULL && e->e_cmd == ELF_C_WRITE) LIBELF_SET_ERROR(SEQUENCE, 0); if (sz) *sz = size; - return (ptr); + return ((char *) ptr); } diff --git a/libelf/elf_scn.c b/libelf/elf_scn.c index 357fbb33d847..f80711579d59 100644 --- a/libelf/elf_scn.c +++ b/libelf/elf_scn.c @@ -1,232 +1,233 @@ /*- * Copyright (c) 2006,2008-2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_scn.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: elf_scn.c 3013 2014-03-23 06:16:59Z jkoshy $"); /* * Load an ELF section table and create a list of Elf_Scn structures. */ int _libelf_load_section_headers(Elf *e, void *ehdr) { - int ec, swapbytes; - size_t fsz, i, shnum; + Elf_Scn *scn; uint64_t shoff; - char *src; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; - Elf_Scn *scn; - int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + int ec, swapbytes; + unsigned char *src; + size_t fsz, i, shnum; + int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, + size_t _c, int _swap); assert(e != NULL); assert(ehdr != NULL); assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0); #define CHECK_EHDR(E,EH) do { \ if (fsz != (EH)->e_shentsize || \ shoff + fsz * shnum > e->e_rawsize) { \ LIBELF_SET_ERROR(HEADER, 0); \ return (0); \ } \ } while (0) ec = e->e_class; fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); assert(fsz > 0); shnum = e->e_u.e_elf.e_nscn; if (ec == ELFCLASS32) { eh32 = (Elf32_Ehdr *) ehdr; shoff = (uint64_t) eh32->e_shoff; CHECK_EHDR(e, eh32); } else { eh64 = (Elf64_Ehdr *) ehdr; shoff = eh64->e_shoff; CHECK_EHDR(e, eh64); } xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder); src = e->e_rawfile + shoff; /* * If the file is using extended numbering then section #0 * would have already been read in. */ i = 0; if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) == STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next)); i = 1; src += fsz; } for (; i < shnum; i++, src += fsz) { if ((scn = _libelf_allocate_scn(e, i)) == NULL) return (0); - (*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr), src, - (size_t) 1, swapbytes); + (*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr), + src, (size_t) 1, swapbytes); if (ec == ELFCLASS32) { scn->s_offset = scn->s_rawoff = scn->s_shdr.s_shdr32.sh_offset; scn->s_size = scn->s_shdr.s_shdr32.sh_size; } else { scn->s_offset = scn->s_rawoff = scn->s_shdr.s_shdr64.sh_offset; scn->s_size = scn->s_shdr.s_shdr64.sh_size; } } e->e_flags |= LIBELF_F_SHDRS_LOADED; return (1); } Elf_Scn * elf_getscn(Elf *e, size_t index) { int ec; void *ehdr; Elf_Scn *s; if (e == NULL || e->e_kind != ELF_K_ELF || ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) return (NULL); if (e->e_cmd != ELF_C_WRITE && (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && _libelf_load_section_headers(e, ehdr) == 0) return (NULL); STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) if (s->s_ndx == index) return (s); LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } size_t elf_ndxscn(Elf_Scn *s) { if (s == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (SHN_UNDEF); } return (s->s_ndx); } Elf_Scn * elf_newscn(Elf *e) { int ec; void *ehdr; Elf_Scn *scn; if (e == NULL || e->e_kind != ELF_K_ELF) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { LIBELF_SET_ERROR(CLASS, 0); return (NULL); } if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) return (NULL); /* * The application may be asking for a new section descriptor * on an ELF object opened with ELF_C_RDWR or ELF_C_READ. We * need to bring in the existing section information before * appending a new one to the list. * * Per the ELF(3) API, an application is allowed to open a * file using ELF_C_READ, mess with its internal structure and * use elf_update(...,ELF_C_NULL) to compute its new layout. */ if (e->e_cmd != ELF_C_WRITE && (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && _libelf_load_section_headers(e, ehdr) == 0) return (NULL); if (STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) { assert(e->e_u.e_elf.e_nscn == 0); if ((scn = _libelf_allocate_scn(e, (size_t) SHN_UNDEF)) == NULL) return (NULL); e->e_u.e_elf.e_nscn++; } assert(e->e_u.e_elf.e_nscn > 0); if ((scn = _libelf_allocate_scn(e, e->e_u.e_elf.e_nscn)) == NULL) return (NULL); e->e_u.e_elf.e_nscn++; (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY); return (scn); } Elf_Scn * elf_nextscn(Elf *e, Elf_Scn *s) { if (e == NULL || (e->e_kind != ELF_K_ELF) || (s && s->s_elf != e)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } return (s == NULL ? elf_getscn(e, (size_t) 1) : STAILQ_NEXT(s, s_next)); } diff --git a/libelf/elf_strptr.c b/libelf/elf_strptr.c index c79970dc8907..e2a6b2899f58 100644 --- a/libelf/elf_strptr.c +++ b/libelf/elf_strptr.c @@ -1,132 +1,132 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: elf_strptr.c 2271 2011-12-03 17:06:35Z jkoshy $"); +ELFTC_VCSID("$Id: elf_strptr.c 2990 2014-03-17 09:56:58Z jkoshy $"); /* * Convert an ELF section#,offset pair to a string pointer. */ char * elf_strptr(Elf *e, size_t scndx, size_t offset) { Elf_Scn *s; Elf_Data *d; - size_t alignment, count; GElf_Shdr shdr; + uint64_t alignment, count; if (e == NULL || e->e_kind != ELF_K_ELF) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((s = elf_getscn(e, scndx)) == NULL || gelf_getshdr(s, &shdr) == NULL) return (NULL); if (shdr.sh_type != SHT_STRTAB || offset >= shdr.sh_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } d = NULL; if (e->e_flags & ELF_F_LAYOUT) { /* * The application is taking responsibility for the * ELF object's layout, so we can directly translate * an offset to a `char *' address using the `d_off' * members of Elf_Data descriptors. */ while ((d = elf_getdata(s, d)) != NULL) { if (d->d_buf == 0 || d->d_size == 0) continue; if (d->d_type != ELF_T_BYTE) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if (offset >= d->d_off && offset < d->d_off + d->d_size) return ((char *) d->d_buf + offset - d->d_off); } } else { /* * Otherwise, the `d_off' members are not useable and * we need to compute offsets ourselves, taking into * account 'holes' in coverage of the section introduced * by alignment requirements. */ - count = (size_t) 0; /* cumulative count of bytes seen */ + count = (uint64_t) 0; /* cumulative count of bytes seen */ while ((d = elf_getdata(s, d)) != NULL && count <= offset) { if (d->d_buf == NULL || d->d_size == 0) continue; if (d->d_type != ELF_T_BYTE) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((alignment = d->d_align) > 1) { if ((alignment & (alignment - 1)) != 0) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } count = roundup2(count, alignment); } if (offset < count) { /* offset starts in the 'hole' */ LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (offset < count + d->d_size) { if (d->d_buf != NULL) return ((char *) d->d_buf + offset - count); LIBELF_SET_ERROR(DATA, 0); return (NULL); } count += d->d_size; } } LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } diff --git a/libelf/elf_update.c b/libelf/elf_update.c index b589233c8e4a..70a7c2e21e25 100644 --- a/libelf/elf_update.c +++ b/libelf/elf_update.c @@ -1,1202 +1,1213 @@ /*- * Copyright (c) 2006-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "_libelf.h" #if ELFTC_HAVE_MMAP #include #endif -ELFTC_VCSID("$Id: elf_update.c 2931 2013-03-23 11:41:07Z jkoshy $"); +ELFTC_VCSID("$Id: elf_update.c 3013 2014-03-23 06:16:59Z jkoshy $"); /* * Layout strategy: * * - Case 1: ELF_F_LAYOUT is asserted * In this case the application has full control over where the * section header table, program header table, and section data * will reside. The library only perform error checks. * * - Case 2: ELF_F_LAYOUT is not asserted * * The library will do the object layout using the following * ordering: * - The executable header is placed first, are required by the * ELF specification. * - The program header table is placed immediately following the * executable header. * - Section data, if any, is placed after the program header * table, aligned appropriately. * - The section header table, if needed, is placed last. * * There are two sub-cases to be taken care of: * * - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR * * In this sub-case, the underlying ELF object may already have * content in it, which the application may have modified. The * library will retrieve content from the existing object as * needed. * * - Case 2b: e->e_cmd == ELF_C_WRITE * * The ELF object is being created afresh in this sub-case; * there is no pre-existing content in the underlying ELF * object. */ /* * The types of extents in an ELF object. */ enum elf_extent { ELF_EXTENT_EHDR, ELF_EXTENT_PHDR, ELF_EXTENT_SECTION, ELF_EXTENT_SHDR }; /* * A extent descriptor, used when laying out an ELF object. */ struct _Elf_Extent { SLIST_ENTRY(_Elf_Extent) ex_next; uint64_t ex_start; /* Start of the region. */ uint64_t ex_size; /* The size of the region. */ enum elf_extent ex_type; /* Type of region. */ void *ex_desc; /* Associated descriptor. */ }; SLIST_HEAD(_Elf_Extent_List, _Elf_Extent); /* * Compute the extents of a section, by looking at the data * descriptors associated with it. The function returns 1 * if successful, or zero if an error was detected. */ static int _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) { - int ec; Elf_Data *d; size_t fsz, msz; + int ec, elftype; uint32_t sh_type; uint64_t d_align; Elf32_Shdr *shdr32; Elf64_Shdr *shdr64; - unsigned int elftype; struct _Libelf_Data *ld; uint64_t scn_size, scn_alignment; uint64_t sh_align, sh_entsize, sh_offset, sh_size; ec = e->e_class; shdr32 = &s->s_shdr.s_shdr32; shdr64 = &s->s_shdr.s_shdr64; if (ec == ELFCLASS32) { sh_type = shdr32->sh_type; sh_align = (uint64_t) shdr32->sh_addralign; sh_entsize = (uint64_t) shdr32->sh_entsize; sh_offset = (uint64_t) shdr32->sh_offset; sh_size = (uint64_t) shdr32->sh_size; } else { sh_type = shdr64->sh_type; sh_align = shdr64->sh_addralign; sh_entsize = shdr64->sh_entsize; sh_offset = shdr64->sh_offset; sh_size = shdr64->sh_size; } assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS); elftype = _libelf_xlate_shtype(sh_type); if (elftype > ELF_T_LAST) { LIBELF_SET_ERROR(SECTION, 0); return (0); } if (sh_align == 0) sh_align = _libelf_falign(elftype, ec); /* * Compute the section's size and alignment using the data * descriptors associated with the section. */ if (STAILQ_EMPTY(&s->s_data)) { /* * The section's content (if any) has not been read in * yet. If section is not dirty marked dirty, we can * reuse the values in the 'sh_size' and 'sh_offset' * fields of the section header. */ if ((s->s_flags & ELF_F_DIRTY) == 0) { /* * If the library is doing the layout, then we * compute the new start offset for the * section based on the current offset and the * section's alignment needs. * * If the application is doing the layout, we * can use the value in the 'sh_offset' field * in the section header directly. */ if (e->e_flags & ELF_F_LAYOUT) goto updatedescriptor; else goto computeoffset; } /* * Otherwise, we need to bring in the section's data * from the underlying ELF object. */ if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL) return (0); } /* * Loop through the section's data descriptors. */ scn_size = 0L; scn_alignment = 0; STAILQ_FOREACH(ld, &s->s_data, d_next) { d = &ld->d_data; /* * The data buffer's type is known. */ if (d->d_type >= ELF_T_NUM) { LIBELF_SET_ERROR(DATA, 0); return (0); } /* * The data buffer's version is supported. */ if (d->d_version != e->e_version) { LIBELF_SET_ERROR(VERSION, 0); return (0); } /* * The buffer's alignment is non-zero and a power of * two. */ if ((d_align = d->d_align) == 0 || (d_align & (d_align - 1))) { LIBELF_SET_ERROR(DATA, 0); return (0); } /* * The buffer's size should be a multiple of the * memory size of the underlying type. */ msz = _libelf_msize(d->d_type, ec, e->e_version); if (d->d_size % msz) { LIBELF_SET_ERROR(DATA, 0); return (0); } /* * If the application is controlling layout, then the * d_offset field should be compatible with the * buffer's specified alignment. */ if ((e->e_flags & ELF_F_LAYOUT) && (d->d_off & (d_align - 1))) { LIBELF_SET_ERROR(LAYOUT, 0); return (0); } /* * Compute the section's size. */ if (e->e_flags & ELF_F_LAYOUT) { if ((uint64_t) d->d_off + d->d_size > scn_size) scn_size = d->d_off + d->d_size; } else { scn_size = roundup2(scn_size, d->d_align); d->d_off = scn_size; fsz = _libelf_fsize(d->d_type, ec, d->d_version, - d->d_size / msz); + (size_t) d->d_size / msz); scn_size += fsz; } /* * The section's alignment is the maximum alignment * needed for its data buffers. */ if (d_align > scn_alignment) scn_alignment = d_align; } /* * If the application is requesting full control over the * layout of the section, check the section's specified size, * offsets and alignment for sanity. */ if (e->e_flags & ELF_F_LAYOUT) { if (scn_alignment > sh_align || sh_offset % sh_align || sh_size < scn_size) { LIBELF_SET_ERROR(LAYOUT, 0); return (0); } goto updatedescriptor; } /* * Otherwise, compute the values in the section header. * * The section alignment is the maximum alignment for any of * its contained data descriptors. */ if (scn_alignment > sh_align) sh_align = scn_alignment; /* * If the section entry size is zero, try and fill in an * appropriate entry size. Per the elf(5) manual page * sections without fixed-size entries should have their * 'sh_entsize' field set to zero. */ if (sh_entsize == 0 && (sh_entsize = _libelf_fsize(elftype, ec, e->e_version, (size_t) 1)) == 1) sh_entsize = 0; sh_size = scn_size; computeoffset: /* * Compute the new offset for the section based on * the section's alignment needs. */ - sh_offset = roundup(rc, sh_align); + sh_offset = roundup((uint64_t) rc, sh_align); /* * Update the section header. */ if (ec == ELFCLASS32) { shdr32->sh_addralign = (uint32_t) sh_align; shdr32->sh_entsize = (uint32_t) sh_entsize; shdr32->sh_offset = (uint32_t) sh_offset; shdr32->sh_size = (uint32_t) sh_size; } else { shdr64->sh_addralign = sh_align; shdr64->sh_entsize = sh_entsize; shdr64->sh_offset = sh_offset; shdr64->sh_size = sh_size; } updatedescriptor: /* * Update the section descriptor. */ s->s_size = sh_size; s->s_offset = sh_offset; return (1); } /* * Free a list of extent descriptors. */ static void _libelf_release_extents(struct _Elf_Extent_List *extents) { struct _Elf_Extent *ex; while ((ex = SLIST_FIRST(extents)) != NULL) { SLIST_REMOVE_HEAD(extents, ex_next); free(ex); } } /* * Check if an extent 's' defined by [start..start+size) is free. * This routine assumes that the given extent list is sorted in order * of ascending extent offsets. */ static int _libelf_extent_is_unused(struct _Elf_Extent_List *extents, const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt) { uint64_t tmax, tmin; struct _Elf_Extent *t, *pt; const uint64_t smax = start + size; /* First, look for overlaps with existing extents. */ pt = NULL; SLIST_FOREACH(t, extents, ex_next) { tmin = t->ex_start; tmax = tmin + t->ex_size; if (tmax <= start) { /* * 't' lies entirely before 's': ...| t |...| s |... */ pt = t; continue; } else if (smax <= tmin) { /* * 's' lies entirely before 't', and after 'pt': * ...| pt |...| s |...| t |... */ assert(pt == NULL || pt->ex_start + pt->ex_size <= start); break; } else /* 's' and 't' overlap. */ return (0); } if (prevt) *prevt = pt; return (1); } /* * Insert an extent into the list of extents. */ static int _libelf_insert_extent(struct _Elf_Extent_List *extents, int type, uint64_t start, uint64_t size, void *desc) { struct _Elf_Extent *ex, *prevt; assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR); prevt = NULL; /* * If the requested range overlaps with an existing extent, * signal an error. */ if (!_libelf_extent_is_unused(extents, start, size, &prevt)) { LIBELF_SET_ERROR(LAYOUT, 0); return (0); } /* Allocate and fill in a new extent descriptor. */ if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) { LIBELF_SET_ERROR(RESOURCE, errno); return (0); } ex->ex_start = start; ex->ex_size = size; ex->ex_desc = desc; ex->ex_type = type; /* Insert the region descriptor into the list. */ if (prevt) SLIST_INSERT_AFTER(prevt, ex, ex_next); else SLIST_INSERT_HEAD(extents, ex, ex_next); return (1); } /* * Recompute section layout. */ static off_t _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents) { int ec; Elf_Scn *s; size_t sh_type; ec = e->e_class; /* * Make a pass through sections, computing the extent of each * section. */ STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) { if (ec == ELFCLASS32) sh_type = s->s_shdr.s_shdr32.sh_type; else sh_type = s->s_shdr.s_shdr64.sh_type; if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) continue; if (_libelf_compute_section_extents(e, s, rc) == 0) return ((off_t) -1); if (s->s_size == 0) continue; if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION, s->s_offset, s->s_size, s)) return ((off_t) -1); if ((size_t) rc < s->s_offset + s->s_size) - rc = s->s_offset + s->s_size; + rc = (off_t) (s->s_offset + s->s_size); } return (rc); } /* * Recompute the layout of the ELF object and update the internal data * structures associated with the ELF descriptor. * * Returns the size in bytes the ELF object would occupy in its file * representation. * * After a successful call to this function, the following structures * are updated: * * - The ELF header is updated. * - All extents in the ELF object are sorted in order of ascending * addresses. Sections have their section header table entries * updated. An error is signalled if an overlap was detected among * extents. * - Data descriptors associated with sections are checked for valid * types, offsets and alignment. * * After a resync_elf() successfully returns, the ELF descriptor is * ready for being handed over to _libelf_write_elf(). */ static off_t _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) { int ec, eh_class; unsigned int eh_byteorder, eh_version; size_t align, fsz; size_t phnum, shnum; off_t rc, phoff, shoff; void *ehdr, *phdr; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; rc = 0; ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); /* * Prepare the EHDR. */ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) return ((off_t) -1); eh32 = ehdr; eh64 = ehdr; if (ec == ELFCLASS32) { eh_byteorder = eh32->e_ident[EI_DATA]; eh_class = eh32->e_ident[EI_CLASS]; - phoff = (uint64_t) eh32->e_phoff; - shoff = (uint64_t) eh32->e_shoff; + phoff = (off_t) eh32->e_phoff; + shoff = (off_t) eh32->e_shoff; eh_version = eh32->e_version; } else { eh_byteorder = eh64->e_ident[EI_DATA]; eh_class = eh64->e_ident[EI_CLASS]; - phoff = eh64->e_phoff; - shoff = eh64->e_shoff; + phoff = (off_t) eh64->e_phoff; + shoff = (off_t) eh64->e_shoff; eh_version = eh64->e_version; } + if (phoff < 0 || shoff < 0) { + LIBELF_SET_ERROR(HEADER, 0); + return ((off_t) -1); + } + if (eh_version == EV_NONE) eh_version = EV_CURRENT; if (eh_version != e->e_version) { /* always EV_CURRENT */ LIBELF_SET_ERROR(VERSION, 0); return ((off_t) -1); } if (eh_class != e->e_class) { LIBELF_SET_ERROR(CLASS, 0); return ((off_t) -1); } if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) { LIBELF_SET_ERROR(HEADER, 0); return ((off_t) -1); } shnum = e->e_u.e_elf.e_nscn; phnum = e->e_u.e_elf.e_nphdr; e->e_byteorder = eh_byteorder; #define INITIALIZE_EHDR(E,EC,V) do { \ + unsigned int _version = (unsigned int) (V); \ (E)->e_ident[EI_MAG0] = ELFMAG0; \ (E)->e_ident[EI_MAG1] = ELFMAG1; \ (E)->e_ident[EI_MAG2] = ELFMAG2; \ (E)->e_ident[EI_MAG3] = ELFMAG3; \ - (E)->e_ident[EI_CLASS] = (EC); \ - (E)->e_ident[EI_VERSION] = (V); \ - (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \ - (size_t) 1); \ - (E)->e_phentsize = (phnum == 0) ? 0 : _libelf_fsize( \ - ELF_T_PHDR, (EC), (V), (size_t) 1); \ - (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \ - (size_t) 1); \ + (E)->e_ident[EI_CLASS] = (unsigned char) (EC); \ + (E)->e_ident[EI_VERSION] = (_version & 0xFFU); \ + (E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR, \ + (EC), _version, (size_t) 1); \ + (E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : \ + _libelf_fsize(ELF_T_PHDR, (EC), _version, \ + (size_t) 1)); \ + (E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR, \ + (EC), _version, (size_t) 1); \ } while (0) if (ec == ELFCLASS32) INITIALIZE_EHDR(eh32, ec, eh_version); else INITIALIZE_EHDR(eh64, ec, eh_version); (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); - rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); + rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); - if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, rc, ehdr)) + if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc, + ehdr)) return ((off_t) -1); /* * Compute the layout the program header table, if one is * present. The program header table needs to be aligned to a * `natural' boundary. */ if (phnum) { fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum); align = _libelf_falign(ELF_T_PHDR, ec); if (e->e_flags & ELF_F_LAYOUT) { /* * Check offsets for sanity. */ if (rc > phoff) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } - if (phoff % align) { + if (phoff % (off_t) align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } } else - phoff = roundup(rc, align); + phoff = roundup(rc, (off_t) align); - rc = phoff + fsz; + rc = phoff + (off_t) fsz; phdr = _libelf_getphdr(e, ec); - if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, phoff, - fsz, phdr)) + if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, + (uint64_t) phoff, fsz, phdr)) return ((off_t) -1); } else phoff = 0; /* * Compute the layout of the sections associated with the * file. */ if (e->e_cmd != ELF_C_WRITE && (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && _libelf_load_section_headers(e, ehdr) == 0) return ((off_t) -1); if ((rc = _libelf_resync_sections(e, rc, extents)) < 0) return ((off_t) -1); /* * Compute the space taken up by the section header table, if * one is needed. * * If ELF_F_LAYOUT has been asserted, the application may have * placed the section header table in between existing * sections, so the net size of the file need not increase due * to the presence of the section header table. * * If the library is responsible for laying out the object, * the section header table is placed after section data. */ if (shnum) { fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum); align = _libelf_falign(ELF_T_SHDR, ec); if (e->e_flags & ELF_F_LAYOUT) { - if (shoff % align) { + if (shoff % (off_t) align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } } else - shoff = roundup(rc, align); + shoff = roundup(rc, (off_t) align); - if (shoff + fsz > (size_t) rc) - rc = shoff + fsz; + if (shoff + (off_t) fsz > rc) + rc = shoff + (off_t) fsz; - if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, shoff, - fsz, NULL)) + if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, + (uint64_t) shoff, fsz, NULL)) return ((off_t) -1); } else shoff = 0; /* * Set the fields of the Executable Header that could potentially use * extended numbering. */ _libelf_setphnum(e, ehdr, ec, phnum); _libelf_setshnum(e, ehdr, ec, shnum); /* * Update the `e_phoff' and `e_shoff' fields if the library is * doing the layout. */ if ((e->e_flags & ELF_F_LAYOUT) == 0) { if (ec == ELFCLASS32) { eh32->e_phoff = (uint32_t) phoff; eh32->e_shoff = (uint32_t) shoff; } else { eh64->e_phoff = (uint64_t) phoff; eh64->e_shoff = (uint64_t) shoff; } } return (rc); } /* * Write out the contents of an ELF section. */ -static size_t -_libelf_write_scn(Elf *e, char *nf, struct _Elf_Extent *ex) +static off_t +_libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; + off_t rc; Elf_Scn *s; int elftype; Elf_Data *d, dst; uint32_t sh_type; struct _Libelf_Data *ld; uint64_t sh_off, sh_size; - size_t fsz, msz, nobjects, rc; + size_t fsz, msz, nobjects; assert(ex->ex_type == ELF_EXTENT_SECTION); s = ex->ex_desc; - rc = ex->ex_start; + rc = (off_t) ex->ex_start; if ((ec = e->e_class) == ELFCLASS32) { sh_type = s->s_shdr.s_shdr32.sh_type; sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; } else { sh_type = s->s_shdr.s_shdr64.sh_type; sh_size = s->s_shdr.s_shdr64.sh_size; } /* * Ignore sections that do not allocate space in the file. */ if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0) return (rc); elftype = _libelf_xlate_shtype(sh_type); assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST); sh_off = s->s_offset; assert(sh_off % _libelf_falign(elftype, ec) == 0); /* * If the section has a `rawdata' descriptor, and the section * contents have not been modified, use its contents directly. * The `s_rawoff' member contains the offset into the original * file, while `s_offset' contains its new location in the * destination. */ if (STAILQ_EMPTY(&s->s_data)) { if ((d = elf_rawdata(s, NULL)) == NULL) return ((off_t) -1); STAILQ_FOREACH(ld, &s->s_rawdata, d_next) { d = &ld->d_data; if ((uint64_t) rc < sh_off + d->d_off) (void) memset(nf + rc, - LIBELF_PRIVATE(fillchar), sh_off + - d->d_off - rc); - rc = sh_off + d->d_off; + LIBELF_PRIVATE(fillchar), + (size_t) (sh_off + d->d_off - + (uint64_t) rc)); + rc = (off_t) (sh_off + d->d_off); assert(d->d_buf != NULL); assert(d->d_type == ELF_T_BYTE); assert(d->d_version == e->e_version); (void) memcpy(nf + rc, - e->e_rawfile + s->s_rawoff + d->d_off, d->d_size); + e->e_rawfile + s->s_rawoff + d->d_off, + (size_t) d->d_size); - rc += d->d_size; + rc += (off_t) d->d_size; } return (rc); } /* * Iterate over the set of data descriptors for this section. * The prior call to _libelf_resync_elf() would have setup the * descriptors for this step. */ dst.d_version = e->e_version; STAILQ_FOREACH(ld, &s->s_data, d_next) { d = &ld->d_data; msz = _libelf_msize(d->d_type, ec, e->e_version); if ((uint64_t) rc < sh_off + d->d_off) (void) memset(nf + rc, - LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc); + LIBELF_PRIVATE(fillchar), + (size_t) (sh_off + d->d_off - (uint64_t) rc)); - rc = sh_off + d->d_off; + rc = (off_t) (sh_off + d->d_off); assert(d->d_buf != NULL); assert(d->d_version == e->e_version); assert(d->d_size % msz == 0); - nobjects = d->d_size / msz; + nobjects = (size_t) (d->d_size / msz); fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects); dst.d_buf = nf + rc; dst.d_size = fsz; if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) == NULL) return ((off_t) -1); - rc += fsz; + rc += (off_t) fsz; } - return ((off_t) rc); + return (rc); } /* * Write out an ELF Executable Header. */ static off_t -_libelf_write_ehdr(Elf *e, char *nf, struct _Elf_Extent *ex) +_libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; void *ehdr; size_t fsz, msz; Elf_Data dst, src; assert(ex->ex_type == ELF_EXTENT_EHDR); assert(ex->ex_start == 0); /* Ehdr always comes first. */ ec = e->e_class; ehdr = _libelf_ehdr(e, ec, 0); assert(ehdr != NULL); fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version); (void) memset(&dst, 0, sizeof(dst)); (void) memset(&src, 0, sizeof(src)); src.d_buf = ehdr; src.d_size = msz; src.d_type = ELF_T_EHDR; src.d_version = dst.d_version = e->e_version; dst.d_buf = nf; dst.d_size = fsz; if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == NULL) return ((off_t) -1); return ((off_t) fsz); } /* * Write out an ELF program header table. */ static off_t -_libelf_write_phdr(Elf *e, char *nf, struct _Elf_Extent *ex) +_libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; void *ehdr; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; Elf_Data dst, src; size_t fsz, phnum; uint64_t phoff; assert(ex->ex_type == ELF_EXTENT_PHDR); ec = e->e_class; ehdr = _libelf_ehdr(e, ec, 0); phnum = e->e_u.e_elf.e_nphdr; assert(phnum > 0); if (ec == ELFCLASS32) { eh32 = (Elf32_Ehdr *) ehdr; phoff = (uint64_t) eh32->e_phoff; } else { eh64 = (Elf64_Ehdr *) ehdr; phoff = eh64->e_phoff; } assert(phoff > 0); assert(ex->ex_start == phoff); assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0); (void) memset(&dst, 0, sizeof(dst)); (void) memset(&src, 0, sizeof(src)); fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum); assert(fsz > 0); src.d_buf = _libelf_getphdr(e, ec); src.d_version = dst.d_version = e->e_version; src.d_type = ELF_T_PHDR; src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec, e->e_version); dst.d_size = fsz; dst.d_buf = nf + ex->ex_start; if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == NULL) return ((off_t) -1); - return (phoff + fsz); + return ((off_t) (phoff + fsz)); } /* * Write out an ELF section header table. */ static off_t -_libelf_write_shdr(Elf *e, char *nf, struct _Elf_Extent *ex) +_libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) { int ec; void *ehdr; Elf_Scn *scn; uint64_t shoff; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; size_t fsz, nscn; Elf_Data dst, src; assert(ex->ex_type == ELF_EXTENT_SHDR); ec = e->e_class; ehdr = _libelf_ehdr(e, ec, 0); nscn = e->e_u.e_elf.e_nscn; if (ec == ELFCLASS32) { eh32 = (Elf32_Ehdr *) ehdr; shoff = (uint64_t) eh32->e_shoff; } else { eh64 = (Elf64_Ehdr *) ehdr; shoff = eh64->e_shoff; } assert(nscn > 0); assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0); assert(ex->ex_start == shoff); (void) memset(&dst, 0, sizeof(dst)); (void) memset(&src, 0, sizeof(src)); src.d_type = ELF_T_SHDR; src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version); src.d_version = dst.d_version = e->e_version; fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) { if (ec == ELFCLASS32) src.d_buf = &scn->s_shdr.s_shdr32; else src.d_buf = &scn->s_shdr.s_shdr64; dst.d_size = fsz; dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz; if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == NULL) return ((off_t) -1); } - return (ex->ex_start + nscn * fsz); + return ((off_t) (ex->ex_start + nscn * fsz)); } /* * Write out the file image. * * The original file could have been mapped in with an ELF_C_RDWR * command and the application could have added new content or * re-arranged its sections before calling elf_update(). Consequently * its not safe to work `in place' on the original file. So we * malloc() the required space for the updated ELF object and build * the object there and write it out to the underlying file at the * end. Note that the application may have opened the underlying file * in ELF_C_RDWR and only retrieved/modified a few sections. We take * care to avoid translating file sections unnecessarily. * * Gaps in the coverage of the file by the file's sections will be * filled with the fill character set by elf_fill(3). */ static off_t _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) { off_t nrc, rc; - char *newfile; Elf_Scn *scn, *tscn; struct _Elf_Extent *ex; + unsigned char *newfile; assert(e->e_kind == ELF_K_ELF); assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE); assert(e->e_fd >= 0); if ((newfile = malloc((size_t) newsize)) == NULL) { LIBELF_SET_ERROR(RESOURCE, errno); return ((off_t) -1); } nrc = rc = 0; SLIST_FOREACH(ex, extents, ex_next) { /* Fill inter-extent gaps. */ if (ex->ex_start > (size_t) rc) (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar), - ex->ex_start - rc); + (size_t) (ex->ex_start - (uint64_t) rc)); switch (ex->ex_type) { case ELF_EXTENT_EHDR: if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0) goto error; break; case ELF_EXTENT_PHDR: if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0) goto error; break; case ELF_EXTENT_SECTION: if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0) goto error; break; case ELF_EXTENT_SHDR: if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0) goto error; break; default: assert(0); break; } assert(ex->ex_start + ex->ex_size == (size_t) nrc); assert(rc < nrc); rc = nrc; } assert(rc == newsize); /* * For regular files, throw away existing file content and * unmap any existing mappings. */ if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) { if (ftruncate(e->e_fd, (off_t) 0) < 0 || lseek(e->e_fd, (off_t) 0, SEEK_SET)) { LIBELF_SET_ERROR(IO, errno); goto error; } #if ELFTC_HAVE_MMAP if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { assert(e->e_rawfile != NULL); assert(e->e_cmd == ELF_C_RDWR); if (munmap(e->e_rawfile, e->e_rawsize) < 0) { LIBELF_SET_ERROR(IO, errno); goto error; } } #endif } /* * Write out the new contents. */ if (write(e->e_fd, newfile, (size_t) newsize) != newsize) { LIBELF_SET_ERROR(IO, errno); goto error; } /* * For files opened in ELF_C_RDWR mode, set up the new 'raw' * contents. */ if (e->e_cmd == ELF_C_RDWR) { assert(e->e_rawfile != NULL); assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) || (e->e_flags & LIBELF_F_RAWFILE_MMAP)); if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) { free(e->e_rawfile); e->e_rawfile = newfile; newfile = NULL; } #if ELFTC_HAVE_MMAP else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) { if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) { LIBELF_SET_ERROR(IO, errno); goto error; } } #endif /* ELFTC_HAVE_MMAP */ /* Record the new size of the file. */ - e->e_rawsize = newsize; + e->e_rawsize = (size_t) newsize; } else { /* File opened in ELF_C_WRITE mode. */ assert(e->e_rawfile == NULL); } /* * Reset flags, remove existing section descriptors and * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr() * and elf_getscn() will function correctly. */ e->e_flags &= ~ELF_F_DIRTY; STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn) _libelf_release_scn(scn); if (e->e_class == ELFCLASS32) { free(e->e_u.e_elf.e_ehdr.e_ehdr32); if (e->e_u.e_elf.e_phdr.e_phdr32) free(e->e_u.e_elf.e_phdr.e_phdr32); e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL; e->e_u.e_elf.e_phdr.e_phdr32 = NULL; } else { free(e->e_u.e_elf.e_ehdr.e_ehdr64); if (e->e_u.e_elf.e_phdr.e_phdr64) free(e->e_u.e_elf.e_phdr.e_phdr64); e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL; e->e_u.e_elf.e_phdr.e_phdr64 = NULL; } /* Free the temporary buffer. */ if (newfile) free(newfile); return (rc); error: free(newfile); return ((off_t) -1); } /* * Update an ELF object. */ off_t elf_update(Elf *e, Elf_Cmd c) { int ec; off_t rc; struct _Elf_Extent_List extents; rc = (off_t) -1; if (e == NULL || e->e_kind != ELF_K_ELF || (c != ELF_C_NULL && c != ELF_C_WRITE)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (rc); } if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { LIBELF_SET_ERROR(CLASS, 0); return (rc); } if (e->e_version == EV_NONE) e->e_version = EV_CURRENT; if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) { LIBELF_SET_ERROR(MODE, 0); return (rc); } SLIST_INIT(&extents); if ((rc = _libelf_resync_elf(e, &extents)) < 0) goto done; if (c == ELF_C_NULL) goto done; if (e->e_fd < 0) { rc = (off_t) -1; LIBELF_SET_ERROR(SEQUENCE, 0); goto done; } rc = _libelf_write_elf(e, rc, &extents); done: _libelf_release_extents(&extents); return (rc); } diff --git a/libelf/gelf_cap.c b/libelf/gelf_cap.c index a1c1417be1fa..9925d1bd214f 100644 --- a/libelf/gelf_cap.c +++ b/libelf/gelf_cap.c @@ -1,151 +1,151 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_cap.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_cap.c 2995 2014-03-18 02:16:31Z jkoshy $"); GElf_Cap * gelf_getcap(Elf_Data *ed, int ndx, GElf_Cap *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; Elf32_Cap *cap32; Elf64_Cap *cap64; uint32_t sh_type; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_CAP) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_CAP, ec, e->e_version); assert(msz > 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { cap32 = (Elf32_Cap *) d->d_data.d_buf + ndx; dst->c_tag = cap32->c_tag; dst->c_un.c_val = (Elf64_Xword) cap32->c_un.c_val; } else { cap64 = (Elf64_Cap *) d->d_data.d_buf + ndx; *dst = *cap64; } return (dst); } int gelf_update_cap(Elf_Data *ed, int ndx, GElf_Cap *gc) { int ec; Elf *e; size_t msz; Elf_Scn *scn; Elf32_Cap *cap32; Elf64_Cap *cap64; uint32_t sh_type; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || gc == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_CAP) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_CAP, ec, e->e_version); assert(msz > 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { cap32 = (Elf32_Cap *) d->d_data.d_buf + ndx; LIBELF_COPY_U32(cap32, gc, c_tag); LIBELF_COPY_U32(cap32, gc, c_un.c_val); } else { cap64 = (Elf64_Cap *) d->d_data.d_buf + ndx; *cap64 = *gc; } return (1); } diff --git a/libelf/gelf_dyn.c b/libelf/gelf_dyn.c index 263102603397..4e09afd12ce2 100644 --- a/libelf/gelf_dyn.c +++ b/libelf/gelf_dyn.c @@ -1,150 +1,153 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_dyn.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_dyn.c 2998 2014-03-18 17:19:00Z jkoshy $"); GElf_Dyn * gelf_getdyn(Elf_Data *ed, int ndx, GElf_Dyn *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; Elf32_Dyn *dyn32; Elf64_Dyn *dyn64; uint32_t sh_type; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_DYN) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_DYN, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { dyn32 = (Elf32_Dyn *) d->d_data.d_buf + ndx; dst->d_tag = dyn32->d_tag; dst->d_un.d_val = (Elf64_Xword) dyn32->d_un.d_val; } else { dyn64 = (Elf64_Dyn *) d->d_data.d_buf + ndx; *dst = *dyn64; } return (dst); } int gelf_update_dyn(Elf_Data *ed, int ndx, GElf_Dyn *ds) { int ec; Elf *e; size_t msz; Elf_Scn *scn; Elf32_Dyn *dyn32; Elf64_Dyn *dyn64; uint32_t sh_type; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || ds == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_DYN) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_DYN, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { dyn32 = (Elf32_Dyn *) d->d_data.d_buf + ndx; LIBELF_COPY_S32(dyn32, ds, d_tag); LIBELF_COPY_U32(dyn32, ds, d_un.d_val); } else { dyn64 = (Elf64_Dyn *) d->d_data.d_buf + ndx; *dyn64 = *ds; } return (1); } diff --git a/libelf/gelf_move.c b/libelf/gelf_move.c index d9e8993deee4..2b734eba53b8 100644 --- a/libelf/gelf_move.c +++ b/libelf/gelf_move.c @@ -1,157 +1,160 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_move.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_move.c 2998 2014-03-18 17:19:00Z jkoshy $"); GElf_Move * gelf_getmove(Elf_Data *ed, int ndx, GElf_Move *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Move *move32; Elf64_Move *move64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_MOVE) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { move32 = (Elf32_Move *) d->d_data.d_buf + ndx; dst->m_value = move32->m_value; dst->m_info = (Elf64_Xword) move32->m_info; dst->m_poffset = (Elf64_Xword) move32->m_poffset; dst->m_repeat = move32->m_repeat; dst->m_stride = move32->m_stride; } else { move64 = (Elf64_Move *) d->d_data.d_buf + ndx; *dst = *move64; } return (dst); } int gelf_update_move(Elf_Data *ed, int ndx, GElf_Move *gm) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Move *move32; Elf64_Move *move64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || gm == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_MOVE) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_MOVE, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { move32 = (Elf32_Move *) d->d_data.d_buf + ndx; move32->m_value = gm->m_value; LIBELF_COPY_U32(move32, gm, m_info); LIBELF_COPY_U32(move32, gm, m_poffset); move32->m_repeat = gm->m_repeat; move32->m_stride = gm->m_stride; } else { move64 = (Elf64_Move *) d->d_data.d_buf + ndx; *move64 = *gm; } return (1); } diff --git a/libelf/gelf_rel.c b/libelf/gelf_rel.c index eb057177d4cc..3b798c042201 100644 --- a/libelf/gelf_rel.c +++ b/libelf/gelf_rel.c @@ -1,159 +1,163 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_rel.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_rel.c 2998 2014-03-18 17:19:00Z jkoshy $"); GElf_Rel * gelf_getrel(Elf_Data *ed, int ndx, GElf_Rel *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Rel *rel32; Elf64_Rel *rel64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_REL, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { rel32 = (Elf32_Rel *) d->d_data.d_buf + ndx; dst->r_offset = (Elf64_Addr) rel32->r_offset; dst->r_info = ELF64_R_INFO( (Elf64_Xword) ELF32_R_SYM(rel32->r_info), ELF32_R_TYPE(rel32->r_info)); } else { rel64 = (Elf64_Rel *) d->d_data.d_buf + ndx; *dst = *rel64; } return (dst); } int gelf_update_rel(Elf_Data *ed, int ndx, GElf_Rel *dr) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Rel *rel32; Elf64_Rel *rel64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dr == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_REL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_REL, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { rel32 = (Elf32_Rel *) d->d_data.d_buf + ndx; LIBELF_COPY_U32(rel32, dr, r_offset); if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) || ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) { LIBELF_SET_ERROR(RANGE, 0); return (0); } - rel32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info), - ELF64_R_TYPE(dr->r_info)); + rel32->r_info = ELF32_R_INFO( + (Elf32_Word) ELF64_R_SYM(dr->r_info), + (Elf32_Word) ELF64_R_TYPE(dr->r_info)); } else { rel64 = (Elf64_Rel *) d->d_data.d_buf + ndx; *rel64 = *dr; } return (1); } diff --git a/libelf/gelf_rela.c b/libelf/gelf_rela.c index cb61bdc2e2df..ed289a674d1f 100644 --- a/libelf/gelf_rela.c +++ b/libelf/gelf_rela.c @@ -1,162 +1,166 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_rela.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_rela.c 2998 2014-03-18 17:19:00Z jkoshy $"); GElf_Rela * gelf_getrela(Elf_Data *ed, int ndx, GElf_Rela *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Rela *rela32; Elf64_Rela *rela64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_RELA, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { rela32 = (Elf32_Rela *) d->d_data.d_buf + ndx; dst->r_offset = (Elf64_Addr) rela32->r_offset; dst->r_info = ELF64_R_INFO( (Elf64_Xword) ELF32_R_SYM(rela32->r_info), ELF32_R_TYPE(rela32->r_info)); dst->r_addend = (Elf64_Sxword) rela32->r_addend; } else { rela64 = (Elf64_Rela *) d->d_data.d_buf + ndx; *dst = *rela64; } return (dst); } int gelf_update_rela(Elf_Data *ed, int ndx, GElf_Rela *dr) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Rela *rela32; Elf64_Rela *rela64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dr == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_RELA, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { rela32 = (Elf32_Rela *) d->d_data.d_buf + ndx; LIBELF_COPY_U32(rela32, dr, r_offset); if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) || ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) { LIBELF_SET_ERROR(RANGE, 0); return (0); } - rela32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info), - ELF64_R_TYPE(dr->r_info)); + rela32->r_info = ELF32_R_INFO( + (Elf32_Word) ELF64_R_SYM(dr->r_info), + (Elf32_Word) ELF64_R_TYPE(dr->r_info)); LIBELF_COPY_S32(rela32, dr, r_addend); } else { rela64 = (Elf64_Rela *) d->d_data.d_buf + ndx; *rela64 = *dr; } return (1); } diff --git a/libelf/gelf_sym.c b/libelf/gelf_sym.c index 4a490d9ee079..e32a1869cea7 100644 --- a/libelf/gelf_sym.c +++ b/libelf/gelf_sym.c @@ -1,160 +1,160 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_sym.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_sym.c 2999 2014-03-18 17:19:06Z jkoshy $"); GElf_Sym * gelf_getsym(Elf_Data *ed, int ndx, GElf_Sym *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Sym *sym32; Elf64_Sym *sym64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_SYM, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { - sym32 = (Elf32_Sym *) d->d_data.d_buf + ndx; dst->st_name = sym32->st_name; dst->st_value = (Elf64_Addr) sym32->st_value; dst->st_size = (Elf64_Xword) sym32->st_size; - dst->st_info = ELF64_ST_INFO(ELF32_ST_BIND(sym32->st_info), - ELF32_ST_TYPE(sym32->st_info)); + dst->st_info = sym32->st_info; dst->st_other = sym32->st_other; dst->st_shndx = sym32->st_shndx; } else { - sym64 = (Elf64_Sym *) d->d_data.d_buf + ndx; *dst = *sym64; } return (dst); } int gelf_update_sym(Elf_Data *ed, int ndx, GElf_Sym *gs) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Sym *sym32; Elf64_Sym *sym64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || gs == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_SYM, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { sym32 = (Elf32_Sym *) d->d_data.d_buf + ndx; sym32->st_name = gs->st_name; sym32->st_info = gs->st_info; sym32->st_other = gs->st_other; sym32->st_shndx = gs->st_shndx; LIBELF_COPY_U32(sym32, gs, st_value); LIBELF_COPY_U32(sym32, gs, st_size); } else { sym64 = (Elf64_Sym *) d->d_data.d_buf + ndx; *sym64 = *gs; } return (1); } diff --git a/libelf/gelf_syminfo.c b/libelf/gelf_syminfo.c index bb2063d9a2d4..e54258292aa1 100644 --- a/libelf/gelf_syminfo.c +++ b/libelf/gelf_syminfo.c @@ -1,151 +1,154 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_syminfo.c 2272 2011-12-03 17:07:31Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_syminfo.c 2998 2014-03-18 17:19:00Z jkoshy $"); GElf_Syminfo * gelf_getsyminfo(Elf_Data *ed, int ndx, GElf_Syminfo *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; struct _Libelf_Data *d; Elf32_Syminfo *syminfo32; Elf64_Syminfo *syminfo64; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_SYMINFO) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { syminfo32 = (Elf32_Syminfo *) d->d_data.d_buf + ndx; dst->si_boundto = syminfo32->si_boundto; dst->si_flags = syminfo32->si_flags; } else { syminfo64 = (Elf64_Syminfo *) d->d_data.d_buf + ndx; *dst = *syminfo64; } return (dst); } int gelf_update_syminfo(Elf_Data *ed, int ndx, GElf_Syminfo *gs) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; struct _Libelf_Data *d; Elf32_Syminfo *syminfo32; Elf64_Syminfo *syminfo64; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || gs == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_SYMINFO) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_SYMINFO, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= d->d_data.d_size) { + if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { syminfo32 = (Elf32_Syminfo *) d->d_data.d_buf + ndx; syminfo32->si_boundto = gs->si_boundto; syminfo32->si_flags = gs->si_flags; } else { syminfo64 = (Elf64_Syminfo *) d->d_data.d_buf + ndx; *syminfo64 = *gs; } return (1); } diff --git a/libelf/gelf_symshndx.c b/libelf/gelf_symshndx.c index 9cf3b7578183..69fabe55ce03 100644 --- a/libelf/gelf_symshndx.c +++ b/libelf/gelf_symshndx.c @@ -1,136 +1,139 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: gelf_symshndx.c 2283 2011-12-04 04:07:24Z jkoshy $"); +ELFTC_VCSID("$Id: gelf_symshndx.c 2998 2014-03-18 17:19:00Z jkoshy $"); GElf_Sym * gelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst, Elf32_Word *shindex) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; struct _Libelf_Data *ld, *lid; ld = (struct _Libelf_Data *) d; lid = (struct _Libelf_Data *) id; if (gelf_getsym(d, ndx, dst) == 0) return (NULL); if (lid == NULL || (scn = lid->d_scn) == NULL || (e = scn->s_elf) == NULL || (e != ld->d_scn->s_elf) || shindex == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD || id->d_type != ELF_T_WORD) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_WORD, ec, e->e_version); assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= id->d_size) { + if (msz * (size_t) ndx >= id->d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } *shindex = ((Elf32_Word *) id->d_buf)[ndx]; return (dst); } int gelf_update_symshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *gs, Elf32_Word xindex) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; struct _Libelf_Data *ld, *lid; ld = (struct _Libelf_Data *) d; lid = (struct _Libelf_Data *) id; if (gelf_update_sym(d, ndx, gs) == 0) return (0); if (lid == NULL || (scn = lid->d_scn) == NULL || (e = scn->s_elf) == NULL || (e != ld->d_scn->s_elf)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD || d->d_type != ELF_T_WORD) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_WORD, ec, e->e_version); + assert(msz > 0); + assert(ndx >= 0); - if (msz * ndx >= id->d_size) { + if (msz * (size_t) ndx >= id->d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } *(((Elf32_Word *) id->d_buf) + ndx) = xindex; return (1); } diff --git a/libelf/libelf.h b/libelf/libelf.h index d3219d7ce251..41e7224956fc 100644 --- a/libelf/libelf.h +++ b/libelf/libelf.h @@ -1,252 +1,252 @@ /*- * Copyright (c) 2006,2008-2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: libelf.h 2366 2011-12-29 06:12:14Z jkoshy $ + * $Id: libelf.h 2988 2014-03-17 08:51:49Z jkoshy $ */ #ifndef _LIBELF_H_ #define _LIBELF_H_ #include #include /* Library private data structures */ typedef struct _Elf Elf; typedef struct _Elf_Scn Elf_Scn; /* File types */ typedef enum { ELF_K_NONE = 0, ELF_K_AR, /* `ar' archives */ ELF_K_COFF, /* COFF files (unsupported) */ ELF_K_ELF, /* ELF files */ ELF_K_NUM } Elf_Kind; #define ELF_K_FIRST ELF_K_NONE #define ELF_K_LAST ELF_K_NUM /* Data types */ typedef enum { ELF_T_ADDR, ELF_T_BYTE, ELF_T_CAP, ELF_T_DYN, ELF_T_EHDR, ELF_T_HALF, ELF_T_LWORD, ELF_T_MOVE, ELF_T_MOVEP, ELF_T_NOTE, ELF_T_OFF, ELF_T_PHDR, ELF_T_REL, ELF_T_RELA, ELF_T_SHDR, ELF_T_SWORD, ELF_T_SXWORD, ELF_T_SYMINFO, ELF_T_SYM, ELF_T_VDEF, ELF_T_VNEED, ELF_T_WORD, ELF_T_XWORD, ELF_T_GNUHASH, /* GNU style hash tables. */ ELF_T_NUM } Elf_Type; #define ELF_T_FIRST ELF_T_ADDR #define ELF_T_LAST ELF_T_GNUHASH /* Commands */ typedef enum { ELF_C_NULL = 0, ELF_C_CLR, ELF_C_FDDONE, ELF_C_FDREAD, ELF_C_RDWR, ELF_C_READ, ELF_C_SET, ELF_C_WRITE, ELF_C_NUM } Elf_Cmd; #define ELF_C_FIRST ELF_C_NULL #define ELF_C_LAST ELF_C_NUM /* * An `Elf_Data' structure describes data in an * ELF section. */ typedef struct _Elf_Data { /* * `Public' members that are part of the ELF(3) API. */ uint64_t d_align; void *d_buf; uint64_t d_off; uint64_t d_size; Elf_Type d_type; unsigned int d_version; } Elf_Data; /* * An `Elf_Arhdr' structure describes an archive * header. */ typedef struct { time_t ar_date; char *ar_name; /* archive member name */ gid_t ar_gid; mode_t ar_mode; char *ar_rawname; /* 'raw' member name */ size_t ar_size; uid_t ar_uid; /* * Members that are not part of the public API. */ - int ar_flags; + unsigned int ar_flags; } Elf_Arhdr; /* * An `Elf_Arsym' describes an entry in the archive * symbol table. */ typedef struct { off_t as_off; /* byte offset to member's header */ unsigned long as_hash; /* elf_hash() value for name */ char *as_name; /* null terminated symbol name */ } Elf_Arsym; /* * Error numbers. */ enum Elf_Error { ELF_E_NONE, /* No error */ ELF_E_ARCHIVE, /* Malformed ar(1) archive */ ELF_E_ARGUMENT, /* Invalid argument */ ELF_E_CLASS, /* Mismatched ELF class */ ELF_E_DATA, /* Invalid data descriptor */ ELF_E_HEADER, /* Missing or malformed ELF header */ ELF_E_IO, /* I/O error */ ELF_E_LAYOUT, /* Layout constraint violation */ ELF_E_MODE, /* Wrong mode for ELF descriptor */ ELF_E_RANGE, /* Value out of range */ ELF_E_RESOURCE, /* Resource exhaustion */ ELF_E_SECTION, /* Invalid section descriptor */ ELF_E_SEQUENCE, /* API calls out of sequence */ ELF_E_UNIMPL, /* Feature is unimplemented */ ELF_E_VERSION, /* Unknown API version */ ELF_E_NUM /* Max error number */ }; /* * Flags defined by the API. */ #define ELF_F_LAYOUT 0x001U /* application will layout the file */ #define ELF_F_DIRTY 0x002U /* a section or ELF file is dirty */ /* ELF(3) API extensions. */ #define ELF_F_ARCHIVE 0x100U /* archive creation */ #define ELF_F_ARCHIVE_SYSV 0x200U /* SYSV style archive */ __BEGIN_DECLS Elf *elf_begin(int _fd, Elf_Cmd _cmd, Elf *_elf); int elf_cntl(Elf *_elf, Elf_Cmd _cmd); int elf_end(Elf *_elf); const char *elf_errmsg(int _error); int elf_errno(void); void elf_fill(int _fill); unsigned int elf_flagarhdr(Elf_Arhdr *_arh, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagdata(Elf_Data *_data, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagehdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagelf(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagphdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagscn(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagshdr(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags); Elf_Arhdr *elf_getarhdr(Elf *_elf); Elf_Arsym *elf_getarsym(Elf *_elf, size_t *_ptr); off_t elf_getbase(Elf *_elf); Elf_Data *elf_getdata(Elf_Scn *, Elf_Data *); char *elf_getident(Elf *_elf, size_t *_ptr); int elf_getphdrnum(Elf *_elf, size_t *_dst); int elf_getphnum(Elf *_elf, size_t *_dst); /* Deprecated */ Elf_Scn *elf_getscn(Elf *_elf, size_t _index); int elf_getshdrnum(Elf *_elf, size_t *_dst); int elf_getshnum(Elf *_elf, size_t *_dst); /* Deprecated */ int elf_getshdrstrndx(Elf *_elf, size_t *_dst); int elf_getshstrndx(Elf *_elf, size_t *_dst); /* Deprecated */ unsigned long elf_hash(const char *_name); Elf_Kind elf_kind(Elf *_elf); Elf *elf_memory(char *_image, size_t _size); size_t elf_ndxscn(Elf_Scn *_scn); Elf_Data *elf_newdata(Elf_Scn *_scn); Elf_Scn *elf_newscn(Elf *_elf); Elf_Scn *elf_nextscn(Elf *_elf, Elf_Scn *_scn); Elf_Cmd elf_next(Elf *_elf); Elf *elf_open(int _fd); Elf *elf_openmemory(char *_image, size_t _size); off_t elf_rand(Elf *_elf, off_t _off); Elf_Data *elf_rawdata(Elf_Scn *_scn, Elf_Data *_data); char *elf_rawfile(Elf *_elf, size_t *_size); int elf_setshstrndx(Elf *_elf, size_t _shnum); char *elf_strptr(Elf *_elf, size_t _section, size_t _offset); off_t elf_update(Elf *_elf, Elf_Cmd _cmd); unsigned int elf_version(unsigned int _version); long elf32_checksum(Elf *_elf); size_t elf32_fsize(Elf_Type _type, size_t _count, unsigned int _version); Elf32_Ehdr *elf32_getehdr(Elf *_elf); Elf32_Phdr *elf32_getphdr(Elf *_elf); Elf32_Shdr *elf32_getshdr(Elf_Scn *_scn); Elf32_Ehdr *elf32_newehdr(Elf *_elf); Elf32_Phdr *elf32_newphdr(Elf *_elf, size_t _count); Elf_Data *elf32_xlatetof(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); Elf_Data *elf32_xlatetom(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); long elf64_checksum(Elf *_elf); size_t elf64_fsize(Elf_Type _type, size_t _count, unsigned int _version); Elf64_Ehdr *elf64_getehdr(Elf *_elf); Elf64_Phdr *elf64_getphdr(Elf *_elf); Elf64_Shdr *elf64_getshdr(Elf_Scn *_scn); Elf64_Ehdr *elf64_newehdr(Elf *_elf); Elf64_Phdr *elf64_newphdr(Elf *_elf, size_t _count); Elf_Data *elf64_xlatetof(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); Elf_Data *elf64_xlatetom(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); __END_DECLS #endif /* _LIBELF_H_ */ diff --git a/libelf/libelf_align.c b/libelf/libelf_align.c index 9550c5bd49ea..817fd1588565 100644 --- a/libelf/libelf_align.c +++ b/libelf/libelf_align.c @@ -1,137 +1,137 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_align.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_align.c 3006 2014-03-22 08:10:07Z jkoshy $"); struct align { - int a32; - int a64; + unsigned int a32; + unsigned int a64; }; #ifdef __GNUC__ #define MALIGN(N) { \ .a32 = __alignof__(Elf32_##N), \ .a64 = __alignof__(Elf64_##N) \ } #define MALIGN64(V) { \ .a32 = 0, \ .a64 = __alignof__(Elf64_##V) \ } #define MALIGN_WORD() { \ .a32 = __alignof__(int32_t), \ .a64 = __alignof__(int64_t) \ } #else #error Need the __alignof__ builtin. #endif #define UNSUPPORTED() { \ .a32 = 0, \ .a64 = 0 \ } static struct align malign[ELF_T_NUM] = { [ELF_T_ADDR] = MALIGN(Addr), [ELF_T_BYTE] = { .a32 = 1, .a64 = 1 }, [ELF_T_CAP] = MALIGN(Cap), [ELF_T_DYN] = MALIGN(Dyn), [ELF_T_EHDR] = MALIGN(Ehdr), [ELF_T_HALF] = MALIGN(Half), [ELF_T_LWORD] = MALIGN(Lword), [ELF_T_MOVE] = MALIGN(Move), [ELF_T_MOVEP] = UNSUPPORTED(), [ELF_T_NOTE] = MALIGN(Nhdr), [ELF_T_OFF] = MALIGN(Off), [ELF_T_PHDR] = MALIGN(Phdr), [ELF_T_REL] = MALIGN(Rel), [ELF_T_RELA] = MALIGN(Rela), [ELF_T_SHDR] = MALIGN(Shdr), [ELF_T_SWORD] = MALIGN(Sword), [ELF_T_SXWORD] = MALIGN64(Sxword), [ELF_T_SYM] = MALIGN(Sym), [ELF_T_SYMINFO] = MALIGN(Syminfo), [ELF_T_VDEF] = MALIGN(Verdef), [ELF_T_VNEED] = MALIGN(Verneed), [ELF_T_WORD] = MALIGN(Word), [ELF_T_XWORD] = MALIGN64(Xword), [ELF_T_GNUHASH] = MALIGN_WORD() }; -int +unsigned int _libelf_malign(Elf_Type t, int elfclass) { if (t >= ELF_T_NUM || (int) t < 0) return (0); return (elfclass == ELFCLASS32 ? malign[t].a32 : malign[t].a64); } #define FALIGN(A32,A64) { .a32 = (A32), .a64 = (A64) } static struct align falign[ELF_T_NUM] = { [ELF_T_ADDR] = FALIGN(4,8), [ELF_T_BYTE] = FALIGN(1,1), [ELF_T_CAP] = FALIGN(4,8), [ELF_T_DYN] = FALIGN(4,8), [ELF_T_EHDR] = FALIGN(4,8), [ELF_T_HALF] = FALIGN(2,2), [ELF_T_LWORD] = FALIGN(8,8), [ELF_T_MOVE] = FALIGN(8,8), [ELF_T_MOVEP] = UNSUPPORTED(), [ELF_T_NOTE] = FALIGN(4,4), [ELF_T_OFF] = FALIGN(4,8), [ELF_T_PHDR] = FALIGN(4,8), [ELF_T_REL] = FALIGN(4,8), [ELF_T_RELA] = FALIGN(4,8), [ELF_T_SHDR] = FALIGN(4,8), [ELF_T_SWORD] = FALIGN(4,4), [ELF_T_SXWORD] = FALIGN(0,8), [ELF_T_SYM] = FALIGN(4,8), [ELF_T_SYMINFO] = FALIGN(2,2), [ELF_T_VDEF] = FALIGN(4,4), [ELF_T_VNEED] = FALIGN(4,4), [ELF_T_WORD] = FALIGN(4,4), [ELF_T_XWORD] = FALIGN(0,8), [ELF_T_GNUHASH] = FALIGN(4,8) }; -int +unsigned int _libelf_falign(Elf_Type t, int elfclass) { if (t >= ELF_T_NUM || (int) t < 0) return (0); return (elfclass == ELFCLASS32 ? falign[t].a32 : falign[t].a64); } diff --git a/libelf/libelf_ar.c b/libelf/libelf_ar.c index c990d6dc971a..0830dd6fc069 100644 --- a/libelf/libelf_ar.c +++ b/libelf/libelf_ar.c @@ -1,461 +1,468 @@ /*- * Copyright (c) 2006,2008,2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "_libelf.h" #include "_libelf_ar.h" -ELFTC_VCSID("$Id: libelf_ar.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_ar.c 3013 2014-03-23 06:16:59Z jkoshy $"); #define LIBELF_NALLOC_SIZE 16 /* * `ar' archive handling. * * `ar' archives start with signature `ARMAG'. Each archive member is * preceded by a header containing meta-data for the member. This * header is described in (struct ar_hdr). The header always * starts on an even address. File data is padded with "\n" * characters to keep this invariant. * * Special considerations for `ar' archives: * * There are two variants of the `ar' archive format: traditional BSD * and SVR4. These differ in the way long file names are treated, and * in the layout of the archive symbol table. * * The `ar' header only has space for a 16 character file name. * * In the SVR4 format, file names are terminated with a '/', so this * effectively leaves 15 characters for the actual file name. Longer * file names stored in a separate 'string table' and referenced * indirectly from the name field. The string table itself appears as * an archive member with name "// ". An `indirect' file name in an * `ar' header matches the pattern "/[0-9]*". The digits form a * decimal number that corresponds to a byte offset into the string * table where the actual file name of the object starts. Strings in * the string table are padded to start on even addresses. * * In the BSD format, file names can be upto 16 characters. File * names shorter than 16 characters are padded to 16 characters using * (ASCII) space characters. File names with embedded spaces and file * names longer than 16 characters are stored immediately after the * archive header and the name field set to a special indirect name * matching the pattern "#1/[0-9]+". The digits form a decimal number * that corresponds to the actual length of the file name following * the archive header. The content of the archive member immediately * follows the file name, and the size field of the archive member * holds the sum of the sizes of the member and of the appended file * name. * * Archives may also have a symbol table (see ranlib(1)), mapping * program symbols to object files inside the archive. * * In the SVR4 format, a symbol table uses a file name of "/ " in its * archive header. The symbol table is structured as: * - a 4-byte count of entries stored as a binary value, MSB first * - 'n' 4-byte offsets, stored as binary values, MSB first * - 'n' NUL-terminated strings, for ELF symbol names, stored unpadded. * * In the BSD format, the symbol table uses a file name of "__.SYMDEF". * It is structured as two parts: * - The first part is an array of "ranlib" structures preceded by * the size of the array in bytes. Each "ranlib" structure * describes one symbol. Each structure contains an offset into * the string table for the symbol name, and a file offset into the * archive for the member defining the symbol. * - The second part is a string table containing NUL-terminated * strings, preceded by the size of the string table in bytes. * * If the symbol table and string table are is present in an archive * they must be the very first objects and in that order. */ /* * Retrieve an archive header descriptor. */ Elf_Arhdr * _libelf_ar_gethdr(Elf *e) { Elf *parent; - char *namelen; Elf_Arhdr *eh; + char *namelen; size_t n, nlen; struct ar_hdr *arh; if ((parent = e->e_parent) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert((e->e_flags & LIBELF_F_AR_HEADER) == 0); arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr; assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG); assert((uintptr_t) arh <= (uintptr_t) parent->e_rawfile + parent->e_rawsize - sizeof(struct ar_hdr)); if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } e->e_hdr.e_arhdr = eh; e->e_flags |= LIBELF_F_AR_HEADER; eh->ar_name = eh->ar_rawname = NULL; if ((eh->ar_name = _libelf_ar_get_translated_name(arh, parent)) == NULL) goto error; if (_libelf_ar_get_number(arh->ar_uid, sizeof(arh->ar_uid), 10, &n) == 0) goto error; eh->ar_uid = (uid_t) n; if (_libelf_ar_get_number(arh->ar_gid, sizeof(arh->ar_gid), 10, &n) == 0) goto error; eh->ar_gid = (gid_t) n; if (_libelf_ar_get_number(arh->ar_mode, sizeof(arh->ar_mode), 8, &n) == 0) goto error; eh->ar_mode = (mode_t) n; if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10, &n) == 0) goto error; /* * Get the true size of the member if extended naming is being used. */ if (IS_EXTENDED_BSD_NAME(arh->ar_name)) { namelen = arh->ar_name + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) - LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nlen) == 0) goto error; n -= nlen; } eh->ar_size = n; if ((eh->ar_rawname = _libelf_ar_get_raw_name(arh)) == NULL) goto error; eh->ar_flags = 0; return (eh); error: if (eh) { if (eh->ar_name) free(eh->ar_name); if (eh->ar_rawname) free(eh->ar_rawname); free(eh); } e->e_flags &= ~LIBELF_F_AR_HEADER; - e->e_hdr.e_rawhdr = (char *) arh; + e->e_hdr.e_rawhdr = (unsigned char *) arh; return (NULL); } Elf * _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf) { Elf *e; - char *member, *namelen; - size_t nsz, sz; off_t next; + size_t nsz, sz; struct ar_hdr *arh; + char *member, *namelen; assert(elf->e_kind == ELF_K_AR); next = elf->e_u.e_ar.e_next; /* * `next' is only set to zero by elf_next() when the last * member of an archive is processed. */ if (next == (off_t) 0) return (NULL); assert((next & 1) == 0); arh = (struct ar_hdr *) (elf->e_rawfile + next); /* * Retrieve the size of the member. */ if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10, &sz) == 0) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } /* * Adjust the size field for members in BSD archives using * extended naming. */ if (IS_EXTENDED_BSD_NAME(arh->ar_name)) { namelen = arh->ar_name + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) - LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nsz) == 0) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } member = (char *) (arh + 1) + nsz; sz -= nsz; } else member = (char *) (arh + 1); - if ((e = elf_memory((char *) member, sz)) == NULL) + if ((e = elf_memory(member, sz)) == NULL) return (NULL); e->e_fd = fd; e->e_cmd = c; - e->e_hdr.e_rawhdr = (char *) arh; + e->e_hdr.e_rawhdr = (unsigned char *) arh; elf->e_u.e_ar.e_nchildren++; e->e_parent = elf; return (e); } /* * A BSD-style ar(1) symbol table has the following layout: * * - A count of bytes used by the following array of 'ranlib' * structures, stored as a 'long'. * - An array of 'ranlib' structures. Each array element is * two 'long's in size. * - A count of bytes used for the following symbol table. * - The symbol table itself. */ /* - * A helper macro to read in a 'long' value from the archive. We use - * memcpy() since the source pointer may be misaligned with respect to - * the natural alignment for a C 'long'. + * A helper macro to read in a 'long' value from the archive. + * + * We use memcpy() since the source pointer may be misaligned with + * respect to the natural alignment for a C 'long'. */ #define GET_LONG(P, V)do { \ memcpy(&(V), (P), sizeof(long)); \ (P) += sizeof(long); \ } while (0) Elf_Arsym * _libelf_ar_process_bsd_symtab(Elf *e, size_t *count) { Elf_Arsym *symtab, *sym; + unsigned int n, nentries; unsigned char *end, *p, *p0, *s, *s0; - const unsigned int entrysize = 2 * sizeof(long); - long arraysize, fileoffset, n, nentries, stroffset, strtabsize; + const size_t entrysize = 2 * sizeof(long); + long arraysize, fileoffset, stroffset, strtabsize; assert(e != NULL); assert(count != NULL); assert(e->e_u.e_ar.e_symtab == NULL); symtab = NULL; /* * The BSD symbol table always contains the count fields even * if there are no entries in it. */ if (e->e_u.e_ar.e_rawsymtabsz < 2 * sizeof(long)) goto symtaberror; p = p0 = (unsigned char *) e->e_u.e_ar.e_rawsymtab; end = p0 + e->e_u.e_ar.e_rawsymtabsz; /* * Retrieve the size of the array of ranlib descriptors and * check it for validity. */ GET_LONG(p, arraysize); - if (p0 + arraysize >= end || (arraysize % entrysize != 0)) + if (arraysize < 0 || p0 + arraysize >= end || + ((size_t) arraysize % entrysize != 0)) goto symtaberror; /* * Check the value of the string table size. */ s = p + arraysize; GET_LONG(s, strtabsize); s0 = s; /* Start of string table. */ - if (s0 + strtabsize > end) + if (strtabsize < 0 || s0 + strtabsize > end) goto symtaberror; - nentries = arraysize / entrysize; + nentries = (size_t) arraysize / entrysize; /* * Allocate space for the returned Elf_Arsym array. */ if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries + 1))) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } /* Read in symbol table entries. */ for (n = 0, sym = symtab; n < nentries; n++, sym++) { GET_LONG(p, stroffset); GET_LONG(p, fileoffset); + if (stroffset < 0 || fileoffset < 0 || + (size_t) fileoffset >= e->e_rawsize) + goto symtaberror; + s = s0 + stroffset; if (s >= end) goto symtaberror; - sym->as_off = fileoffset; + sym->as_off = (off_t) fileoffset; sym->as_hash = elf_hash((char *) s); sym->as_name = (char *) s; } /* Fill up the sentinel entry. */ sym->as_name = NULL; sym->as_hash = ~0UL; sym->as_off = (off_t) 0; /* Remember the processed symbol table. */ e->e_u.e_ar.e_symtab = symtab; *count = e->e_u.e_ar.e_symtabsz = nentries + 1; return (symtab); symtaberror: if (symtab) free(symtab); LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } /* * An SVR4-style ar(1) symbol table has the following layout: * * - The first 4 bytes are a binary count of the number of entries in the * symbol table, stored MSB-first. * - Then there are 'n' 4-byte binary offsets, also stored MSB first. * - Following this, there are 'n' null-terminated strings. */ #define GET_WORD(P, V) do { \ (V) = 0; \ (V) = (P)[0]; (V) <<= 8; \ (V) += (P)[1]; (V) <<= 8; \ (V) += (P)[2]; (V) <<= 8; \ (V) += (P)[3]; \ } while (0) #define INTSZ 4 Elf_Arsym * _libelf_ar_process_svr4_symtab(Elf *e, size_t *count) { - size_t n, nentries, off; + uint32_t off; + size_t n, nentries; Elf_Arsym *symtab, *sym; unsigned char *p, *s, *end; assert(e != NULL); assert(count != NULL); assert(e->e_u.e_ar.e_symtab == NULL); symtab = NULL; if (e->e_u.e_ar.e_rawsymtabsz < INTSZ) goto symtaberror; p = (unsigned char *) e->e_u.e_ar.e_rawsymtab; end = p + e->e_u.e_ar.e_rawsymtabsz; GET_WORD(p, nentries); p += INTSZ; if (nentries == 0 || p + nentries * INTSZ >= end) goto symtaberror; /* Allocate space for a nentries + a sentinel. */ if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries+1))) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } s = p + (nentries * INTSZ); /* start of the string table. */ for (n = nentries, sym = symtab; n > 0; n--) { - if (s >= end) goto symtaberror; - off = 0; - GET_WORD(p, off); + if (off >= e->e_rawsize) + goto symtaberror; - sym->as_off = off; + sym->as_off = (off_t) off; sym->as_hash = elf_hash((char *) s); sym->as_name = (char *) s; p += INTSZ; sym++; for (; s < end && *s++ != '\0';) /* skip to next string */ ; } /* Fill up the sentinel entry. */ sym->as_name = NULL; sym->as_hash = ~0UL; sym->as_off = (off_t) 0; *count = e->e_u.e_ar.e_symtabsz = nentries + 1; e->e_u.e_ar.e_symtab = symtab; return (symtab); symtaberror: if (symtab) free(symtab); LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } diff --git a/libelf/libelf_ar_util.c b/libelf/libelf_ar_util.c index 958fbbf49022..7e6ec4068f69 100644 --- a/libelf/libelf_ar_util.c +++ b/libelf/libelf_ar_util.c @@ -1,359 +1,362 @@ /*- * Copyright (c) 2006,2009,2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "_libelf.h" #include "_libelf_ar.h" -ELFTC_VCSID("$Id: libelf_ar_util.c 2365 2011-12-29 04:36:44Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_ar_util.c 3013 2014-03-23 06:16:59Z jkoshy $"); /* * Convert a string bounded by `start' and `start+sz' (exclusive) to a * number in the specified base. */ int -_libelf_ar_get_number(const char *s, size_t sz, int base, size_t *ret) +_libelf_ar_get_number(const char *src, size_t sz, unsigned int base, + size_t *ret) { - int c, v; size_t r; - const char *e; + unsigned int c, v; + const unsigned char *e, *s; assert(base <= 10); + s = (const unsigned char *) src; e = s + sz; /* skip leading blanks */ for (;s < e && (c = *s) == ' '; s++) ; r = 0L; for (;s < e; s++) { if ((c = *s) == ' ') break; if (c < '0' || c > '9') return (0); v = c - '0'; if (v >= base) /* Illegal digit. */ break; r *= base; r += v; } *ret = r; return (1); } /* * Return the translated name for an archive member. */ char * _libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar) { - char c, *s; + char *s; + unsigned char c; size_t len, offset; - const char *buf, *p, *q, *r; + const unsigned char *buf, *p, *q, *r; const size_t bufsize = sizeof(arh->ar_name); assert(arh != NULL); assert(ar->e_kind == ELF_K_AR); - assert((const char *) arh >= ar->e_rawfile && - (const char *) arh < ar->e_rawfile + ar->e_rawsize); + assert((const unsigned char *) arh >= ar->e_rawfile && + (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize); - buf = arh->ar_name; + buf = (const unsigned char *) arh->ar_name; /* * Check for extended naming. * * If the name matches the pattern "^/[0-9]+", it is an * SVR4-style extended name. If the name matches the pattern * "#1/[0-9]+", the entry uses BSD style extended naming. */ if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { /* * The value in field ar_name is a decimal offset into * the archive string table where the actual name * resides. */ - if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10, - &offset) == 0) { + if (_libelf_ar_get_number((const char *) (buf + 1), + bufsize - 1, 10, &offset) == 0) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } if (offset > ar->e_u.e_ar.e_rawstrtabsz) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } p = q = ar->e_u.e_ar.e_rawstrtab + offset; r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz; for (; p < r && *p != '/'; p++) ; - len = p - q + 1; /* space for the trailing NUL */ + len = (size_t) (p - q + 1); /* space for the trailing NUL */ if ((s = malloc(len)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } - (void) strncpy(s, q, len - 1); + (void) strncpy(s, (const char *) q, len - 1); s[len - 1] = '\0'; return (s); } else if (IS_EXTENDED_BSD_NAME(buf)) { r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; - if (_libelf_ar_get_number(r, bufsize - + if (_libelf_ar_get_number((const char *) r, bufsize - LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &len) == 0) { LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } /* * Allocate space for the file name plus a * trailing NUL. */ if ((s = malloc(len + 1)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } /* * The file name follows the archive header. */ - q = (const char *) (arh + 1); + q = (const unsigned char *) (arh + 1); - (void) strncpy(s, q, len); + (void) strncpy(s, (const char *) q, len); s[len] = '\0'; return (s); } /* * A 'normal' name. * * Skip back over trailing blanks from the end of the field. * In the SVR4 format, a '/' is used as a terminator for * non-special names. */ for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) ; if (q >= buf) { if (*q == '/') { /* * SVR4 style names: ignore the trailing * character '/', but only if the name is not * one of the special names "/" and "//". */ if (q > buf + 1 || (q == (buf + 1) && *buf != '/')) q--; } - len = q - buf + 2; /* Add space for a trailing NUL. */ + len = (size_t) (q - buf + 2); /* Space for a trailing NUL. */ } else { /* The buffer only had blanks. */ - buf = ""; + buf = (const unsigned char *) ""; len = 1; } if ((s = malloc(len)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } - (void) strncpy(s, buf, len - 1); + (void) strncpy(s, (const char *) buf, len - 1); s[len - 1] = '\0'; return (s); } /* * Return the raw name for an archive member, inclusive of any * formatting characters. */ char * _libelf_ar_get_raw_name(const struct ar_hdr *arh) { char *rawname; const size_t namesz = sizeof(arh->ar_name); if ((rawname = malloc(namesz + 1)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } (void) strncpy(rawname, arh->ar_name, namesz); rawname[namesz] = '\0'; return (rawname); } /* * Open an 'ar' archive. */ Elf * _libelf_ar_open(Elf *e, int reporterror) { size_t sz; int scanahead; - char *s, *end; struct ar_hdr arh; + unsigned char *s, *end; _libelf_init_elf(e, ELF_K_AR); e->e_u.e_ar.e_nchildren = 0; e->e_u.e_ar.e_next = (off_t) -1; /* * Look for special members. */ s = e->e_rawfile + SARMAG; end = e->e_rawfile + e->e_rawsize; assert(e->e_rawsize > 0); /* * We use heuristics to determine the flavor of the archive we * are examining. * * SVR4 flavor archives use the name "/ " and "// " for * special members. * * In BSD flavor archives the symbol table, if present, is the * first archive with name "__.SYMDEF". */ #define READ_AR_HEADER(S, ARH, SZ, END) \ do { \ if ((S) + sizeof((ARH)) > (END)) \ goto error; \ (void) memcpy(&(ARH), (S), sizeof((ARH))); \ if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \ goto error; \ - if (_libelf_ar_get_number((ARH).ar_size, \ + if (_libelf_ar_get_number((char *) (ARH).ar_size, \ sizeof((ARH).ar_size), 10, &(SZ)) == 0) \ goto error; \ } while (0) READ_AR_HEADER(s, arh, sz, end); /* * Handle special archive members for the SVR4 format. */ if (arh.ar_name[0] == '/') { assert(sz > 0); e->e_flags |= LIBELF_F_AR_VARIANT_SVR4; scanahead = 0; /* * The symbol table (file name "/ ") always comes before the * string table (file name "// "). */ if (arh.ar_name[1] == ' ') { /* "/ " => symbol table. */ scanahead = 1; /* The string table to follow. */ s += sizeof(arh); e->e_u.e_ar.e_rawsymtab = s; e->e_u.e_ar.e_rawsymtabsz = sz; sz = LIBELF_ADJUST_AR_SIZE(sz); s += sz; } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { /* "// " => string table for long file names. */ s += sizeof(arh); e->e_u.e_ar.e_rawstrtab = s; e->e_u.e_ar.e_rawstrtabsz = sz; sz = LIBELF_ADJUST_AR_SIZE(sz); s += sz; } /* * If the string table hasn't been seen yet, look for * it in the next member. */ if (scanahead) { READ_AR_HEADER(s, arh, sz, end); /* "// " => string table for long file names. */ if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { s += sizeof(arh); e->e_u.e_ar.e_rawstrtab = s; e->e_u.e_ar.e_rawstrtabsz = sz; sz = LIBELF_ADJUST_AR_SIZE(sz); s += sz; } } } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME, sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) { /* * BSD style archive symbol table. */ s += sizeof(arh); e->e_u.e_ar.e_rawsymtab = s; e->e_u.e_ar.e_rawsymtabsz = sz; sz = LIBELF_ADJUST_AR_SIZE(sz); s += sz; } /* * Update the 'next' offset, so that a subsequent elf_begin() * works as expected. */ e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); return (e); error: if (!reporterror) { e->e_kind = ELF_K_NONE; return (e); } LIBELF_SET_ERROR(ARCHIVE, 0); return (NULL); } diff --git a/libelf/libelf_checksum.c b/libelf/libelf_checksum.c index 8f84aa4d0f05..f05f9a936404 100644 --- a/libelf/libelf_checksum.c +++ b/libelf/libelf_checksum.c @@ -1,100 +1,100 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_checksum.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_checksum.c 3003 2014-03-22 07:43:10Z jkoshy $"); static unsigned long _libelf_sum(unsigned long c, const unsigned char *s, size_t size) { if (s == NULL || size == 0) return (c); while (size--) c += *s++; return (c); } -unsigned long +long _libelf_checksum(Elf *e, int elfclass) { size_t shn; Elf_Scn *scn; Elf_Data *d; unsigned long checksum; GElf_Ehdr eh; GElf_Shdr shdr; if (e == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0L); } if (e->e_class != elfclass) { LIBELF_SET_ERROR(CLASS, 0); return (0L); } if (gelf_getehdr(e, &eh) == NULL) return (0); /* * Iterate over all sections in the ELF file, computing the * checksum along the way. * * The first section is always SHN_UNDEF and can be skipped. * Non-allocatable sections are skipped, as are sections that * could be affected by utilities such as strip(1). */ checksum = 0; for (shn = 1; shn < e->e_u.e_elf.e_nscn; shn++) { if ((scn = elf_getscn(e, shn)) == NULL) return (0); if (gelf_getshdr(scn, &shdr) == NULL) return (0); if ((shdr.sh_flags & SHF_ALLOC) == 0 || shdr.sh_type == SHT_DYNAMIC || shdr.sh_type == SHT_DYNSYM) continue; d = NULL; while ((d = elf_rawdata(scn, d)) != NULL) checksum = _libelf_sum(checksum, - (unsigned char *) d->d_buf, d->d_size); + (unsigned char *) d->d_buf, (size_t) d->d_size); } /* * Return a 16-bit checksum compatible with Solaris. */ - return (((checksum >> 16) & 0xFFFFUL) + (checksum & 0xFFFFUL)); + return (long) (((checksum >> 16) & 0xFFFFUL) + (checksum & 0xFFFFUL)); } diff --git a/libelf/libelf_convert.m4 b/libelf/libelf_convert.m4 index 0e0e4fd8ff35..fc9cf394a24d 100644 --- a/libelf/libelf_convert.m4 +++ b/libelf/libelf_convert.m4 @@ -1,1086 +1,1089 @@ /*- * Copyright (c) 2006-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_convert.m4 2361 2011-12-28 12:03:05Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_convert.m4 3009 2014-03-23 01:49:59Z jkoshy $"); /* WARNING: GENERATED FROM __file__. */ divert(-1) # Generate conversion routines for converting between in-memory and # file representations of Elf data structures. # # These conversions use the type information defined in `elf_types.m4'. include(SRCDIR`/elf_types.m4') # For the purposes of generating conversion code, ELF types may be # classified according to the following characteristics: # # 1. Whether the ELF type can be directly mapped to an integral C # language type. For example, the ELF_T_WORD type maps directly to # a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type. # # 2. Whether the type has word size dependent variants. For example, # ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr, # and the ELF_T_ADDR and ELF_T_OFF types have integral C types that # can be 32- or 64- bit wide. # # 3. Whether the ELF types has a fixed representation or not. For # example, the ELF_T_SYM type has a fixed size file representation, # some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size # representation. # # We use m4 macros to generate conversion code for ELF types that have # a fixed size representation. Conversion functions for the remaining # types are coded by hand. # #* Handling File and Memory Representations # # `In-memory' representations of an Elf data structure use natural # alignments and native byte ordering. This allows pointer arithmetic # and casting to work as expected. On the other hand, the `file' # representation of an ELF data structure could possibly be packed # tighter than its `in-memory' representation, and could be of a # differing byte order. Reading ELF objects that are members of `ar' # archives present an additional complication: `ar' pads file data to # even addresses, so file data structures in an archive member # residing inside an `ar' archive could be at misaligned memory # addresses when brought into memory. # # In summary, casting the `char *' pointers that point to memory # representations (i.e., source pointers for the *_tof() functions and # the destination pointers for the *_tom() functions), is safe, as # these pointers should be correctly aligned for the memory type # already. However, pointers to file representations have to be # treated as being potentially unaligned and no casting can be done. # NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE define(`NOCVT',`define(`NOCVT_'$1,1)') # NOFUNC(TYPE) -- Do not generate a conversion function for TYPE define(`NOFUNC',`define(`NOFUNC_'$1,1)') # IGNORE(TYPE) -- Completely ignore the type. define(`IGNORE',`NOCVT($1)NOFUNC($1)') # Mark ELF types that should not be processed by the M4 macros below. # Types for which we use functions with non-standard names. IGNORE(`BYTE') # Uses a wrapper around memcpy(). IGNORE(`NOTE') # Not a fixed size type. # Types for which we supply hand-coded functions. NOFUNC(`GNUHASH') # A type with complex internal structure. NOFUNC(`VDEF') # See MAKE_VERSION_CONVERTERS below. NOFUNC(`VNEED') # .. # Unimplemented types. IGNORE(`MOVEP') # ELF types that don't exist in a 32-bit world. NOFUNC(`XWORD32') NOFUNC(`SXWORD32') # `Primitive' ELF types are those that are an alias for an integral # type. As they have no internal structure, they can be copied using # a `memcpy()', and byteswapped in straightforward way. # # Mark all ELF types that directly map to integral C types. define(`PRIM_ADDR', 1) define(`PRIM_BYTE', 1) define(`PRIM_HALF', 1) define(`PRIM_LWORD', 1) define(`PRIM_OFF', 1) define(`PRIM_SWORD', 1) define(`PRIM_SXWORD', 1) define(`PRIM_WORD', 1) define(`PRIM_XWORD', 1) # Note the primitive types that are size-dependent. define(`SIZEDEP_ADDR', 1) define(`SIZEDEP_OFF', 1) # Generate conversion functions for primitive types. # # Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE) # `$1': Name of the ELF type. # `$2': C structure name suffix. # `$3': ELF class specifier for types, one of [`32', `64']. # `$4': Additional ELF class specifier, one of [`', `32', `64']. # # Generates a pair of conversion functions. define(`MAKEPRIMFUNCS',` static int -_libelf_cvt_$1$4_tof(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_$1$4_tof(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src; size_t c; (void) dsz; if (!byteswap) { (void) memcpy(dst, src, count * sizeof(*s)); return (1); } for (c = 0; c < count; c++) { t = *s++; SWAP_$1$4(t); WRITE_$1$4(dst,t); } return (1); } static int -_libelf_cvt_$1$4_tom(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_$1$4_tom(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst; size_t c; if (dsz < count * sizeof(Elf$3_$2)) return (0); if (!byteswap) { (void) memcpy(dst, src, count * sizeof(*d)); return (1); } for (c = 0; c < count; c++) { READ_$1$4(src,t); SWAP_$1$4(t); *d++ = t; } return (1); } ') # # Handling composite ELF types # # SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field. define(`SWAP_FIELD', `ifdef(`SIZEDEP_'$2, `SWAP_$2'SZ()`(t.$1); ', `SWAP_$2(t.$1); ')') # SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition. define(`SWAP_MEMBERS', `ifelse($#,1,`/**/', `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')') # SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure. define(`SWAP_STRUCT', `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */ SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') # WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field. define(`WRITE_FIELD', `ifdef(`SIZEDEP_'$2, `WRITE_$2'SZ()`(dst,t.$1); ', `WRITE_$2(dst,t.$1); ')') # WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition. define(`WRITE_MEMBERS', `ifelse($#,1,`/**/', `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')') # WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure. define(`WRITE_STRUCT', `pushdef(`SZ',$2)/* Write an Elf$2_$1 */ WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') # READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field. define(`READ_FIELD', `ifdef(`SIZEDEP_'$2, `READ_$2'SZ()`(s,t.$1); ', `READ_$2(s,t.$1); ')') # READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition. define(`READ_MEMBERS', `ifelse($#,1,`/**/', `READ_FIELD($1)READ_MEMBERS(shift($@))')') # READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure. define(`READ_STRUCT', `pushdef(`SZ',$2)/* Read an Elf$2_$1 */ READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') # MAKECOMPFUNCS -- Generate converters for composite ELF structures. # # When converting data to file representation, the source pointer will # be naturally aligned for a data structure's in-memory # representation. When converting data to memory, the destination # pointer will be similarly aligned. # # For in-place conversions, when converting to file representations, # the source buffer is large enough to hold `file' data. When # converting from file to memory, we need to be careful to work # `backwards', to avoid overwriting unconverted data. # # Macro use: # `$1': Name of the ELF type. # `$2': C structure name suffix. # `$3': ELF class specifier, one of [`', `32', `64'] define(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',` static int -_libelf_cvt_$1$3_tof(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_$1$3_tof(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { Elf$3_$2 t, *s; size_t c; (void) dsz; s = (Elf$3_$2 *) (uintptr_t) src; for (c = 0; c < count; c++) { t = *s++; if (byteswap) { SWAP_STRUCT($2,$3) } WRITE_STRUCT($2,$3) } return (1); } static int -_libelf_cvt_$1$3_tom(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_$1$3_tom(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { - Elf$3_$2 t, *d; - char *s,*s0; + Elf$3_$2 t, *d; + unsigned char *s,*s0; size_t fsz; fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT); d = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1); - s0 = (char *) src + (count - 1) * fsz; + s0 = src + (count - 1) * fsz; if (dsz < count * sizeof(Elf$3_$2)) return (0); while (count--) { s = s0; READ_STRUCT($2,$3) if (byteswap) { SWAP_STRUCT($2,$3) } *d-- = t; s0 -= fsz; } return (1); } ')') # MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE) # # Make type convertor functions from the type definition # of the ELF type: # - Skip convertors marked as `NOFUNC'. # - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate. define(`MAKE_TYPE_CONVERTER', `ifdef(`NOFUNC_'$1,`', `ifdef(`PRIM_'$1, `ifdef(`SIZEDEP_'$1, `MAKEPRIMFUNCS($1,$2,32,32)dnl MAKEPRIMFUNCS($1,$2,64,64)', `MAKEPRIMFUNCS($1,$2,64)')', `MAKECOMPFUNCS($1,$2,32)dnl MAKECOMPFUNCS($1,$2,64)')')') # MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions. define(`MAKE_TYPE_CONVERTERS', `ifelse($#,1,`', `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')') # # Macros to generate entries for the table of convertors. # # CONV(ELFTYPE,SIZE,DIRECTION) # # Generate the name of a convertor function. define(`CONV', `ifdef(`NOFUNC_'$1$2, `.$3$2 = NULL', `ifdef(`PRIM_'$1, `ifdef(`SIZEDEP_'$1, `.$3$2 = _libelf_cvt_$1$2_$3', `.$3$2 = _libelf_cvt_$1_$3')', `.$3$2 = _libelf_cvt_$1$2_$3')')') # CONVERTER_NAME(ELFTYPE) # # Generate the contents of one `struct cvt' instance. define(`CONVERTER_NAME', `ifdef(`NOCVT_'$1,`', ` [ELF_T_$1] = { CONV($1,32,tof), CONV($1,32,tom), CONV($1,64,tof), CONV($1,64,tom) }, ')') # CONVERTER_NAMES(ELFTYPELIST) # # Generate the `struct cvt[]' array. define(`CONVERTER_NAMES', `ifelse($#,1,`', `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')') # # Handling ELF version sections. # # _FSZ(FIELD,BASETYPE) - return the file size for a field. define(`_FSZ', `ifelse($2,`HALF',2, $2,`WORD',4)') # FSZ(STRUCT) - determine the file size of a structure. define(`FSZ', `ifelse($#,1,0, `eval(_FSZ($1) + FSZ(shift($@)))')') # MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion # functions for versioning structures. define(`MAKE_VERSION_CONVERTERS', `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32) MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)') # MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a # conversion function. define(`MAKE_VERSION_CONVERTER',` static int -_libelf_cvt_$1$5_tof(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_$1$5_tof(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { Elf$5_$2 t; Elf$5_$3 a; const size_t verfsz = FSZ(Elf$5_$2_DEF); const size_t auxfsz = FSZ(Elf$5_$3_DEF); const size_t vermsz = sizeof(Elf$5_$2); const size_t auxmsz = sizeof(Elf$5_$3); - char * const dstend = dst + dsz; - char * const srcend = src + count; - char *dtmp, *dstaux, *srcaux; + unsigned char * const dstend = dst + dsz; + unsigned char * const srcend = src + count; + unsigned char *dtmp, *dstaux, *srcaux; Elf$5_Word aux, anext, cnt, vnext; - for (dtmp = dst, vnext = ~0; + for (dtmp = dst, vnext = ~0U; vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend; dtmp += vnext, src += vnext) { /* Read in an Elf$5_$2 structure. */ t = *((Elf$5_$2 *) (uintptr_t) src); aux = t.$4_aux; cnt = t.$4_cnt; vnext = t.$4_next; if (byteswap) { SWAP_STRUCT($2, $5) } dst = dtmp; WRITE_STRUCT($2, $5) if (aux < verfsz) return (0); /* Process AUX entries. */ - for (anext = ~0, dstaux = dtmp + aux, srcaux = src + aux; + for (anext = ~0U, dstaux = dtmp + aux, srcaux = src + aux; cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend && srcaux + auxmsz <= srcend; dstaux += anext, srcaux += anext, cnt--) { /* Read in an Elf$5_$3 structure. */ a = *((Elf$5_$3 *) (uintptr_t) srcaux); anext = a.$4a_next; if (byteswap) { pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t') } dst = dstaux; pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t') } if (anext || cnt) return (0); } if (vnext) return (0); return (1); } static int -_libelf_cvt_$1$5_tom(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_$1$5_tom(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { Elf$5_$2 t, *dp; Elf$5_$3 a, *ap; const size_t verfsz = FSZ(Elf$5_$2_DEF); const size_t auxfsz = FSZ(Elf$5_$3_DEF); const size_t vermsz = sizeof(Elf$5_$2); const size_t auxmsz = sizeof(Elf$5_$3); - char * const dstend = dst + dsz; - char * const srcend = src + count; - char *dstaux, *s, *srcaux, *stmp; + unsigned char * const dstend = dst + dsz; + unsigned char * const srcend = src + count; + unsigned char *dstaux, *s, *srcaux, *stmp; Elf$5_Word aux, anext, cnt, vnext; - for (stmp = src, vnext = ~0; + for (stmp = src, vnext = ~0U; vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend; stmp += vnext, dst += vnext) { /* Read in a $1 structure. */ s = stmp; READ_STRUCT($2, $5) if (byteswap) { SWAP_STRUCT($2, $5) } dp = (Elf$5_$2 *) (uintptr_t) dst; *dp = t; aux = t.$4_aux; cnt = t.$4_cnt; vnext = t.$4_next; if (aux < vermsz) return (0); /* Process AUX entries. */ - for (anext = ~0, dstaux = dst + aux, srcaux = stmp + aux; + for (anext = ~0U, dstaux = dst + aux, srcaux = stmp + aux; cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend && srcaux + auxfsz <= srcend; dstaux += anext, srcaux += anext, cnt--) { s = srcaux; pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t') if (byteswap) { pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t') } anext = a.$4a_next; ap = ((Elf$5_$3 *) (uintptr_t) dstaux); *ap = a; } if (anext || cnt) return (0); } if (vnext) return (0); return (1); }') divert(0) /* * C macros to byte swap integral quantities. */ #define SWAP_BYTE(X) do { (void) (X); } while (0) #define SWAP_IDENT(X) do { (void) (X); } while (0) #define SWAP_HALF(X) do { \ uint16_t _x = (uint16_t) (X); \ - uint16_t _t = _x & 0xFF; \ - _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ - (X) = _t; \ + uint32_t _t = _x & 0xFFU; \ + _t <<= 8U; _x >>= 8U; _t |= _x & 0xFFU; \ + (X) = (uint16_t) _t; \ } while (0) -#define SWAP_WORD(X) do { \ +#define _SWAP_WORD(X, T) do { \ uint32_t _x = (uint32_t) (X); \ uint32_t _t = _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ - (X) = _t; \ + (X) = (T) _t; \ } while (0) -#define SWAP_ADDR32(X) SWAP_WORD(X) -#define SWAP_OFF32(X) SWAP_WORD(X) -#define SWAP_SWORD(X) SWAP_WORD(X) -#define SWAP_WORD64(X) do { \ +#define SWAP_ADDR32(X) _SWAP_WORD(X, Elf32_Addr) +#define SWAP_OFF32(X) _SWAP_WORD(X, Elf32_Off) +#define SWAP_SWORD(X) _SWAP_WORD(X, Elf32_Sword) +#define SWAP_WORD(X) _SWAP_WORD(X, Elf32_Word) +#define _SWAP_WORD64(X, T) do { \ uint64_t _x = (uint64_t) (X); \ uint64_t _t = _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ - (X) = _t; \ + (X) = (T) _t; \ } while (0) -#define SWAP_ADDR64(X) SWAP_WORD64(X) -#define SWAP_LWORD(X) SWAP_WORD64(X) -#define SWAP_OFF64(X) SWAP_WORD64(X) -#define SWAP_SXWORD(X) SWAP_WORD64(X) -#define SWAP_XWORD(X) SWAP_WORD64(X) +#define SWAP_ADDR64(X) _SWAP_WORD64(X, Elf64_Addr) +#define SWAP_LWORD(X) _SWAP_WORD64(X, Elf64_Lword) +#define SWAP_OFF64(X) _SWAP_WORD64(X, Elf64_Off) +#define SWAP_SXWORD(X) _SWAP_WORD64(X, Elf64_Sxword) +#define SWAP_XWORD(X) _SWAP_WORD64(X, Elf64_Xword) /* * C macros to write out various integral values. * * Note: * - The destination pointer could be unaligned. * - Values are written out in native byte order. * - The destination pointer is incremented after the write. */ #define WRITE_BYTE(P,X) do { \ - char *const _p = (char *) (P); \ - _p[0] = (char) (X); \ + unsigned char *const _p = (unsigned char *) (P); \ + _p[0] = (unsigned char) (X); \ (P) = _p + 1; \ } while (0) #define WRITE_HALF(P,X) do { \ uint16_t _t = (X); \ - char *const _p = (char *) (P); \ - const char *const _q = (char *) &_t; \ + unsigned char *const _p = (unsigned char *) (P); \ + const unsigned char *const _q = (unsigned char *) &_t; \ _p[0] = _q[0]; \ _p[1] = _q[1]; \ (P) = _p + 2; \ } while (0) -#define WRITE_WORD(P,X) do { \ - uint32_t _t = (X); \ - char *const _p = (char *) (P); \ - const char *const _q = (char *) &_t; \ +#define WRITE_WORD(P,X) do { \ + uint32_t _t = (uint32_t) (X); \ + unsigned char *const _p = (unsigned char *) (P); \ + const unsigned char *const _q = (unsigned char *) &_t; \ _p[0] = _q[0]; \ _p[1] = _q[1]; \ _p[2] = _q[2]; \ _p[3] = _q[3]; \ (P) = _p + 4; \ } while (0) #define WRITE_ADDR32(P,X) WRITE_WORD(P,X) #define WRITE_OFF32(P,X) WRITE_WORD(P,X) #define WRITE_SWORD(P,X) WRITE_WORD(P,X) #define WRITE_WORD64(P,X) do { \ - uint64_t _t = (X); \ - char *const _p = (char *) (P); \ - const char *const _q = (char *) &_t; \ + uint64_t _t = (uint64_t) (X); \ + unsigned char *const _p = (unsigned char *) (P); \ + const unsigned char *const _q = (unsigned char *) &_t; \ _p[0] = _q[0]; \ _p[1] = _q[1]; \ _p[2] = _q[2]; \ _p[3] = _q[3]; \ _p[4] = _q[4]; \ _p[5] = _q[5]; \ _p[6] = _q[6]; \ _p[7] = _q[7]; \ (P) = _p + 8; \ } while (0) #define WRITE_ADDR64(P,X) WRITE_WORD64(P,X) #define WRITE_LWORD(P,X) WRITE_WORD64(P,X) #define WRITE_OFF64(P,X) WRITE_WORD64(P,X) #define WRITE_SXWORD(P,X) WRITE_WORD64(P,X) #define WRITE_XWORD(P,X) WRITE_WORD64(P,X) #define WRITE_IDENT(P,X) do { \ (void) memcpy((P), (X), sizeof((X))); \ (P) = (P) + EI_NIDENT; \ } while (0) /* * C macros to read in various integral values. * * Note: * - The source pointer could be unaligned. * - Values are read in native byte order. * - The source pointer is incremented appropriately. */ #define READ_BYTE(P,X) do { \ - const char *const _p = \ - (const char *) (P); \ + const unsigned char *const _p = \ + (const unsigned char *) (P); \ (X) = _p[0]; \ (P) = (P) + 1; \ } while (0) #define READ_HALF(P,X) do { \ uint16_t _t; \ - char *const _q = (char *) &_t; \ - const char *const _p = \ - (const char *) (P); \ + unsigned char *const _q = (unsigned char *) &_t; \ + const unsigned char *const _p = \ + (const unsigned char *) (P); \ _q[0] = _p[0]; \ _q[1] = _p[1]; \ (P) = (P) + 2; \ (X) = _t; \ } while (0) -#define READ_WORD(P,X) do { \ +#define _READ_WORD(P,X,T) do { \ uint32_t _t; \ - char *const _q = (char *) &_t; \ - const char *const _p = \ - (const char *) (P); \ + unsigned char *const _q = (unsigned char *) &_t; \ + const unsigned char *const _p = \ + (const unsigned char *) (P); \ _q[0] = _p[0]; \ _q[1] = _p[1]; \ _q[2] = _p[2]; \ _q[3] = _p[3]; \ (P) = (P) + 4; \ - (X) = _t; \ + (X) = (T) _t; \ } while (0) -#define READ_ADDR32(P,X) READ_WORD(P,X) -#define READ_OFF32(P,X) READ_WORD(P,X) -#define READ_SWORD(P,X) READ_WORD(P,X) -#define READ_WORD64(P,X) do { \ +#define READ_ADDR32(P,X) _READ_WORD(P, X, Elf32_Addr) +#define READ_OFF32(P,X) _READ_WORD(P, X, Elf32_Off) +#define READ_SWORD(P,X) _READ_WORD(P, X, Elf32_Sword) +#define READ_WORD(P,X) _READ_WORD(P, X, Elf32_Word) +#define _READ_WORD64(P,X,T) do { \ uint64_t _t; \ - char *const _q = (char *) &_t; \ - const char *const _p = \ - (const char *) (P); \ + unsigned char *const _q = (unsigned char *) &_t; \ + const unsigned char *const _p = \ + (const unsigned char *) (P); \ _q[0] = _p[0]; \ _q[1] = _p[1]; \ _q[2] = _p[2]; \ _q[3] = _p[3]; \ _q[4] = _p[4]; \ _q[5] = _p[5]; \ _q[6] = _p[6]; \ _q[7] = _p[7]; \ (P) = (P) + 8; \ - (X) = _t; \ + (X) = (T) _t; \ } while (0) -#define READ_ADDR64(P,X) READ_WORD64(P,X) -#define READ_LWORD(P,X) READ_WORD64(P,X) -#define READ_OFF64(P,X) READ_WORD64(P,X) -#define READ_SXWORD(P,X) READ_WORD64(P,X) -#define READ_XWORD(P,X) READ_WORD64(P,X) +#define READ_ADDR64(P,X) _READ_WORD64(P, X, Elf64_Addr) +#define READ_LWORD(P,X) _READ_WORD64(P, X, Elf64_Lword) +#define READ_OFF64(P,X) _READ_WORD64(P, X, Elf64_Off) +#define READ_SXWORD(P,X) _READ_WORD64(P, X, Elf64_Sxword) +#define READ_XWORD(P,X) _READ_WORD64(P, X, Elf64_Xword) #define READ_IDENT(P,X) do { \ (void) memcpy((X), (P), sizeof((X))); \ (P) = (P) + EI_NIDENT; \ } while (0) #define ROUNDUP2(V,N) (V) = ((((V) + (N) - 1)) & ~((N) - 1)) /*[*/ MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST) MAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd) MAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn) /*]*/ /* * Sections of type ELF_T_BYTE are never byteswapped, consequently a * simple memcpy suffices for both directions of conversion. */ static int -_libelf_cvt_BYTE_tox(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_BYTE_tox(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { (void) byteswap; if (dsz < count) return (0); if (dst != src) (void) memcpy(dst, src, count); return (1); } /* * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit * words. Bloom filter data comes next, followed by hash buckets and the * hash chain. * * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit * wide on ELFCLASS32 objects. The other objects in this section are 32 * bits wide. * * Argument `srcsz' denotes the number of bytes to be converted. In the * 32-bit case we need to translate `srcsz' to a count of 32-bit words. */ static int -_libelf_cvt_GNUHASH32_tom(char *dst, size_t dsz, char *src, size_t srcsz, - int byteswap) +_libelf_cvt_GNUHASH32_tom(unsigned char *dst, size_t dsz, unsigned char *src, + size_t srcsz, int byteswap) { return (_libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t), byteswap)); } static int -_libelf_cvt_GNUHASH32_tof(char *dst, size_t dsz, char *src, size_t srcsz, - int byteswap) +_libelf_cvt_GNUHASH32_tof(unsigned char *dst, size_t dsz, unsigned char *src, + size_t srcsz, int byteswap) { return (_libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t), byteswap)); } static int -_libelf_cvt_GNUHASH64_tom(char *dst, size_t dsz, char *src, size_t srcsz, - int byteswap) +_libelf_cvt_GNUHASH64_tom(unsigned char *dst, size_t dsz, unsigned char *src, + size_t srcsz, int byteswap) { size_t sz; uint64_t t64, *bloom64; Elf_GNU_Hash_Header *gh; uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32; uint32_t *buckets, *chains; sz = 4 * sizeof(uint32_t); /* File header is 4 words long. */ if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz) return (0); /* Read in the section header and byteswap if needed. */ READ_WORD(src, nbuckets); READ_WORD(src, symndx); READ_WORD(src, maskwords); READ_WORD(src, shift2); srcsz -= sz; if (byteswap) { SWAP_WORD(nbuckets); SWAP_WORD(symndx); SWAP_WORD(maskwords); SWAP_WORD(shift2); } /* Check source buffer and destination buffer sizes. */ sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t); if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header)) return (0); gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst; gh->gh_nbuckets = nbuckets; gh->gh_symndx = symndx; gh->gh_maskwords = maskwords; gh->gh_shift2 = shift2; dsz -= sizeof(Elf_GNU_Hash_Header); dst += sizeof(Elf_GNU_Hash_Header); bloom64 = (uint64_t *) (uintptr_t) dst; /* Copy bloom filter data. */ for (n = 0; n < maskwords; n++) { READ_XWORD(src, t64); if (byteswap) SWAP_XWORD(t64); bloom64[n] = t64; } /* The hash buckets follows the bloom filter. */ dst += maskwords * sizeof(uint64_t); buckets = (uint32_t *) (uintptr_t) dst; for (n = 0; n < nbuckets; n++) { READ_WORD(src, t32); if (byteswap) SWAP_WORD(t32); buckets[n] = t32; } dst += nbuckets * sizeof(uint32_t); /* The hash chain follows the hash buckets. */ dsz -= sz; srcsz -= sz; if (dsz < srcsz) /* Destination lacks space. */ return (0); nchains = srcsz / sizeof(uint32_t); chains = (uint32_t *) (uintptr_t) dst; for (n = 0; n < nchains; n++) { READ_WORD(src, t32); if (byteswap) SWAP_WORD(t32); *chains++ = t32; } return (1); } static int -_libelf_cvt_GNUHASH64_tof(char *dst, size_t dsz, char *src, size_t srcsz, - int byteswap) +_libelf_cvt_GNUHASH64_tof(unsigned char *dst, size_t dsz, unsigned char *src, + size_t srcsz, int byteswap) { uint32_t *s32; size_t sz, hdrsz; uint64_t *s64, t64; Elf_GNU_Hash_Header *gh; uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32; hdrsz = 4 * sizeof(uint32_t); /* Header is 4x32 bits. */ if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header)) return (0); gh = (Elf_GNU_Hash_Header *) (uintptr_t) src; t0 = nbuckets = gh->gh_nbuckets; t1 = gh->gh_symndx; t2 = maskwords = gh->gh_maskwords; t3 = gh->gh_shift2; src += sizeof(Elf_GNU_Hash_Header); srcsz -= sizeof(Elf_GNU_Hash_Header); dsz -= hdrsz; sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords * sizeof(uint64_t); if (srcsz < sz || dsz < sz) return (0); /* Write out the header. */ if (byteswap) { SWAP_WORD(t0); SWAP_WORD(t1); SWAP_WORD(t2); SWAP_WORD(t3); } WRITE_WORD(dst, t0); WRITE_WORD(dst, t1); WRITE_WORD(dst, t2); WRITE_WORD(dst, t3); /* Copy the bloom filter and the hash table. */ s64 = (uint64_t *) (uintptr_t) src; for (n = 0; n < maskwords; n++) { t64 = *s64++; if (byteswap) SWAP_XWORD(t64); WRITE_WORD64(dst, t64); } s32 = (uint32_t *) s64; for (n = 0; n < nbuckets; n++) { t32 = *s32++; if (byteswap) SWAP_WORD(t32); WRITE_WORD(dst, t32); } srcsz -= sz; dsz -= sz; /* Copy out the hash chains. */ if (dsz < srcsz) return (0); nchains = srcsz / sizeof(uint32_t); for (n = 0; n < nchains; n++) { t32 = *s32++; if (byteswap) SWAP_WORD(t32); WRITE_WORD(dst, t32); } return (1); } /* * Elf_Note structures comprise a fixed size header followed by variable * length strings. The fixed size header needs to be byte swapped, but * not the strings. * * Argument `count' denotes the total number of bytes to be converted. * The destination buffer needs to be at least `count' bytes in size. */ static int -_libelf_cvt_NOTE_tom(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_NOTE_tom(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { uint32_t namesz, descsz, type; Elf_Note *en; size_t sz, hdrsz; if (dsz < count) /* Destination buffer is too small. */ return (0); hdrsz = 3 * sizeof(uint32_t); if (count < hdrsz) /* Source too small. */ return (0); if (!byteswap) { (void) memcpy(dst, src, count); return (1); } /* Process all notes in the section. */ while (count > hdrsz) { /* Read the note header. */ READ_WORD(src, namesz); READ_WORD(src, descsz); READ_WORD(src, type); /* Translate. */ SWAP_WORD(namesz); SWAP_WORD(descsz); SWAP_WORD(type); /* Copy out the translated note header. */ en = (Elf_Note *) (uintptr_t) dst; en->n_namesz = namesz; en->n_descsz = descsz; en->n_type = type; dsz -= sizeof(Elf_Note); dst += sizeof(Elf_Note); count -= hdrsz; - ROUNDUP2(namesz, 4); - ROUNDUP2(descsz, 4); + ROUNDUP2(namesz, 4U); + ROUNDUP2(descsz, 4U); sz = namesz + descsz; if (count < sz || dsz < sz) /* Buffers are too small. */ return (0); (void) memcpy(dst, src, sz); src += sz; dst += sz; count -= sz; dsz -= sz; } return (1); } static int -_libelf_cvt_NOTE_tof(char *dst, size_t dsz, char *src, size_t count, - int byteswap) +_libelf_cvt_NOTE_tof(unsigned char *dst, size_t dsz, unsigned char *src, + size_t count, int byteswap) { uint32_t namesz, descsz, type; Elf_Note *en; size_t sz; if (dsz < count) return (0); if (!byteswap) { (void) memcpy(dst, src, count); return (1); } while (count > sizeof(Elf_Note)) { en = (Elf_Note *) (uintptr_t) src; namesz = en->n_namesz; descsz = en->n_descsz; type = en->n_type; SWAP_WORD(namesz); SWAP_WORD(descsz); SWAP_WORD(type); WRITE_WORD(dst, namesz); WRITE_WORD(dst, descsz); WRITE_WORD(dst, type); src += sizeof(Elf_Note); - ROUNDUP2(namesz, 4); - ROUNDUP2(descsz, 4); + ROUNDUP2(namesz, 4U); + ROUNDUP2(descsz, 4U); sz = namesz + descsz; if (count < sz) sz = count; (void) memcpy(dst, src, sz); src += sz; dst += sz; count -= sz; } return (1); } struct converters { - int (*tof32)(char *dst, size_t dsz, char *src, size_t cnt, - int byteswap); - int (*tom32)(char *dst, size_t dsz, char *src, size_t cnt, - int byteswap); - int (*tof64)(char *dst, size_t dsz, char *src, size_t cnt, - int byteswap); - int (*tom64)(char *dst, size_t dsz, char *src, size_t cnt, - int byteswap); + int (*tof32)(unsigned char *dst, size_t dsz, unsigned char *src, + size_t cnt, int byteswap); + int (*tom32)(unsigned char *dst, size_t dsz, unsigned char *src, + size_t cnt, int byteswap); + int (*tof64)(unsigned char *dst, size_t dsz, unsigned char *src, + size_t cnt, int byteswap); + int (*tom64)(unsigned char *dst, size_t dsz, unsigned char *src, + size_t cnt, int byteswap); }; static struct converters cvt[ELF_T_NUM] = { /*[*/ CONVERTER_NAMES(ELF_TYPE_LIST) /*]*/ /* * Types that need hand-coded converters follow. */ [ELF_T_BYTE] = { .tof32 = _libelf_cvt_BYTE_tox, .tom32 = _libelf_cvt_BYTE_tox, .tof64 = _libelf_cvt_BYTE_tox, .tom64 = _libelf_cvt_BYTE_tox }, [ELF_T_NOTE] = { .tof32 = _libelf_cvt_NOTE_tof, .tom32 = _libelf_cvt_NOTE_tom, .tof64 = _libelf_cvt_NOTE_tof, .tom64 = _libelf_cvt_NOTE_tom } }; int (*_libelf_get_translator(Elf_Type t, int direction, int elfclass)) - (char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap) + (unsigned char *_dst, size_t dsz, unsigned char *_src, size_t _cnt, + int _byteswap) { assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); if (t >= ELF_T_NUM || (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) || (direction != ELF_TOFILE && direction != ELF_TOMEMORY)) return (NULL); return ((elfclass == ELFCLASS32) ? (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) : (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64)); } diff --git a/libelf/libelf_data.c b/libelf/libelf_data.c index 809002f71e78..f078c36ab755 100644 --- a/libelf/libelf_data.c +++ b/libelf/libelf_data.c @@ -1,88 +1,103 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_data.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_data.c 3080 2014-07-28 08:46:17Z jkoshy $"); int _libelf_xlate_shtype(uint32_t sht) { + /* + * Look for known section types. + */ switch (sht) { case SHT_DYNAMIC: return (ELF_T_DYN); case SHT_DYNSYM: return (ELF_T_SYM); case SHT_FINI_ARRAY: return (ELF_T_ADDR); case SHT_GNU_HASH: return (ELF_T_GNUHASH); case SHT_GNU_LIBLIST: return (ELF_T_WORD); case SHT_GROUP: return (ELF_T_WORD); case SHT_HASH: return (ELF_T_WORD); case SHT_INIT_ARRAY: return (ELF_T_ADDR); case SHT_NOBITS: return (ELF_T_BYTE); case SHT_NOTE: return (ELF_T_NOTE); case SHT_PREINIT_ARRAY: return (ELF_T_ADDR); case SHT_PROGBITS: return (ELF_T_BYTE); case SHT_REL: return (ELF_T_REL); case SHT_RELA: return (ELF_T_RELA); case SHT_STRTAB: return (ELF_T_BYTE); case SHT_SYMTAB: return (ELF_T_SYM); case SHT_SYMTAB_SHNDX: return (ELF_T_WORD); case SHT_SUNW_dof: return (ELF_T_BYTE); case SHT_SUNW_move: return (ELF_T_MOVE); case SHT_SUNW_syminfo: return (ELF_T_SYMINFO); case SHT_SUNW_verdef: /* == SHT_GNU_verdef */ return (ELF_T_VDEF); case SHT_SUNW_verneed: /* == SHT_GNU_verneed */ return (ELF_T_VNEED); case SHT_SUNW_versym: /* == SHT_GNU_versym */ return (ELF_T_HALF); default: + /* + * Values in the range [SHT_LOOS..SHT_HIUSER] (i.e., + * OS, processor and user-defined section types) are + * legal, but since we do not know anything more about + * their semantics, we return a type of ELF_T_BYTE. + */ + if (sht >= SHT_LOOS && sht <= SHT_HIUSER) + return (ELF_T_BYTE); + + /* + * Other values are unsupported. + */ return (-1); } } diff --git a/libelf/libelf_ehdr.c b/libelf/libelf_ehdr.c index 363a0a834b9f..d59f61f2ba1e 100644 --- a/libelf/libelf_ehdr.c +++ b/libelf/libelf_ehdr.c @@ -1,204 +1,206 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_ehdr.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_ehdr.c 3009 2014-03-23 01:49:59Z jkoshy $"); /* * Retrieve counts for sections, phdrs and the section string table index * from section header #0 of the ELF object. */ static int _libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum, uint16_t strndx) { Elf_Scn *scn; size_t fsz; - int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, + size_t _c, int _swap); uint32_t shtype; assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn)); fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1); assert(fsz > 0); if (e->e_rawsize < shoff + fsz) { /* raw file too small */ LIBELF_SET_ERROR(HEADER, 0); return (0); } if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL) return (0); xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); - (*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr), - e->e_rawfile + shoff, (size_t) 1, + (*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr), + (unsigned char *) e->e_rawfile + shoff, (size_t) 1, e->e_byteorder != LIBELF_PRIVATE(byteorder)); #define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \ scn->s_shdr.s_shdr64.M) if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) { LIBELF_SET_ERROR(SECTION, 0); return (0); } - e->e_u.e_elf.e_nscn = GET_SHDR_MEMBER(sh_size); + e->e_u.e_elf.e_nscn = (size_t) GET_SHDR_MEMBER(sh_size); e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum : GET_SHDR_MEMBER(sh_info); e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx : GET_SHDR_MEMBER(sh_link); #undef GET_SHDR_MEMBER return (1); } #define EHDR_INIT(E,SZ) do { \ Elf##SZ##_Ehdr *eh = (E); \ eh->e_ident[EI_MAG0] = ELFMAG0; \ eh->e_ident[EI_MAG1] = ELFMAG1; \ eh->e_ident[EI_MAG2] = ELFMAG2; \ eh->e_ident[EI_MAG3] = ELFMAG3; \ eh->e_ident[EI_CLASS] = ELFCLASS##SZ; \ eh->e_ident[EI_DATA] = ELFDATANONE; \ - eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version); \ + eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version) & 0xFFU; \ eh->e_machine = EM_NONE; \ eh->e_type = ELF_K_NONE; \ eh->e_version = LIBELF_PRIVATE(version); \ } while (0) void * _libelf_ehdr(Elf *e, int ec, int allocate) { void *ehdr; size_t fsz, msz; uint16_t phnum, shnum, strndx; uint64_t shoff; - int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, + size_t _c, int _swap); assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (e == NULL || e->e_kind != ELF_K_ELF) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (e->e_class != ELFCLASSNONE && e->e_class != ec) { LIBELF_SET_ERROR(CLASS, 0); return (NULL); } if (e->e_version != EV_CURRENT) { LIBELF_SET_ERROR(VERSION, 0); return (NULL); } if (e->e_class == ELFCLASSNONE) e->e_class = ec; if (ec == ELFCLASS32) ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32; else ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64; if (ehdr != NULL) /* already have a translated ehdr */ return (ehdr); fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); assert(fsz > 0); if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) { LIBELF_SET_ERROR(HEADER, 0); return (NULL); } msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT); assert(msz > 0); if ((ehdr = calloc((size_t) 1, msz)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (ec == ELFCLASS32) { e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr; EHDR_INIT(ehdr,32); } else { e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr; EHDR_INIT(ehdr,64); } if (allocate) e->e_flags |= ELF_F_DIRTY; if (e->e_cmd == ELF_C_WRITE) return (ehdr); xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec); - (*xlator)(ehdr, msz, e->e_rawfile, (size_t) 1, + (*xlator)((unsigned char*) ehdr, msz, e->e_rawfile, (size_t) 1, e->e_byteorder != LIBELF_PRIVATE(byteorder)); /* * If extended numbering is being used, read the correct * number of sections and program header entries. */ if (ec == ELFCLASS32) { phnum = ((Elf32_Ehdr *) ehdr)->e_phnum; shnum = ((Elf32_Ehdr *) ehdr)->e_shnum; shoff = ((Elf32_Ehdr *) ehdr)->e_shoff; strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx; } else { phnum = ((Elf64_Ehdr *) ehdr)->e_phnum; shnum = ((Elf64_Ehdr *) ehdr)->e_shnum; shoff = ((Elf64_Ehdr *) ehdr)->e_shoff; strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx; } if (shnum >= SHN_LORESERVE || (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM || strndx == SHN_XINDEX))) { LIBELF_SET_ERROR(HEADER, 0); return (NULL); } if (shnum != 0 || shoff == 0LL) { /* not using extended numbering */ e->e_u.e_elf.e_nphdr = phnum; e->e_u.e_elf.e_nscn = shnum; e->e_u.e_elf.e_strndx = strndx; } else if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0) return (NULL); return (ehdr); } diff --git a/libelf/libelf_extended.c b/libelf/libelf_extended.c index 5343696548d4..f1a77d17efba 100644 --- a/libelf/libelf_extended.c +++ b/libelf/libelf_extended.c @@ -1,136 +1,136 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_extended.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_extended.c 3005 2014-03-22 07:43:25Z jkoshy $"); /* * Retrieve section #0, allocating a new section if needed. */ static Elf_Scn * _libelf_getscn0(Elf *e) { Elf_Scn *s; if ((s = STAILQ_FIRST(&e->e_u.e_elf.e_scn)) != NULL) return (s); return (_libelf_allocate_scn(e, (size_t) SHN_UNDEF)); } int _libelf_setshnum(Elf *e, void *eh, int ec, size_t shnum) { Elf_Scn *scn; if (shnum >= SHN_LORESERVE) { if ((scn = _libelf_getscn0(e)) == NULL) return (0); assert(scn->s_ndx == SHN_UNDEF); if (ec == ELFCLASS32) scn->s_shdr.s_shdr32.sh_size = shnum; else scn->s_shdr.s_shdr64.sh_size = shnum; (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); shnum = 0; } if (ec == ELFCLASS32) - ((Elf32_Ehdr *) eh)->e_shnum = shnum; + ((Elf32_Ehdr *) eh)->e_shnum = shnum & 0xFFFFU; else - ((Elf64_Ehdr *) eh)->e_shnum = shnum; + ((Elf64_Ehdr *) eh)->e_shnum = shnum & 0xFFFFU; return (1); } int _libelf_setshstrndx(Elf *e, void *eh, int ec, size_t shstrndx) { Elf_Scn *scn; if (shstrndx >= SHN_LORESERVE) { if ((scn = _libelf_getscn0(e)) == NULL) return (0); assert(scn->s_ndx == SHN_UNDEF); if (ec == ELFCLASS32) scn->s_shdr.s_shdr32.sh_link = shstrndx; else scn->s_shdr.s_shdr64.sh_link = shstrndx; (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); shstrndx = SHN_XINDEX; } if (ec == ELFCLASS32) - ((Elf32_Ehdr *) eh)->e_shstrndx = shstrndx; + ((Elf32_Ehdr *) eh)->e_shstrndx = shstrndx & 0xFFFFU; else - ((Elf64_Ehdr *) eh)->e_shstrndx = shstrndx; + ((Elf64_Ehdr *) eh)->e_shstrndx = shstrndx & 0xFFFFU; return (1); } int _libelf_setphnum(Elf *e, void *eh, int ec, size_t phnum) { Elf_Scn *scn; if (phnum >= PN_XNUM) { if ((scn = _libelf_getscn0(e)) == NULL) return (0); assert(scn->s_ndx == SHN_UNDEF); if (ec == ELFCLASS32) scn->s_shdr.s_shdr32.sh_info = phnum; else scn->s_shdr.s_shdr64.sh_info = phnum; (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); phnum = PN_XNUM; } if (ec == ELFCLASS32) - ((Elf32_Ehdr *) eh)->e_phnum = phnum; + ((Elf32_Ehdr *) eh)->e_phnum = phnum & 0xFFFFU; else - ((Elf64_Ehdr *) eh)->e_phnum = phnum; + ((Elf64_Ehdr *) eh)->e_phnum = phnum & 0xFFFFU; return (1); } diff --git a/libelf/libelf_memory.c b/libelf/libelf_memory.c index 892e909b079c..cb8e8f20438a 100644 --- a/libelf/libelf_memory.c +++ b/libelf/libelf_memory.c @@ -1,96 +1,96 @@ /*- * Copyright (c) 2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_memory.c 2368 2011-12-29 06:34:28Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_memory.c 3013 2014-03-23 06:16:59Z jkoshy $"); /* * Create an ELF descriptor for a memory image, optionally reporting * parse errors. */ Elf * -_libelf_memory(char *image, size_t sz, int reporterror) +_libelf_memory(unsigned char *image, size_t sz, int reporterror) { Elf *e; int e_class; enum Elf_Error error; unsigned int e_byteorder, e_version; assert(image != NULL); assert(sz > 0); if ((e = _libelf_allocate_elf()) == NULL) return (NULL); e->e_cmd = ELF_C_READ; e->e_rawfile = image; e->e_rawsize = sz; #undef LIBELF_IS_ELF #define LIBELF_IS_ELF(P) ((P)[EI_MAG0] == ELFMAG0 && \ (P)[EI_MAG1] == ELFMAG1 && (P)[EI_MAG2] == ELFMAG2 && \ (P)[EI_MAG3] == ELFMAG3) if (sz > EI_NIDENT && LIBELF_IS_ELF(image)) { e_byteorder = image[EI_DATA]; e_class = image[EI_CLASS]; e_version = image[EI_VERSION]; error = ELF_E_NONE; if (e_version > EV_CURRENT) error = ELF_E_VERSION; else if ((e_byteorder != ELFDATA2LSB && e_byteorder != ELFDATA2MSB) || (e_class != ELFCLASS32 && e_class != ELFCLASS64)) error = ELF_E_HEADER; if (error != ELF_E_NONE) { if (reporterror) { LIBELF_PRIVATE(error) = LIBELF_ERROR(error, 0); (void) _libelf_release_elf(e); return (NULL); } } else { _libelf_init_elf(e, ELF_K_ELF); e->e_byteorder = e_byteorder; e->e_class = e_class; e->e_version = e_version; } } else if (sz >= SARMAG && - strncmp(image, ARMAG, (size_t) SARMAG) == 0) + strncmp((const char *) image, ARMAG, (size_t) SARMAG) == 0) return (_libelf_ar_open(e, reporterror)); return (e); } diff --git a/libelf/libelf_open.c b/libelf/libelf_open.c index 6d93c73a0312..7ec33952dfe1 100644 --- a/libelf/libelf_open.c +++ b/libelf/libelf_open.c @@ -1,249 +1,249 @@ /*- * Copyright (c) 2006,2008-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "_libelf.h" #if ELFTC_HAVE_MMAP #include #endif -ELFTC_VCSID("$Id: libelf_open.c 2932 2013-03-30 01:26:04Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_open.c 3007 2014-03-22 08:10:14Z jkoshy $"); #define _LIBELF_INITSIZE (64*1024) /* * Read from a device file, pipe or socket. */ static void * _libelf_read_special_file(int fd, size_t *fsz) { ssize_t readsz; size_t bufsz, datasz; unsigned char *buf, *t; datasz = 0; readsz = 0; bufsz = _LIBELF_INITSIZE; if ((buf = malloc(bufsz)) == NULL) goto resourceerror; /* * Read data from the file descriptor till we reach EOF, or * till an error is encountered. */ do { /* Check if we need to expand the data buffer. */ if (datasz == bufsz) { bufsz *= 2; if ((t = realloc(buf, bufsz)) == NULL) goto resourceerror; buf = t; } do { - readsz = bufsz - datasz; + assert(bufsz - datasz > 0); t = buf + datasz; - if ((readsz = read(fd, t, readsz)) <= 0) + if ((readsz = read(fd, t, bufsz - datasz)) <= 0) break; - datasz += readsz; + datasz += (size_t) readsz; } while (datasz < bufsz); } while (readsz > 0); if (readsz < 0) { LIBELF_SET_ERROR(IO, errno); goto error; } assert(readsz == 0); /* * Free up extra buffer space. */ if (bufsz > datasz) { if (datasz > 0) { if ((t = realloc(buf, datasz)) == NULL) goto resourceerror; buf = t; } else { /* Zero bytes read. */ LIBELF_SET_ERROR(ARGUMENT, 0); free(buf); buf = NULL; } } *fsz = datasz; return (buf); resourceerror: LIBELF_SET_ERROR(RESOURCE, 0); error: if (buf != NULL) free(buf); return (NULL); } /* * Read the contents of the file referenced by the file descriptor * 'fd'. */ Elf * _libelf_open_object(int fd, Elf_Cmd c, int reporterror) { Elf *e; void *m; mode_t mode; size_t fsize; struct stat sb; unsigned int flags; assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE); if (fstat(fd, &sb) < 0) { LIBELF_SET_ERROR(IO, errno); return (NULL); } mode = sb.st_mode; fsize = (size_t) sb.st_size; /* * Reject unsupported file types. */ if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && !S_ISSOCK(mode)) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } /* * For ELF_C_WRITE mode, allocate and return a descriptor. */ if (c == ELF_C_WRITE) { if ((e = _libelf_allocate_elf()) != NULL) { _libelf_init_elf(e, ELF_K_ELF); e->e_byteorder = LIBELF_PRIVATE(byteorder); e->e_fd = fd; e->e_cmd = c; if (!S_ISREG(mode)) e->e_flags |= LIBELF_F_SPECIAL_FILE; } return (e); } /* * ELF_C_READ and ELF_C_RDWR mode. */ m = NULL; flags = 0; if (S_ISREG(mode)) { /* * Reject zero length files. */ if (fsize == 0) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } #if ELFTC_HAVE_MMAP /* * Always map regular files in with 'PROT_READ' * permissions. * * For objects opened in ELF_C_RDWR mode, when * elf_update(3) is called, we remove this mapping, * write file data out using write(2), and map the new * contents back. */ m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0); if (m == MAP_FAILED) m = NULL; else flags = LIBELF_F_RAWFILE_MMAP; #endif /* * Fallback to a read() if the call to mmap() failed, * or if mmap() is not available. */ if (m == NULL) { if ((m = malloc(fsize)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (read(fd, m, fsize) != (ssize_t) fsize) { LIBELF_SET_ERROR(IO, errno); free(m); return (NULL); } flags = LIBELF_F_RAWFILE_MALLOC; } } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL) flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE; else return (NULL); if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) { assert((flags & LIBELF_F_RAWFILE_MALLOC) || (flags & LIBELF_F_RAWFILE_MMAP)); if (flags & LIBELF_F_RAWFILE_MALLOC) free(m); #if ELFTC_HAVE_MMAP else (void) munmap(m, fsize); #endif return (NULL); } /* ar(1) archives aren't supported in RDWR mode. */ if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) { (void) elf_end(e); LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } e->e_flags |= flags; e->e_fd = fd; e->e_cmd = c; return (e); } diff --git a/libelf/libelf_phdr.c b/libelf/libelf_phdr.c index f2eb697fbc04..f44c3cd7e44e 100644 --- a/libelf/libelf_phdr.c +++ b/libelf/libelf_phdr.c @@ -1,154 +1,155 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_phdr.c 2931 2013-03-23 11:41:07Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_phdr.c 3009 2014-03-23 01:49:59Z jkoshy $"); void * _libelf_getphdr(Elf *e, int ec) { size_t phnum; size_t fsz, msz; uint64_t phoff; Elf32_Ehdr *eh32; Elf64_Ehdr *eh64; void *ehdr, *phdr; - int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap); + int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, + size_t _c, int _swap); assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (e == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((phdr = (ec == ELFCLASS32 ? (void *) e->e_u.e_elf.e_phdr.e_phdr32 : (void *) e->e_u.e_elf.e_phdr.e_phdr64)) != NULL) return (phdr); /* * Check the PHDR related fields in the EHDR for sanity. */ if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) return (NULL); phnum = e->e_u.e_elf.e_nphdr; if (ec == ELFCLASS32) { eh32 = (Elf32_Ehdr *) ehdr; phoff = (uint64_t) eh32->e_phoff; } else { eh64 = (Elf64_Ehdr *) ehdr; phoff = (uint64_t) eh64->e_phoff; } fsz = gelf_fsize(e, ELF_T_PHDR, phnum, e->e_version); assert(fsz > 0); if ((uint64_t) e->e_rawsize < (phoff + fsz)) { LIBELF_SET_ERROR(HEADER, 0); return (NULL); } msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT); assert(msz > 0); if ((phdr = calloc(phnum, msz)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (ec == ELFCLASS32) e->e_u.e_elf.e_phdr.e_phdr32 = phdr; else e->e_u.e_elf.e_phdr.e_phdr64 = phdr; xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec); (*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum, e->e_byteorder != LIBELF_PRIVATE(byteorder)); return (phdr); } void * _libelf_newphdr(Elf *e, int ec, size_t count) { void *ehdr, *newphdr, *oldphdr; size_t msz; if (e == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) { LIBELF_SET_ERROR(SEQUENCE, 0); return (NULL); } assert(e->e_class == ec); assert(ec == ELFCLASS32 || ec == ELFCLASS64); assert(e->e_version == EV_CURRENT); msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version); assert(msz > 0); newphdr = NULL; if (count > 0 && (newphdr = calloc(count, msz)) == NULL) { LIBELF_SET_ERROR(RESOURCE, 0); return (NULL); } if (ec == ELFCLASS32) { if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL) free(oldphdr); e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) newphdr; } else { if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL) free(oldphdr); e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) newphdr; } e->e_u.e_elf.e_nphdr = count; elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY); return (newphdr); } diff --git a/libelf/libelf_xlate.c b/libelf/libelf_xlate.c index eda6df8c2260..4cc6a452e4dd 100644 --- a/libelf/libelf_xlate.c +++ b/libelf/libelf_xlate.c @@ -1,150 +1,150 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" -ELFTC_VCSID("$Id: libelf_xlate.c 2225 2011-11-26 18:55:54Z jkoshy $"); +ELFTC_VCSID("$Id: libelf_xlate.c 3007 2014-03-22 08:10:14Z jkoshy $"); /* * Translate to/from the file representation of ELF objects. * * Translation could potentially involve the following * transformations: * * - an endianness conversion, * - a change of layout, as the file representation of ELF objects * can differ from their in-memory representation. * - a change in representation due to a layout version change. */ Elf_Data * _libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding, int elfclass, int direction) { int byteswap; size_t cnt, dsz, fsz, msz; uintptr_t sb, se, db, de; if (encoding == ELFDATANONE) encoding = LIBELF_PRIVATE(byteorder); if ((encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) || dst == NULL || src == NULL || dst == src) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); if (dst->d_version != src->d_version) { LIBELF_SET_ERROR(UNIMPL, 0); return (NULL); } if (src->d_buf == NULL || dst->d_buf == NULL) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((int) src->d_type < 0 || src->d_type >= ELF_T_NUM) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) (src->d_type, (size_t) 1, src->d_version)) == 0) return (NULL); msz = _libelf_msize(src->d_type, elfclass, src->d_version); assert(msz > 0); if (src->d_size % (direction == ELF_TOMEMORY ? fsz : msz)) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } /* * Determine the number of objects that need to be converted, and * the space required for the converted objects in the destination * buffer. */ if (direction == ELF_TOMEMORY) { - cnt = src->d_size / fsz; + cnt = (size_t) src->d_size / fsz; dsz = cnt * msz; } else { - cnt = src->d_size / msz; + cnt = (size_t) src->d_size / msz; dsz = cnt * fsz; } if (dst->d_size < dsz) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } sb = (uintptr_t) src->d_buf; - se = sb + src->d_size; + se = sb + (size_t) src->d_size; db = (uintptr_t) dst->d_buf; - de = db + dst->d_size; + de = db + (size_t) dst->d_size; /* * Check for overlapping buffers. Note that db == sb is * allowed. */ if (db != sb && de > sb && se > db) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } if ((direction == ELF_TOMEMORY ? db : sb) % _libelf_malign(src->d_type, elfclass)) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } dst->d_type = src->d_type; dst->d_size = dsz; byteswap = encoding != LIBELF_PRIVATE(byteorder); if (src->d_size == 0 || (db == sb && !byteswap && fsz == msz)) return (dst); /* nothing more to do */ if (!(_libelf_get_translator(src->d_type, direction, elfclass)) (dst->d_buf, dsz, src->d_buf, cnt, byteswap)) { LIBELF_SET_ERROR(DATA, 0); return (NULL); } return (dst); } diff --git a/libelftc/elftc_copyfile.c b/libelftc/elftc_copyfile.c index 0bacaf45e769..7df1678e702d 100644 --- a/libelftc/elftc_copyfile.c +++ b/libelftc/elftc_copyfile.c @@ -1,107 +1,109 @@ /*- * Copyright (c) 2011, Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "libelftc.h" #include "_libelftc.h" #if ELFTC_HAVE_MMAP #include #endif -ELFTC_VCSID("$Id: elftc_copyfile.c 2318 2011-12-11 10:54:27Z jkoshy $"); +ELFTC_VCSID("$Id: elftc_copyfile.c 2981 2014-02-01 02:41:13Z jkoshy $"); /* * Copy the contents referenced by 'ifd' to 'ofd'. Returns 0 on * success and -1 on error. */ int elftc_copyfile(int ifd, int ofd) { int buf_mmapped; struct stat sb; char *b, *buf; ssize_t nw; size_t n; /* Determine the input file's size. */ if (fstat(ifd, &sb) < 0) return (-1); /* Skip files without content. */ if (sb.st_size == 0) return (0); buf = NULL; buf_mmapped = 0; #if ELFTC_HAVE_MMAP /* * Prefer mmap() if it is available. */ buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, ifd, (off_t) 0); if (buf != MAP_FAILED) buf_mmapped = 1; else buf = NULL; #endif /* * If mmap() is not available, or if the mmap() operation * failed, allocate a buffer, and read in input data. */ - if (buf == NULL) { + if (buf_mmapped == false) { if ((buf = malloc(sb.st_size)) == NULL) return (-1); - if (read(ifd, buf, sb.st_size) != sb.st_size) + if (read(ifd, buf, sb.st_size) != sb.st_size) { + free(buf); return (-1); + } } /* * Write data to the output file descriptor. */ for (n = sb.st_size, b = buf; n > 0; n -= nw, b += nw) if ((nw = write(ofd, b, n)) <= 0) break; /* Release the input buffer. */ #if ELFTC_HAVE_MMAP if (buf_mmapped && munmap(buf, sb.st_size) < 0) return (-1); #endif if (!buf_mmapped) free(buf); return (n > 0 ? -1 : 0); } diff --git a/libelftc/elftc_demangle.c b/libelftc/elftc_demangle.c index c55564e3df63..9639d630c6e8 100644 --- a/libelftc/elftc_demangle.c +++ b/libelftc/elftc_demangle.c @@ -1,110 +1,109 @@ /*- * Copyright (c) 2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include -#include #include #include #include #include "_libelftc.h" -ELFTC_VCSID("$Id: elftc_demangle.c 2065 2011-10-26 15:24:47Z jkoshy $"); +ELFTC_VCSID("$Id: elftc_demangle.c 3030 2014-05-01 06:30:48Z kaiwang27 $"); static int is_mangled(const char *s, int style) { switch (style) { case ELFTC_DEM_ARM: return (is_cpp_mangled_ARM(s) ? style : 0); case ELFTC_DEM_GNU2: return (is_cpp_mangled_gnu2(s) ? style : 0); case ELFTC_DEM_GNU3: return (is_cpp_mangled_gnu3(s) ? style : 0); } /* No style or invalid style spcified, try to guess. */ if (is_cpp_mangled_gnu3(s)) return (ELFTC_DEM_GNU3); if (is_cpp_mangled_gnu2(s)) return (ELFTC_DEM_GNU2); if (is_cpp_mangled_ARM(s)) return (ELFTC_DEM_ARM); /* Cannot be demangled. */ return (0); } static char * demangle(const char *s, int style, int rc) { (void) rc; /* XXX */ switch (style) { case ELFTC_DEM_ARM: return (cpp_demangle_ARM(s)); case ELFTC_DEM_GNU2: return (cpp_demangle_gnu2(s)); case ELFTC_DEM_GNU3: return (cpp_demangle_gnu3(s)); default: assert(0); return (NULL); } } int elftc_demangle(const char *mangledname, char *buffer, size_t bufsize, unsigned int flags) { int style, rc; char *rlt; style = flags & 0xFFFF; rc = flags >> 16; if (mangledname == NULL || ((style = is_mangled(mangledname, style)) == 0)) { errno = EINVAL; return (-1); } if ((rlt = demangle(mangledname, style, rc)) == NULL) { errno = EINVAL; return (-1); } if (buffer == NULL || bufsize < strlen(rlt) + 1) { free(rlt); errno = ENAMETOOLONG; return (-1); } strncpy(buffer, rlt, bufsize); buffer[bufsize - 1] = '\0'; free(rlt); return (0); } diff --git a/libelftc/libelftc.h b/libelftc/libelftc.h index aa6b0b6ffe1e..85e4feb3a710 100644 --- a/libelftc/libelftc.h +++ b/libelftc/libelftc.h @@ -1,89 +1,92 @@ /*- * Copyright (c) 2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: users/kaiwang27/elftc/libelftc.h 392 2009-05-31 19:17:46Z kaiwang27 $ - * $Id: libelftc.h 2863 2013-01-06 03:18:32Z jkoshy $ + * $Id: libelftc.h 3031 2014-05-01 17:45:41Z jkoshy $ */ #ifndef _LIBELFTC_H_ #define _LIBELFTC_H_ #include #include +/* + * Types meant to be opaque to the consumers of these APIs. + */ typedef struct _Elftc_Bfd_Target Elftc_Bfd_Target; typedef struct _Elftc_String_Table Elftc_String_Table; /* Target types. */ typedef enum { ETF_NONE, ETF_ELF, ETF_BINARY, ETF_SREC, ETF_IHEX } Elftc_Bfd_Target_Flavor; /* * Demangler flags. */ /* Name mangling style. */ #define ELFTC_DEM_UNKNOWN 0x00000000U /* Not specified. */ #define ELFTC_DEM_ARM 0x00000001U /* C++ Ann. Ref. Manual. */ #define ELFTC_DEM_GNU2 0x00000002U /* GNU version 2. */ #define ELFTC_DEM_GNU3 0x00000004U /* GNU version 3. */ /* Demangling behaviour control. */ #define ELFTC_DEM_NOPARAM 0x00010000U __BEGIN_DECLS Elftc_Bfd_Target *elftc_bfd_find_target(const char *_tgt_name); Elftc_Bfd_Target_Flavor elftc_bfd_target_flavor(Elftc_Bfd_Target *_tgt); unsigned int elftc_bfd_target_byteorder(Elftc_Bfd_Target *_tgt); unsigned int elftc_bfd_target_class(Elftc_Bfd_Target *_tgt); unsigned int elftc_bfd_target_machine(Elftc_Bfd_Target *_tgt); int elftc_copyfile(int _srcfd, int _dstfd); int elftc_demangle(const char *_mangledname, char *_buffer, size_t _bufsize, unsigned int _flags); int elftc_set_timestamps(const char *_filename, struct stat *_sb); Elftc_String_Table *elftc_string_table_create(int _hint); void elftc_string_table_destroy(Elftc_String_Table *_table); Elftc_String_Table *elftc_string_table_from_section(Elf_Scn *_scn, int _hint); const char *elftc_string_table_image(Elftc_String_Table *_table, size_t *_sz); size_t elftc_string_table_insert(Elftc_String_Table *_table, const char *_string); size_t elftc_string_table_lookup(Elftc_String_Table *_table, const char *_string); int elftc_string_table_remove(Elftc_String_Table *_table, const char *_string); const char *elftc_string_table_to_string(Elftc_String_Table *_table, size_t offset); const char *elftc_version(void); __END_DECLS #endif /* _LIBELFTC_H_ */ diff --git a/libelftc/libelftc_dem_gnu3.c b/libelftc/libelftc_dem_gnu3.c index bd54f549ddb8..05a6302816c9 100644 --- a/libelftc/libelftc_dem_gnu3.c +++ b/libelftc/libelftc_dem_gnu3.c @@ -1,3238 +1,3238 @@ /*- * Copyright (c) 2007 Hyogeol Lee * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "_libelftc.h" -ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 2179 2011-11-18 03:05:47Z jkoshy $"); +ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3123 2014-12-21 05:46:19Z kaiwang27 $"); /** * @file cpp_demangle.c * @brief Decode IA-64 C++ ABI style implementation. * * IA-64 standard ABI(Itanium C++ ABI) references. * * http://www.codesourcery.com/cxx-abi/abi.html#mangling \n * http://www.codesourcery.com/cxx-abi/abi-mangling.html */ enum type_qualifier { TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT, TYPE_CST }; struct vector_type_qualifier { size_t size, capacity; enum type_qualifier *q_container; struct vector_str ext_name; }; enum read_cmd { READ_FAIL, READ_NEST, READ_TMPL, READ_EXPR, READ_EXPL, READ_LOCAL, READ_TYPE, READ_FUNC, READ_PTRMEM }; struct vector_read_cmd { size_t size, capacity; enum read_cmd *r_container; }; struct cpp_demangle_data { struct vector_str output; /* output string vector */ struct vector_str output_tmp; struct vector_str subst; /* substitution string vector */ struct vector_str tmpl; struct vector_str class_type; struct vector_read_cmd cmd; bool paren; /* parenthesis opened */ bool pfirst; /* first element of parameter */ bool mem_rst; /* restrict member function */ bool mem_vat; /* volatile member function */ bool mem_cst; /* const member function */ int func_type; const char *cur; /* current mangled name ptr */ const char *last_sname; /* last source name */ }; #define CPP_DEMANGLE_TRY_LIMIT 128 #define FLOAT_SPRINTF_TRY_LIMIT 5 #define FLOAT_QUADRUPLE_BYTES 16 #define FLOAT_EXTENED_BYTES 10 #define SIMPLE_HASH(x,y) (64 * x + y) static void cpp_demangle_data_dest(struct cpp_demangle_data *); static int cpp_demangle_data_init(struct cpp_demangle_data *, const char *); static int cpp_demangle_get_subst(struct cpp_demangle_data *, size_t); static int cpp_demangle_get_tmpl_param(struct cpp_demangle_data *, size_t); static int cpp_demangle_push_fp(struct cpp_demangle_data *, char *(*)(const char *, size_t)); static int cpp_demangle_push_str(struct cpp_demangle_data *, const char *, size_t); static int cpp_demangle_push_subst(struct cpp_demangle_data *, const char *, size_t); static int cpp_demangle_push_subst_v(struct cpp_demangle_data *, struct vector_str *); static int cpp_demangle_push_type_qualifier(struct cpp_demangle_data *, struct vector_type_qualifier *, const char *); static int cpp_demangle_read_array(struct cpp_demangle_data *); static int cpp_demangle_read_encoding(struct cpp_demangle_data *); static int cpp_demangle_read_expr_primary(struct cpp_demangle_data *); static int cpp_demangle_read_expression(struct cpp_demangle_data *); static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *, const char *, size_t); static int cpp_demangle_read_expression_unary(struct cpp_demangle_data *, const char *, size_t); static int cpp_demangle_read_expression_trinary(struct cpp_demangle_data *, const char *, size_t, const char *, size_t); static int cpp_demangle_read_function(struct cpp_demangle_data *, int *, struct vector_type_qualifier *); static int cpp_demangle_local_source_name(struct cpp_demangle_data *ddata); static int cpp_demangle_read_local_name(struct cpp_demangle_data *); static int cpp_demangle_read_name(struct cpp_demangle_data *); static int cpp_demangle_read_nested_name(struct cpp_demangle_data *); static int cpp_demangle_read_number(struct cpp_demangle_data *, long *); static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *); static int cpp_demangle_read_offset(struct cpp_demangle_data *); static int cpp_demangle_read_offset_number(struct cpp_demangle_data *); static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *); static int cpp_demangle_read_sname(struct cpp_demangle_data *); static int cpp_demangle_read_subst(struct cpp_demangle_data *); static int cpp_demangle_read_subst_std(struct cpp_demangle_data *); static int cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *, const char *, size_t); static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *); static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *); static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *); static int cpp_demangle_read_type(struct cpp_demangle_data *, int); static int cpp_demangle_read_uqname(struct cpp_demangle_data *); static int cpp_demangle_read_v_offset(struct cpp_demangle_data *); static char *decode_fp_to_double(const char *, size_t); static char *decode_fp_to_float(const char *, size_t); static char *decode_fp_to_float128(const char *, size_t); static char *decode_fp_to_float80(const char *, size_t); static char *decode_fp_to_long_double(const char *, size_t); static int hex_to_dec(char); static void vector_read_cmd_dest(struct vector_read_cmd *); static int vector_read_cmd_find(struct vector_read_cmd *, enum read_cmd); static int vector_read_cmd_init(struct vector_read_cmd *); static int vector_read_cmd_pop(struct vector_read_cmd *); static int vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd); static void vector_type_qualifier_dest(struct vector_type_qualifier *); static int vector_type_qualifier_init(struct vector_type_qualifier *); static int vector_type_qualifier_push(struct vector_type_qualifier *, enum type_qualifier); -int cpp_demangle_gnu3_push_head; +static int cpp_demangle_gnu3_push_head; /** * @brief Decode the input string by IA-64 C++ ABI style. * * GNU GCC v3 use IA-64 standard ABI. * @return New allocated demangled string or NULL if failed. * @todo 1. Testing and more test case. 2. Code cleaning. */ char * cpp_demangle_gnu3(const char *org) { struct cpp_demangle_data ddata; ssize_t org_len; unsigned int limit; char *rtn; if (org == NULL || (org_len = strlen(org)) < 2) return (NULL); if (org_len > 11 && !strncmp(org, "_GLOBAL__I_", 11)) { if ((rtn = malloc(org_len + 19)) == NULL) return (NULL); snprintf(rtn, org_len + 19, "global constructors keyed to %s", org + 11); return (rtn); } if (org[0] != '_' || org[1] != 'Z') return (NULL); if (!cpp_demangle_data_init(&ddata, org + 2)) return (NULL); cpp_demangle_gnu3_push_head = 0; rtn = NULL; if (!cpp_demangle_read_encoding(&ddata)) goto clean; limit = 0; while (*ddata.cur != '\0') { /* * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4 */ if (*ddata.cur == '@' && *(ddata.cur + 1) == '@') break; if (!cpp_demangle_read_type(&ddata, 1)) goto clean; if (limit++ > CPP_DEMANGLE_TRY_LIMIT) goto clean; } if (ddata.output.size == 0) goto clean; if (ddata.paren && !vector_str_push(&ddata.output, ")", 1)) goto clean; if (ddata.mem_vat && !vector_str_push(&ddata.output, " volatile", 9)) goto clean; if (ddata.mem_cst && !vector_str_push(&ddata.output, " const", 6)) goto clean; if (ddata.mem_rst && !vector_str_push(&ddata.output, " restrict", 9)) goto clean; rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL); clean: cpp_demangle_data_dest(&ddata); return (rtn); } static void cpp_demangle_data_dest(struct cpp_demangle_data *d) { if (d == NULL) return; vector_read_cmd_dest(&d->cmd); vector_str_dest(&d->class_type); vector_str_dest(&d->tmpl); vector_str_dest(&d->subst); vector_str_dest(&d->output_tmp); vector_str_dest(&d->output); } static int cpp_demangle_data_init(struct cpp_demangle_data *d, const char *cur) { if (d == NULL || cur == NULL) return (0); if (!vector_str_init(&d->output)) return (0); if (!vector_str_init(&d->output_tmp)) goto clean1; if (!vector_str_init(&d->subst)) goto clean2; if (!vector_str_init(&d->tmpl)) goto clean3; if (!vector_str_init(&d->class_type)) goto clean4; if (!vector_read_cmd_init(&d->cmd)) goto clean5; assert(d->output.container != NULL); assert(d->output_tmp.container != NULL); assert(d->subst.container != NULL); assert(d->tmpl.container != NULL); assert(d->class_type.container != NULL); d->paren = false; d->pfirst = false; d->mem_rst = false; d->mem_vat = false; d->mem_cst = false; d->func_type = 0; d->cur = cur; d->last_sname = NULL; return (1); clean5: vector_str_dest(&d->class_type); clean4: vector_str_dest(&d->tmpl); clean3: vector_str_dest(&d->subst); clean2: vector_str_dest(&d->output_tmp); clean1: vector_str_dest(&d->output); return (0); } static int cpp_demangle_push_fp(struct cpp_demangle_data *ddata, char *(*decoder)(const char *, size_t)) { size_t len; int rtn; const char *fp; char *f; if (ddata == NULL || decoder == NULL) return (0); fp = ddata->cur; while (*ddata->cur != 'E') ++ddata->cur; ++ddata->cur; if ((f = decoder(fp, ddata->cur - fp)) == NULL) return (0); rtn = 0; if ((len = strlen(f)) > 0) rtn = cpp_demangle_push_str(ddata, f, len); free(f); return (rtn); } static int cpp_demangle_push_str(struct cpp_demangle_data *ddata, const char *str, size_t len) { if (ddata == NULL || str == NULL || len == 0) return (0); if (cpp_demangle_gnu3_push_head > 0) return (vector_str_push(&ddata->output_tmp, str, len)); return (vector_str_push(&ddata->output, str, len)); } static int cpp_demangle_push_subst(struct cpp_demangle_data *ddata, const char *str, size_t len) { if (ddata == NULL || str == NULL || len == 0) return (0); if (!vector_str_find(&ddata->subst, str, len)) return (vector_str_push(&ddata->subst, str, len)); return (1); } static int cpp_demangle_push_subst_v(struct cpp_demangle_data *ddata, struct vector_str *v) { size_t str_len; int rtn; char *str; if (ddata == NULL || v == NULL) return (0); if ((str = vector_str_get_flat(v, &str_len)) == NULL) return (0); rtn = cpp_demangle_push_subst(ddata, str, str_len); free(str); return (rtn); } static int cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, struct vector_type_qualifier *v, const char *type_str) { struct vector_str subst_v; size_t idx, e_idx, e_len; int rtn; char *buf; if (ddata == NULL || v == NULL) return (0); if ((idx = v->size) == 0) return (1); rtn = 0; if (type_str != NULL) { if (!vector_str_init(&subst_v)) return (0); if (!vector_str_push(&subst_v, type_str, strlen(type_str))) goto clean; } e_idx = 0; while (idx > 0) { switch (v->q_container[idx - 1]) { case TYPE_PTR: if (!cpp_demangle_push_str(ddata, "*", 1)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, "*", 1)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_REF: if (!cpp_demangle_push_str(ddata, "&", 1)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, "&", 1)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_CMX: if (!cpp_demangle_push_str(ddata, " complex", 8)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, " complex", 8)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_IMG: if (!cpp_demangle_push_str(ddata, " imaginary", 10)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, " imaginary", 10)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_EXT: if (e_idx > v->ext_name.size - 1) goto clean; if ((e_len = strlen(v->ext_name.container[e_idx])) == 0) goto clean; if ((buf = malloc(sizeof(char) * (e_len + 1))) == NULL) goto clean; memcpy(buf, " ", 1); memcpy(buf + 1, v->ext_name.container[e_idx], e_len); if (!cpp_demangle_push_str(ddata, buf, e_len + 1)) { free(buf); goto clean; } if (type_str != NULL) { if (!vector_str_push(&subst_v, buf, e_len + 1)) { free(buf); goto clean; } if (!cpp_demangle_push_subst_v(ddata, &subst_v)) { free(buf); goto clean; } } free(buf); ++e_idx; break; case TYPE_RST: if (!cpp_demangle_push_str(ddata, " restrict", 9)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, " restrict", 9)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_VAT: if (!cpp_demangle_push_str(ddata, " volatile", 9)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, " volatile", 9)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_CST: if (!cpp_demangle_push_str(ddata, " const", 6)) goto clean; if (type_str != NULL) { if (!vector_str_push(&subst_v, " const", 6)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; }; --idx; } rtn = 1; clean: if (type_str != NULL) vector_str_dest(&subst_v); return (rtn); } static int cpp_demangle_get_subst(struct cpp_demangle_data *ddata, size_t idx) { size_t len; if (ddata == NULL || ddata->subst.size <= idx) return (0); if ((len = strlen(ddata->subst.container[idx])) == 0) return (0); if (!cpp_demangle_push_str(ddata, ddata->subst.container[idx], len)) return (0); /* skip '_' */ ++ddata->cur; return (1); } static int cpp_demangle_get_tmpl_param(struct cpp_demangle_data *ddata, size_t idx) { size_t len; if (ddata == NULL || ddata->tmpl.size <= idx) return (0); if ((len = strlen(ddata->tmpl.container[idx])) == 0) return (0); if (!cpp_demangle_push_str(ddata, ddata->tmpl.container[idx], len)) return (0); ++ddata->cur; return (1); } static int cpp_demangle_read_array(struct cpp_demangle_data *ddata) { size_t i, num_len, exp_len, p_idx, idx; const char *num; char *exp; if (ddata == NULL || *(++ddata->cur) == '\0') return (0); if (*ddata->cur == '_') { if (*(++ddata->cur) == '\0') return (0); if (!cpp_demangle_read_type(ddata, 0)) return (0); if (!cpp_demangle_push_str(ddata, "[]", 2)) return (0); } else { if (ELFTC_ISDIGIT(*ddata->cur) != 0) { num = ddata->cur; while (ELFTC_ISDIGIT(*ddata->cur) != 0) ++ddata->cur; if (*ddata->cur != '_') return (0); num_len = ddata->cur - num; assert(num_len > 0); if (*(++ddata->cur) == '\0') return (0); if (!cpp_demangle_read_type(ddata, 0)) return (0); if (!cpp_demangle_push_str(ddata, "[", 1)) return (0); if (!cpp_demangle_push_str(ddata, num, num_len)) return (0); if (!cpp_demangle_push_str(ddata, "]", 1)) return (0); } else { p_idx = ddata->output.size; if (!cpp_demangle_read_expression(ddata)) return (0); if ((exp = vector_str_substr(&ddata->output, p_idx, ddata->output.size - 1, &exp_len)) == NULL) return (0); idx = ddata->output.size; for (i = p_idx; i < idx; ++i) if (!vector_str_pop(&ddata->output)) { free(exp); return (0); } if (*ddata->cur != '_') { free(exp); return (0); } ++ddata->cur; if (*ddata->cur == '\0') { free(exp); return (0); } if (!cpp_demangle_read_type(ddata, 0)) { free(exp); return (0); } if (!cpp_demangle_push_str(ddata, "[", 1)) { free(exp); return (0); } if (!cpp_demangle_push_str(ddata, exp, exp_len)) { free(exp); return (0); } if (!cpp_demangle_push_str(ddata, "]", 1)) { free(exp); return (0); } free(exp); } } return (1); } static int cpp_demangle_read_expr_primary(struct cpp_demangle_data *ddata) { const char *num; if (ddata == NULL || *(++ddata->cur) == '\0') return (0); if (*ddata->cur == '_' && *(ddata->cur + 1) == 'Z') { ddata->cur += 2; if (*ddata->cur == '\0') return (0); if (!cpp_demangle_read_encoding(ddata)) return (0); ++ddata->cur; return (1); } switch (*ddata->cur) { case 'b': switch (*(++ddata->cur)) { case '0': return (cpp_demangle_push_str(ddata, "false", 5)); case '1': return (cpp_demangle_push_str(ddata, "true", 4)); default: return (0); }; case 'd': ++ddata->cur; return (cpp_demangle_push_fp(ddata, decode_fp_to_double)); case 'e': ++ddata->cur; if (sizeof(long double) == 10) return (cpp_demangle_push_fp(ddata, decode_fp_to_double)); return (cpp_demangle_push_fp(ddata, decode_fp_to_float80)); case 'f': ++ddata->cur; return (cpp_demangle_push_fp(ddata, decode_fp_to_float)); case 'g': ++ddata->cur; if (sizeof(long double) == 16) return (cpp_demangle_push_fp(ddata, decode_fp_to_double)); return (cpp_demangle_push_fp(ddata, decode_fp_to_float128)); case 'i': case 'j': case 'l': case 'm': case 'n': case 's': case 't': case 'x': case 'y': if (*(++ddata->cur) == 'n') { if (!cpp_demangle_push_str(ddata, "-", 1)) return (0); ++ddata->cur; } num = ddata->cur; while (*ddata->cur != 'E') { if (!ELFTC_ISDIGIT(*ddata->cur)) return (0); ++ddata->cur; } ++ddata->cur; return (cpp_demangle_push_str(ddata, num, ddata->cur - num)); default: return (0); }; } static int cpp_demangle_read_expression(struct cpp_demangle_data *ddata) { if (ddata == NULL || *ddata->cur == '\0') return (0); switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { case SIMPLE_HASH('s', 't'): ddata->cur += 2; return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('s', 'r'): ddata->cur += 2; if (!cpp_demangle_read_type(ddata, 0)) return (0); if (!cpp_demangle_read_uqname(ddata)) return (0); if (*ddata->cur == 'I') return (cpp_demangle_read_tmpl_args(ddata)); return (1); case SIMPLE_HASH('a', 'a'): /* operator && */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "&&", 2)); case SIMPLE_HASH('a', 'd'): /* operator & (unary) */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "&", 1)); case SIMPLE_HASH('a', 'n'): /* operator & */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "&", 1)); case SIMPLE_HASH('a', 'N'): /* operator &= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "&=", 2)); case SIMPLE_HASH('a', 'S'): /* operator = */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "=", 1)); case SIMPLE_HASH('c', 'l'): /* operator () */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "()", 2)); case SIMPLE_HASH('c', 'm'): /* operator , */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, ",", 1)); case SIMPLE_HASH('c', 'o'): /* operator ~ */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "~", 1)); case SIMPLE_HASH('c', 'v'): /* operator (cast) */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "(cast)", 6)); case SIMPLE_HASH('d', 'a'): /* operator delete [] */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "delete []", 9)); case SIMPLE_HASH('d', 'e'): /* operator * (unary) */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "*", 1)); case SIMPLE_HASH('d', 'l'): /* operator delete */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "delete", 6)); case SIMPLE_HASH('d', 'v'): /* operator / */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "/", 1)); case SIMPLE_HASH('d', 'V'): /* operator /= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "/=", 2)); case SIMPLE_HASH('e', 'o'): /* operator ^ */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "^", 1)); case SIMPLE_HASH('e', 'O'): /* operator ^= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "^=", 2)); case SIMPLE_HASH('e', 'q'): /* operator == */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "==", 2)); case SIMPLE_HASH('g', 'e'): /* operator >= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, ">=", 2)); case SIMPLE_HASH('g', 't'): /* operator > */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, ">", 1)); case SIMPLE_HASH('i', 'x'): /* operator [] */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "[]", 2)); case SIMPLE_HASH('l', 'e'): /* operator <= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "<=", 2)); case SIMPLE_HASH('l', 's'): /* operator << */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "<<", 2)); case SIMPLE_HASH('l', 'S'): /* operator <<= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "<<=", 3)); case SIMPLE_HASH('l', 't'): /* operator < */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "<", 1)); case SIMPLE_HASH('m', 'i'): /* operator - */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "-", 1)); case SIMPLE_HASH('m', 'I'): /* operator -= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "-=", 2)); case SIMPLE_HASH('m', 'l'): /* operator * */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "*", 1)); case SIMPLE_HASH('m', 'L'): /* operator *= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "*=", 2)); case SIMPLE_HASH('m', 'm'): /* operator -- */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "--", 2)); case SIMPLE_HASH('n', 'a'): /* operator new[] */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "new []", 6)); case SIMPLE_HASH('n', 'e'): /* operator != */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "!=", 2)); case SIMPLE_HASH('n', 'g'): /* operator - (unary) */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "-", 1)); case SIMPLE_HASH('n', 't'): /* operator ! */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "!", 1)); case SIMPLE_HASH('n', 'w'): /* operator new */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "new", 3)); case SIMPLE_HASH('o', 'o'): /* operator || */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "||", 2)); case SIMPLE_HASH('o', 'r'): /* operator | */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "|", 1)); case SIMPLE_HASH('o', 'R'): /* operator |= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "|=", 2)); case SIMPLE_HASH('p', 'l'): /* operator + */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "+", 1)); case SIMPLE_HASH('p', 'L'): /* operator += */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "+=", 2)); case SIMPLE_HASH('p', 'm'): /* operator ->* */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "->*", 3)); case SIMPLE_HASH('p', 'p'): /* operator ++ */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "++", 2)); case SIMPLE_HASH('p', 's'): /* operator + (unary) */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "+", 1)); case SIMPLE_HASH('p', 't'): /* operator -> */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "->", 2)); case SIMPLE_HASH('q', 'u'): /* operator ? */ ddata->cur += 2; return (cpp_demangle_read_expression_trinary(ddata, "?", 1, ":", 1)); case SIMPLE_HASH('r', 'm'): /* operator % */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "%", 1)); case SIMPLE_HASH('r', 'M'): /* operator %= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, "%=", 2)); case SIMPLE_HASH('r', 's'): /* operator >> */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, ">>", 2)); case SIMPLE_HASH('r', 'S'): /* operator >>= */ ddata->cur += 2; return (cpp_demangle_read_expression_binary(ddata, ">>=", 3)); case SIMPLE_HASH('r', 'z'): /* operator sizeof */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6)); case SIMPLE_HASH('s', 'v'): /* operator sizeof */ ddata->cur += 2; return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6)); }; switch (*ddata->cur) { case 'L': return (cpp_demangle_read_expr_primary(ddata)); case 'T': return (cpp_demangle_read_tmpl_param(ddata)); }; return (0); } static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *ddata, const char *name, size_t len) { if (ddata == NULL || name == NULL || len == 0) return (0); if (!cpp_demangle_read_expression(ddata)) return (0); if (!cpp_demangle_push_str(ddata, name, len)) return (0); return (cpp_demangle_read_expression(ddata)); } static int cpp_demangle_read_expression_unary(struct cpp_demangle_data *ddata, const char *name, size_t len) { if (ddata == NULL || name == NULL || len == 0) return (0); if (!cpp_demangle_read_expression(ddata)) return (0); return (cpp_demangle_push_str(ddata, name, len)); } static int cpp_demangle_read_expression_trinary(struct cpp_demangle_data *ddata, const char *name1, size_t len1, const char *name2, size_t len2) { if (ddata == NULL || name1 == NULL || len1 == 0 || name2 == NULL || len2 == 0) return (0); if (!cpp_demangle_read_expression(ddata)) return (0); if (!cpp_demangle_push_str(ddata, name1, len1)) return (0); if (!cpp_demangle_read_expression(ddata)) return (0); if (!cpp_demangle_push_str(ddata, name2, len2)) return (0); return (cpp_demangle_read_expression(ddata)); } static int cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c, struct vector_type_qualifier *v) { size_t class_type_size, class_type_len, limit; const char *class_type; if (ddata == NULL || *ddata->cur != 'F' || v == NULL) return (0); ++ddata->cur; if (*ddata->cur == 'Y') { if (ext_c != NULL) *ext_c = 1; ++ddata->cur; } if (!cpp_demangle_read_type(ddata, 0)) return (0); if (*ddata->cur != 'E') { if (!cpp_demangle_push_str(ddata, "(", 1)) return (0); if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM)) { if ((class_type_size = ddata->class_type.size) == 0) return (0); class_type = ddata->class_type.container[class_type_size - 1]; if (class_type == NULL) return (0); if ((class_type_len = strlen(class_type)) == 0) return (0); if (!cpp_demangle_push_str(ddata, class_type, class_type_len)) return (0); if (!cpp_demangle_push_str(ddata, "::*", 3)) return (0); ++ddata->func_type; } else { if (!cpp_demangle_push_type_qualifier(ddata, v, (const char *) NULL)) return (0); vector_type_qualifier_dest(v); if (!vector_type_qualifier_init(v)) return (0); } if (!cpp_demangle_push_str(ddata, ")(", 2)) return (0); limit = 0; for (;;) { if (!cpp_demangle_read_type(ddata, 0)) return (0); if (*ddata->cur == 'E') break; if (limit++ > CPP_DEMANGLE_TRY_LIMIT) return (0); } if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM) == 1) { if (!cpp_demangle_push_type_qualifier(ddata, v, (const char *) NULL)) return (0); vector_type_qualifier_dest(v); if (!vector_type_qualifier_init(v)) return (0); } if (!cpp_demangle_push_str(ddata, ")", 1)) return (0); } ++ddata->cur; return (1); } /* read encoding, encoding are function name, data name, special-name */ static int cpp_demangle_read_encoding(struct cpp_demangle_data *ddata) { if (ddata == NULL || *ddata->cur == '\0') return (0); /* special name */ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { case SIMPLE_HASH('G', 'V'): /* sentry object for 1 time init */ if (!cpp_demangle_push_str(ddata, "guard variable for ", 20)) return (0); ddata->cur += 2; break; case SIMPLE_HASH('T', 'c'): /* virtual function covariant override thunk */ if (!cpp_demangle_push_str(ddata, "virtual function covariant override ", 36)) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); if (!cpp_demangle_read_offset(ddata)) return (0); if (!cpp_demangle_read_offset(ddata)) return (0); return (cpp_demangle_read_encoding(ddata)); case SIMPLE_HASH('T', 'D'): /* typeinfo common proxy */ break; case SIMPLE_HASH('T', 'h'): /* virtual function non-virtual override thunk */ if (cpp_demangle_push_str(ddata, "virtual function non-virtual override ", 38) == 0) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); if (!cpp_demangle_read_nv_offset(ddata)) return (0); return (cpp_demangle_read_encoding(ddata)); case SIMPLE_HASH('T', 'I'): /* typeinfo structure */ /* FALLTHROUGH */ case SIMPLE_HASH('T', 'S'): /* RTTI name (NTBS) */ if (!cpp_demangle_push_str(ddata, "typeinfo for ", 14)) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 1)); case SIMPLE_HASH('T', 'T'): /* VTT table */ if (!cpp_demangle_push_str(ddata, "VTT for ", 8)) return (0); ddata->cur += 2; return (cpp_demangle_read_type(ddata, 1)); case SIMPLE_HASH('T', 'v'): /* virtual function virtual override thunk */ if (!cpp_demangle_push_str(ddata, "virtual function virtual override ", 34)) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); if (!cpp_demangle_read_v_offset(ddata)) return (0); return (cpp_demangle_read_encoding(ddata)); case SIMPLE_HASH('T', 'V'): /* virtual table */ if (!cpp_demangle_push_str(ddata, "vtable for ", 12)) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 1)); }; return (cpp_demangle_read_name(ddata)); } static int cpp_demangle_read_local_name(struct cpp_demangle_data *ddata) { size_t limit; if (ddata == NULL) return (0); if (*(++ddata->cur) == '\0') return (0); if (!cpp_demangle_read_encoding(ddata)) return (0); limit = 0; for (;;) { if (!cpp_demangle_read_type(ddata, 1)) return (0); if (*ddata->cur == 'E') break; if (limit++ > CPP_DEMANGLE_TRY_LIMIT) return (0); } if (*(++ddata->cur) == '\0') return (0); if (ddata->paren == true) { if (!cpp_demangle_push_str(ddata, ")", 1)) return (0); ddata->paren = false; } if (*ddata->cur == 's') ++ddata->cur; else { if (!cpp_demangle_push_str(ddata, "::", 2)) return (0); if (!cpp_demangle_read_name(ddata)) return (0); } if (*ddata->cur == '_') { ++ddata->cur; while (ELFTC_ISDIGIT(*ddata->cur) != 0) ++ddata->cur; } return (1); } static int cpp_demangle_read_name(struct cpp_demangle_data *ddata) { struct vector_str *output, v; size_t p_idx, subst_str_len; int rtn; char *subst_str; if (ddata == NULL || *ddata->cur == '\0') return (0); output = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp : &ddata->output; subst_str = NULL; switch (*ddata->cur) { case 'S': return (cpp_demangle_read_subst(ddata)); case 'N': return (cpp_demangle_read_nested_name(ddata)); case 'Z': return (cpp_demangle_read_local_name(ddata)); }; if (!vector_str_init(&v)) return (0); p_idx = output->size; rtn = 0; if (!cpp_demangle_read_uqname(ddata)) goto clean; if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, &subst_str_len)) == NULL) goto clean; if (subst_str_len > 8 && strstr(subst_str, "operator") != NULL) { rtn = 1; goto clean; } if (!vector_str_push(&v, subst_str, subst_str_len)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &v)) goto clean; if (*ddata->cur == 'I') { p_idx = output->size; if (!cpp_demangle_read_tmpl_args(ddata)) goto clean; free(subst_str); if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, &subst_str_len)) == NULL) goto clean; if (!vector_str_push(&v, subst_str, subst_str_len)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &v)) goto clean; } rtn = 1; clean: free(subst_str); vector_str_dest(&v); return (rtn); } static int cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata) { struct vector_str *output, v; size_t limit, p_idx, subst_str_len; int rtn; char *subst_str; if (ddata == NULL || *ddata->cur != 'N') return (0); if (*(++ddata->cur) == '\0') return (0); while (*ddata->cur == 'r' || *ddata->cur == 'V' || *ddata->cur == 'K') { switch (*ddata->cur) { case 'r': ddata->mem_rst = true; break; case 'V': ddata->mem_vat = true; break; case 'K': ddata->mem_cst = true; break; }; ++ddata->cur; } output = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp : &ddata->output; if (!vector_str_init(&v)) return (0); rtn = 0; limit = 0; for (;;) { p_idx = output->size; switch (*ddata->cur) { case 'I': if (!cpp_demangle_read_tmpl_args(ddata)) goto clean; break; case 'S': if (!cpp_demangle_read_subst(ddata)) goto clean; break; case 'T': if (!cpp_demangle_read_tmpl_param(ddata)) goto clean; break; default: if (!cpp_demangle_read_uqname(ddata)) goto clean; }; if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, &subst_str_len)) == NULL) goto clean; if (!vector_str_push(&v, subst_str, subst_str_len)) { free(subst_str); goto clean; } free(subst_str); if (!cpp_demangle_push_subst_v(ddata, &v)) goto clean; if (*ddata->cur == 'E') break; else if (*ddata->cur != 'I' && *ddata->cur != 'C' && *ddata->cur != 'D') { if (!cpp_demangle_push_str(ddata, "::", 2)) goto clean; if (!vector_str_push(&v, "::", 2)) goto clean; } if (limit++ > CPP_DEMANGLE_TRY_LIMIT) goto clean; } ++ddata->cur; rtn = 1; clean: vector_str_dest(&v); return (rtn); } /* * read number * number ::= [n] */ static int cpp_demangle_read_number(struct cpp_demangle_data *ddata, long *rtn) { long len, negative_factor; if (ddata == NULL || rtn == NULL) return (0); negative_factor = 1; if (*ddata->cur == 'n') { negative_factor = -1; ++ddata->cur; } if (ELFTC_ISDIGIT(*ddata->cur) == 0) return (0); errno = 0; if ((len = strtol(ddata->cur, (char **) NULL, 10)) == 0 && errno != 0) return (0); while (ELFTC_ISDIGIT(*ddata->cur) != 0) ++ddata->cur; assert(len >= 0); assert(negative_factor == 1 || negative_factor == -1); *rtn = len * negative_factor; return (1); } static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *ddata) { if (ddata == NULL) return (0); if (!cpp_demangle_push_str(ddata, "offset : ", 9)) return (0); return (cpp_demangle_read_offset_number(ddata)); } /* read offset, offset are nv-offset, v-offset */ static int cpp_demangle_read_offset(struct cpp_demangle_data *ddata) { if (ddata == NULL) return (0); if (*ddata->cur == 'h') { ++ddata->cur; return (cpp_demangle_read_nv_offset(ddata)); } else if (*ddata->cur == 'v') { ++ddata->cur; return (cpp_demangle_read_v_offset(ddata)); } return (0); } static int cpp_demangle_read_offset_number(struct cpp_demangle_data *ddata) { bool negative; const char *start; if (ddata == NULL || *ddata->cur == '\0') return (0); /* offset could be negative */ if (*ddata->cur == 'n') { negative = true; start = ddata->cur + 1; } else { negative = false; start = ddata->cur; } while (*ddata->cur != '_') ++ddata->cur; if (negative && !cpp_demangle_push_str(ddata, "-", 1)) return (0); assert(start != NULL); if (!cpp_demangle_push_str(ddata, start, ddata->cur - start)) return (0); if (!cpp_demangle_push_str(ddata, " ", 1)) return (0); ++ddata->cur; return (1); } static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata) { size_t class_type_len, i, idx, p_idx; int p_func_type, rtn; char *class_type; if (ddata == NULL || *ddata->cur != 'M' || *(++ddata->cur) == '\0') return (0); p_idx = ddata->output.size; if (!cpp_demangle_read_type(ddata, 0)) return (0); if ((class_type = vector_str_substr(&ddata->output, p_idx, ddata->output.size - 1, &class_type_len)) == NULL) return (0); rtn = 0; idx = ddata->output.size; for (i = p_idx; i < idx; ++i) if (!vector_str_pop(&ddata->output)) goto clean1; if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM)) goto clean1; if (!vector_str_push(&ddata->class_type, class_type, class_type_len)) goto clean2; p_func_type = ddata->func_type; if (!cpp_demangle_read_type(ddata, 0)) goto clean3; if (p_func_type == ddata->func_type) { if (!cpp_demangle_push_str(ddata, " ", 1)) goto clean3; if (!cpp_demangle_push_str(ddata, class_type, class_type_len)) goto clean3; if (!cpp_demangle_push_str(ddata, "::*", 3)) goto clean3; } rtn = 1; clean3: if (!vector_str_pop(&ddata->class_type)) rtn = 0; clean2: if (!vector_read_cmd_pop(&ddata->cmd)) rtn = 0; clean1: free(class_type); return (rtn); } /* read source-name, source-name is */ static int cpp_demangle_read_sname(struct cpp_demangle_data *ddata) { long len; if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 || len <= 0 || cpp_demangle_push_str(ddata, ddata->cur, len) == 0) return (0); assert(ddata->output.size > 0); if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == 0) ddata->last_sname = ddata->output.container[ddata->output.size - 1]; ddata->cur += len; return (1); } static int cpp_demangle_read_subst(struct cpp_demangle_data *ddata) { long nth; if (ddata == NULL || *ddata->cur == '\0') return (0); /* abbreviations of the form Sx */ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { case SIMPLE_HASH('S', 'a'): /* std::allocator */ if (cpp_demangle_push_str(ddata, "std::allocator", 14) == 0) return (0); ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::allocator", 14)); return (1); case SIMPLE_HASH('S', 'b'): /* std::basic_string */ if (!cpp_demangle_push_str(ddata, "std::basic_string", 17)) return (0); ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::basic_string", 17)); return (1); case SIMPLE_HASH('S', 'd'): /* std::basic_iostream > */ if (!cpp_demangle_push_str(ddata, "std::iostream", 19)) return (0); ddata->last_sname = "iostream"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::iostream", 19)); return (1); case SIMPLE_HASH('S', 'i'): /* std::basic_istream > */ if (!cpp_demangle_push_str(ddata, "std::istream", 18)) return (0); ddata->last_sname = "istream"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::istream", 18)); return (1); case SIMPLE_HASH('S', 'o'): /* std::basic_ostream > */ if (!cpp_demangle_push_str(ddata, "std::ostream", 18)) return (0); ddata->last_sname = "istream"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::ostream", 18)); return (1); case SIMPLE_HASH('S', 's'): /* * std::basic_string, * std::allocator > * * a.k.a std::string */ if (!cpp_demangle_push_str(ddata, "std::string", 11)) return (0); ddata->last_sname = "string"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::string", 11)); return (1); case SIMPLE_HASH('S', 't'): /* std:: */ return (cpp_demangle_read_subst_std(ddata)); }; if (*(++ddata->cur) == '\0') return (0); /* substitution */ if (*ddata->cur == '_') return (cpp_demangle_get_subst(ddata, 0)); else { errno = 0; /* substitution number is base 36 */ if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 && errno != 0) return (0); /* first was '_', so increase one */ ++nth; while (*ddata->cur != '_') ++ddata->cur; assert(nth > 0); return (cpp_demangle_get_subst(ddata, nth)); } /* NOTREACHED */ return (0); } static int cpp_demangle_read_subst_std(struct cpp_demangle_data *ddata) { struct vector_str *output, v; size_t p_idx, subst_str_len; int rtn; char *subst_str; if (ddata == NULL) return (0); if (!vector_str_init(&v)) return (0); subst_str = NULL; rtn = 0; if (!cpp_demangle_push_str(ddata, "std::", 5)) goto clean; if (!vector_str_push(&v, "std::", 5)) goto clean; ddata->cur += 2; output = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; if (!cpp_demangle_read_uqname(ddata)) goto clean; if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, &subst_str_len)) == NULL) goto clean; if (!vector_str_push(&v, subst_str, subst_str_len)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &v)) goto clean; if (*ddata->cur == 'I') { p_idx = output->size; if (!cpp_demangle_read_tmpl_args(ddata)) goto clean; free(subst_str); if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, &subst_str_len)) == NULL) goto clean; if (!vector_str_push(&v, subst_str, subst_str_len)) goto clean; if (!cpp_demangle_push_subst_v(ddata, &v)) goto clean; } rtn = 1; clean: free(subst_str); vector_str_dest(&v); return (rtn); } static int cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata, const char *str, size_t len) { struct vector_str *output; size_t p_idx, substr_len; int rtn; char *subst_str, *substr; if (ddata == NULL || str == NULL || len == 0) return (0); output = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; substr = NULL; subst_str = NULL; if (!cpp_demangle_read_tmpl_args(ddata)) return (0); if ((substr = vector_str_substr(output, p_idx, output->size - 1, &substr_len)) == NULL) return (0); rtn = 0; if ((subst_str = malloc(sizeof(char) * (substr_len + len + 1))) == NULL) goto clean; memcpy(subst_str, str, len); memcpy(subst_str + len, substr, substr_len); subst_str[substr_len + len] = '\0'; if (!cpp_demangle_push_subst(ddata, subst_str, substr_len + len)) goto clean; rtn = 1; clean: free(subst_str); free(substr); return (rtn); } static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *ddata) { if (ddata == NULL || *ddata->cur == '\0') return (0); switch (*ddata->cur) { case 'L': return (cpp_demangle_read_expr_primary(ddata)); case 'X': return (cpp_demangle_read_expression(ddata)); }; return (cpp_demangle_read_type(ddata, 0)); } static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata) { struct vector_str *v; size_t arg_len, idx, limit, size; char *arg; if (ddata == NULL || *ddata->cur == '\0') return (0); ++ddata->cur; if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL)) return (0); if (!cpp_demangle_push_str(ddata, "<", 1)) return (0); limit = 0; v = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp : &ddata->output; for (;;) { idx = v->size; if (!cpp_demangle_read_tmpl_arg(ddata)) return (0); if ((arg = vector_str_substr(v, idx, v->size - 1, &arg_len)) == NULL) return (0); if (!vector_str_find(&ddata->tmpl, arg, arg_len) && !vector_str_push(&ddata->tmpl, arg, arg_len)) { free(arg); return (0); } free(arg); if (*ddata->cur == 'E') { ++ddata->cur; size = v->size; assert(size > 0); if (!strncmp(v->container[size - 1], ">", 1)) { if (!cpp_demangle_push_str(ddata, " >", 2)) return (0); } else if (!cpp_demangle_push_str(ddata, ">", 1)) return (0); break; } else if (*ddata->cur != 'I' && !cpp_demangle_push_str(ddata, ", ", 2)) return (0); if (limit++ > CPP_DEMANGLE_TRY_LIMIT) return (0); } return (vector_read_cmd_pop(&ddata->cmd)); } /* * Read template parameter that forms in 'T[number]_'. * This function much like to read_subst but only for types. */ static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *ddata) { long nth; if (ddata == NULL || *ddata->cur != 'T') return (0); ++ddata->cur; if (*ddata->cur == '_') return (cpp_demangle_get_tmpl_param(ddata, 0)); else { errno = 0; if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 && errno != 0) return (0); /* T_ is first */ ++nth; while (*ddata->cur != '_') ++ddata->cur; assert(nth > 0); return (cpp_demangle_get_tmpl_param(ddata, nth)); } /* NOTREACHED */ return (0); } static int cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit) { struct vector_type_qualifier v; struct vector_str *output; size_t p_idx, type_str_len; int extern_c, is_builtin; long len; char *type_str; if (ddata == NULL) return (0); output = &ddata->output; if (!strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) { cpp_demangle_gnu3_push_head++; output = &ddata->output_tmp; } else if (delimit == 1) { if (ddata->paren == false) { if (!cpp_demangle_push_str(ddata, "(", 1)) return (0); if (ddata->output.size < 2) return (0); ddata->paren = true; ddata->pfirst = true; /* Need pop function name */ if (ddata->subst.size == 1 && !vector_str_pop(&ddata->subst)) return (0); } if (ddata->pfirst) ddata->pfirst = false; else if (*ddata->cur != 'I' && !cpp_demangle_push_str(ddata, ", ", 2)) return (0); } assert(output != NULL); /* * [r, V, K] [P, R, C, G, U] builtin, function, class-enum, array * pointer-to-member, template-param, template-template-param, subst */ if (!vector_type_qualifier_init(&v)) return (0); extern_c = 0; is_builtin = 1; p_idx = output->size; type_str = NULL; again: /* builtin type */ switch (*ddata->cur) { case 'a': /* signed char */ if (!cpp_demangle_push_str(ddata, "signed char", 11)) goto clean; ++ddata->cur; goto rtn; case 'A': /* array type */ if (!cpp_demangle_read_array(ddata)) goto clean; is_builtin = 0; goto rtn; case 'b': /* bool */ if (!cpp_demangle_push_str(ddata, "bool", 4)) goto clean; ++ddata->cur; goto rtn; case 'C': /* complex pair */ if (!vector_type_qualifier_push(&v, TYPE_CMX)) goto clean; ++ddata->cur; goto again; case 'c': /* char */ if (!cpp_demangle_push_str(ddata, "char", 4)) goto clean; ++ddata->cur; goto rtn; case 'd': /* double */ if (!cpp_demangle_push_str(ddata, "double", 6)) goto clean; ++ddata->cur; goto rtn; case 'e': /* long double */ if (!cpp_demangle_push_str(ddata, "long double", 11)) goto clean; ++ddata->cur; goto rtn; case 'f': /* float */ if (!cpp_demangle_push_str(ddata, "float", 5)) goto clean; ++ddata->cur; goto rtn; case 'F': /* function */ if (!cpp_demangle_read_function(ddata, &extern_c, &v)) goto clean; is_builtin = 0; goto rtn; case 'g': /* __float128 */ if (!cpp_demangle_push_str(ddata, "__float128", 10)) goto clean; ++ddata->cur; goto rtn; case 'G': /* imaginary */ if (!vector_type_qualifier_push(&v, TYPE_IMG)) goto clean; ++ddata->cur; goto again; case 'h': /* unsigned char */ if (!cpp_demangle_push_str(ddata, "unsigned char", 13)) goto clean; ++ddata->cur; goto rtn; case 'i': /* int */ if (!cpp_demangle_push_str(ddata, "int", 3)) goto clean; ++ddata->cur; goto rtn; case 'j': /* unsigned int */ if (!cpp_demangle_push_str(ddata, "unsigned int", 12)) goto clean; ++ddata->cur; goto rtn; case 'K': /* const */ if (!vector_type_qualifier_push(&v, TYPE_CST)) goto clean; ++ddata->cur; goto again; case 'l': /* long */ if (!cpp_demangle_push_str(ddata, "long", 4)) goto clean; ++ddata->cur; goto rtn; case 'm': /* unsigned long */ if (!cpp_demangle_push_str(ddata, "unsigned long", 13)) goto clean; ++ddata->cur; goto rtn; case 'M': /* pointer to member */ if (!cpp_demangle_read_pointer_to_member(ddata)) goto clean; is_builtin = 0; goto rtn; case 'n': /* __int128 */ if (!cpp_demangle_push_str(ddata, "__int128", 8)) goto clean; ++ddata->cur; goto rtn; case 'o': /* unsigned __int128 */ if (!cpp_demangle_push_str(ddata, "unsigned _;int128", 17)) goto clean; ++ddata->cur; goto rtn; case 'P': /* pointer */ if (!vector_type_qualifier_push(&v, TYPE_PTR)) goto clean; ++ddata->cur; goto again; case 'r': /* restrict */ if (!vector_type_qualifier_push(&v, TYPE_RST)) goto clean; ++ddata->cur; goto again; case 'R': /* reference */ if (!vector_type_qualifier_push(&v, TYPE_REF)) goto clean; ++ddata->cur; goto again; case 's': /* short, local string */ if (!cpp_demangle_push_str(ddata, "short", 5)) goto clean; ++ddata->cur; goto rtn; case 'S': /* substitution */ if (!cpp_demangle_read_subst(ddata)) goto clean; is_builtin = 0; goto rtn; case 't': /* unsigned short */ if (!cpp_demangle_push_str(ddata, "unsigned short", 14)) goto clean; ++ddata->cur; goto rtn; case 'T': /* template parameter */ if (!cpp_demangle_read_tmpl_param(ddata)) goto clean; is_builtin = 0; goto rtn; case 'u': /* vendor extended builtin */ ++ddata->cur; if (!cpp_demangle_read_sname(ddata)) goto clean; is_builtin = 0; goto rtn; case 'U': /* vendor extended type qualifier */ if (!cpp_demangle_read_number(ddata, &len)) goto clean; if (len <= 0) goto clean; if (!vector_str_push(&v.ext_name, ddata->cur, len)) return (0); ddata->cur += len; goto again; case 'v': /* void */ if (!cpp_demangle_push_str(ddata, "void", 4)) goto clean; ++ddata->cur; goto rtn; case 'V': /* volatile */ if (!vector_type_qualifier_push(&v, TYPE_VAT)) goto clean; ++ddata->cur; goto again; case 'w': /* wchar_t */ if (!cpp_demangle_push_str(ddata, "wchar_t", 6)) goto clean; ++ddata->cur; goto rtn; case 'x': /* long long */ if (!cpp_demangle_push_str(ddata, "long long", 9)) goto clean; ++ddata->cur; goto rtn; case 'y': /* unsigned long long */ if (!cpp_demangle_push_str(ddata, "unsigned long long", 18)) goto clean; ++ddata->cur; goto rtn; case 'z': /* ellipsis */ if (!cpp_demangle_push_str(ddata, "ellipsis", 8)) goto clean; ++ddata->cur; goto rtn; }; if (!cpp_demangle_read_name(ddata)) goto clean; is_builtin = 0; rtn: if ((type_str = vector_str_substr(output, p_idx, output->size - 1, &type_str_len)) == NULL) goto clean; if (is_builtin == 0) { if (!vector_str_find(&ddata->subst, type_str, type_str_len) && !vector_str_push(&ddata->subst, type_str, type_str_len)) goto clean; } if (!cpp_demangle_push_type_qualifier(ddata, &v, type_str)) goto clean; free(type_str); vector_type_qualifier_dest(&v); if (cpp_demangle_gnu3_push_head > 0) { if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata) == 0) return (0); if (--cpp_demangle_gnu3_push_head > 0) return (1); if (!vector_str_push(&ddata->output_tmp, " ", 1)) return (0); if (!vector_str_push_vector_head(&ddata->output, &ddata->output_tmp)) return (0); vector_str_dest(&ddata->output_tmp); if (!vector_str_init(&ddata->output_tmp)) return (0); if (!cpp_demangle_push_str(ddata, "(", 1)) return (0); ddata->paren = true; ddata->pfirst = true; } return (1); clean: free(type_str); vector_type_qualifier_dest(&v); return (0); } /* * read unqualified-name, unqualified name are operator-name, ctor-dtor-name, * source-name */ static int cpp_demangle_read_uqname(struct cpp_demangle_data *ddata) { size_t len; if (ddata == NULL || *ddata->cur == '\0') return (0); /* operator name */ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { case SIMPLE_HASH('a', 'a'): /* operator && */ if (!cpp_demangle_push_str(ddata, "operator&&", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'd'): /* operator & (unary) */ if (!cpp_demangle_push_str(ddata, "operator&", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'n'): /* operator & */ if (!cpp_demangle_push_str(ddata, "operator&", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'N'): /* operator &= */ if (!cpp_demangle_push_str(ddata, "operator&=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'S'): /* operator = */ if (!cpp_demangle_push_str(ddata, "operator=", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'l'): /* operator () */ if (!cpp_demangle_push_str(ddata, "operator()", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'm'): /* operator , */ if (!cpp_demangle_push_str(ddata, "operator,", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'o'): /* operator ~ */ if (!cpp_demangle_push_str(ddata, "operator~", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'v'): /* operator (cast) */ if (!cpp_demangle_push_str(ddata, "operator(cast)", 14)) return (0); ddata->cur += 2; return (cpp_demangle_read_type(ddata, 1)); case SIMPLE_HASH('d', 'a'): /* operator delete [] */ if (!cpp_demangle_push_str(ddata, "operator delete []", 18)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'e'): /* operator * (unary) */ if (!cpp_demangle_push_str(ddata, "operator*", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'l'): /* operator delete */ if (!cpp_demangle_push_str(ddata, "operator delete", 15)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'v'): /* operator / */ if (!cpp_demangle_push_str(ddata, "operator/", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'V'): /* operator /= */ if (!cpp_demangle_push_str(ddata, "operator/=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'o'): /* operator ^ */ if (!cpp_demangle_push_str(ddata, "operator^", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'O'): /* operator ^= */ if (!cpp_demangle_push_str(ddata, "operator^=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'q'): /* operator == */ if (!cpp_demangle_push_str(ddata, "operator==", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('g', 'e'): /* operator >= */ if (!cpp_demangle_push_str(ddata, "operator>=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('g', 't'): /* operator > */ if (!cpp_demangle_push_str(ddata, "operator>", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('i', 'x'): /* operator [] */ if (!cpp_demangle_push_str(ddata, "operator[]", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 'e'): /* operator <= */ if (!cpp_demangle_push_str(ddata, "operator<=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 's'): /* operator << */ if (!cpp_demangle_push_str(ddata, "operator<<", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 'S'): /* operator <<= */ if (!cpp_demangle_push_str(ddata, "operator<<=", 11)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 't'): /* operator < */ if (!cpp_demangle_push_str(ddata, "operator<", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'i'): /* operator - */ if (!cpp_demangle_push_str(ddata, "operator-", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'I'): /* operator -= */ if (!cpp_demangle_push_str(ddata, "operator-=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'l'): /* operator * */ if (!cpp_demangle_push_str(ddata, "operator*", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'L'): /* operator *= */ if (!cpp_demangle_push_str(ddata, "operator*=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'm'): /* operator -- */ if (!cpp_demangle_push_str(ddata, "operator--", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'a'): /* operator new[] */ if (!cpp_demangle_push_str(ddata, "operator new []", 15)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'e'): /* operator != */ if (!cpp_demangle_push_str(ddata, "operator!=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'g'): /* operator - (unary) */ if (!cpp_demangle_push_str(ddata, "operator-", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 't'): /* operator ! */ if (!cpp_demangle_push_str(ddata, "operator!", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'w'): /* operator new */ if (!cpp_demangle_push_str(ddata, "operator new", 12)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'o'): /* operator || */ if (!cpp_demangle_push_str(ddata, "operator||", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'r'): /* operator | */ if (!cpp_demangle_push_str(ddata, "operator|", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'R'): /* operator |= */ if (!cpp_demangle_push_str(ddata, "operator|=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'l'): /* operator + */ if (!cpp_demangle_push_str(ddata, "operator+", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'L'): /* operator += */ if (!cpp_demangle_push_str(ddata, "operator+=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'm'): /* operator ->* */ if (!cpp_demangle_push_str(ddata, "operator->*", 11)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'p'): /* operator ++ */ if (!cpp_demangle_push_str(ddata, "operator++", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 's'): /* operator + (unary) */ if (!cpp_demangle_push_str(ddata, "operator+", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 't'): /* operator -> */ if (!cpp_demangle_push_str(ddata, "operator->", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('q', 'u'): /* operator ? */ if (!cpp_demangle_push_str(ddata, "operator?", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'm'): /* operator % */ if (!cpp_demangle_push_str(ddata, "operator%", 9)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'M'): /* operator %= */ if (!cpp_demangle_push_str(ddata, "operator%=", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 's'): /* operator >> */ if (!cpp_demangle_push_str(ddata, "operator>>", 10)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'S'): /* operator >>= */ if (!cpp_demangle_push_str(ddata, "operator>>=", 11)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'z'): /* operator sizeof */ if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('s', 'r'): /* scope resolution operator */ if (!cpp_demangle_push_str(ddata, "scope resolution operator ", 26)) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('s', 'v'): /* operator sizeof */ if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16)) return (0); ddata->cur += 2; return (1); }; /* vendor extened operator */ if (*ddata->cur == 'v' && ELFTC_ISDIGIT(*(ddata->cur + 1))) { if (!cpp_demangle_push_str(ddata, "vendor extened operator ", 24)) return (0); if (!cpp_demangle_push_str(ddata, ddata->cur + 1, 1)) return (0); ddata->cur += 2; return (cpp_demangle_read_sname(ddata)); } /* ctor-dtor-name */ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { case SIMPLE_HASH('C', '1'): /* FALLTHROUGH */ case SIMPLE_HASH('C', '2'): /* FALLTHROUGH */ case SIMPLE_HASH('C', '3'): if (ddata->last_sname == NULL) return (0); if ((len = strlen(ddata->last_sname)) == 0) return (0); if (!cpp_demangle_push_str(ddata, "::", 2)) return (0); if (!cpp_demangle_push_str(ddata, ddata->last_sname, len)) return (0); ddata->cur +=2; return (1); case SIMPLE_HASH('D', '0'): /* FALLTHROUGH */ case SIMPLE_HASH('D', '1'): /* FALLTHROUGH */ case SIMPLE_HASH('D', '2'): if (ddata->last_sname == NULL) return (0); if ((len = strlen(ddata->last_sname)) == 0) return (0); if (!cpp_demangle_push_str(ddata, "::~", 3)) return (0); if (!cpp_demangle_push_str(ddata, ddata->last_sname, len)) return (0); ddata->cur +=2; return (1); }; /* source name */ if (ELFTC_ISDIGIT(*ddata->cur) != 0) return (cpp_demangle_read_sname(ddata)); /* local source name */ if (*ddata->cur == 'L') return (cpp_demangle_local_source_name(ddata)); return (1); } /* * Read local source name. * * References: * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 * http://gcc.gnu.org/viewcvs?view=rev&revision=124467 */ static int cpp_demangle_local_source_name(struct cpp_demangle_data *ddata) { /* L */ if (ddata == NULL || *ddata->cur != 'L') return (0); ++ddata->cur; /* source name */ if (!cpp_demangle_read_sname(ddata)) return (0); /* discriminator */ if (*ddata->cur == '_') { ++ddata->cur; while (ELFTC_ISDIGIT(*ddata->cur) != 0) ++ddata->cur; } return (1); } static int cpp_demangle_read_v_offset(struct cpp_demangle_data *ddata) { if (ddata == NULL) return (0); if (!cpp_demangle_push_str(ddata, "offset : ", 9)) return (0); if (!cpp_demangle_read_offset_number(ddata)) return (0); if (!cpp_demangle_push_str(ddata, "virtual offset : ", 17)) return (0); return (!cpp_demangle_read_offset_number(ddata)); } /* * Decode floating point representation to string * Return new allocated string or NULL * * Todo * Replace these functions to macro. */ static char * decode_fp_to_double(const char *p, size_t len) { double f; size_t rtn_len, limit, i; int byte; char *rtn; if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(double)) return (NULL); memset(&f, 0, sizeof(double)); for (i = 0; i < len / 2; ++i) { byte = hex_to_dec(p[len - i * 2 - 1]) + hex_to_dec(p[len - i * 2 - 2]) * 16; if (byte < 0 || byte > 255) return (NULL); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN ((unsigned char *)&f)[i] = (unsigned char)(byte); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ ((unsigned char *)&f)[sizeof(double) - i - 1] = (unsigned char)(byte); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ } rtn_len = 64; limit = 0; again: if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) return (NULL); if (snprintf(rtn, rtn_len, "%fld", f) >= (int)rtn_len) { free(rtn); if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) return (NULL); rtn_len *= BUFFER_GROWFACTOR; goto again; } return rtn; } static char * decode_fp_to_float(const char *p, size_t len) { size_t i, rtn_len, limit; float f; int byte; char *rtn; if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(float)) return (NULL); memset(&f, 0, sizeof(float)); for (i = 0; i < len / 2; ++i) { byte = hex_to_dec(p[len - i * 2 - 1]) + hex_to_dec(p[len - i * 2 - 2]) * 16; if (byte < 0 || byte > 255) return (NULL); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN ((unsigned char *)&f)[i] = (unsigned char)(byte); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ ((unsigned char *)&f)[sizeof(float) - i - 1] = (unsigned char)(byte); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ } rtn_len = 64; limit = 0; again: if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) return (NULL); if (snprintf(rtn, rtn_len, "%ff", f) >= (int)rtn_len) { free(rtn); if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) return (NULL); rtn_len *= BUFFER_GROWFACTOR; goto again; } return rtn; } static char * decode_fp_to_float128(const char *p, size_t len) { long double f; size_t rtn_len, limit, i; int byte; unsigned char buf[FLOAT_QUADRUPLE_BYTES]; char *rtn; switch(sizeof(long double)) { case FLOAT_QUADRUPLE_BYTES: return (decode_fp_to_long_double(p, len)); case FLOAT_EXTENED_BYTES: if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > FLOAT_QUADRUPLE_BYTES) return (NULL); memset(buf, 0, FLOAT_QUADRUPLE_BYTES); for (i = 0; i < len / 2; ++i) { byte = hex_to_dec(p[len - i * 2 - 1]) + hex_to_dec(p[len - i * 2 - 2]) * 16; if (byte < 0 || byte > 255) return (NULL); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN buf[i] = (unsigned char)(byte); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ buf[FLOAT_QUADRUPLE_BYTES - i -1] = (unsigned char)(byte); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ } memset(&f, 0, FLOAT_EXTENED_BYTES); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN memcpy(&f, buf, FLOAT_EXTENED_BYTES); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ memcpy(&f, buf + 6, FLOAT_EXTENED_BYTES); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ rtn_len = 256; limit = 0; again: if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) return (NULL); if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) { free(rtn); if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) return (NULL); rtn_len *= BUFFER_GROWFACTOR; goto again; } return (rtn); default: return (NULL); } } static char * decode_fp_to_float80(const char *p, size_t len) { long double f; size_t rtn_len, limit, i; int byte; unsigned char buf[FLOAT_EXTENED_BYTES]; char *rtn; switch(sizeof(long double)) { case FLOAT_QUADRUPLE_BYTES: if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > FLOAT_EXTENED_BYTES) return (NULL); memset(buf, 0, FLOAT_EXTENED_BYTES); for (i = 0; i < len / 2; ++i) { byte = hex_to_dec(p[len - i * 2 - 1]) + hex_to_dec(p[len - i * 2 - 2]) * 16; if (byte < 0 || byte > 255) return (NULL); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN buf[i] = (unsigned char)(byte); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ buf[FLOAT_EXTENED_BYTES - i -1] = (unsigned char)(byte); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ } memset(&f, 0, FLOAT_QUADRUPLE_BYTES); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN memcpy(&f, buf, FLOAT_EXTENED_BYTES); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ memcpy((unsigned char *)(&f) + 6, buf, FLOAT_EXTENED_BYTES); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ rtn_len = 256; limit = 0; again: if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) return (NULL); if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) { free(rtn); if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) return (NULL); rtn_len *= BUFFER_GROWFACTOR; goto again; } return (rtn); case FLOAT_EXTENED_BYTES: return (decode_fp_to_long_double(p, len)); default: return (NULL); } } static char * decode_fp_to_long_double(const char *p, size_t len) { long double f; size_t rtn_len, limit, i; int byte; char *rtn; if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(long double)) return (NULL); memset(&f, 0, sizeof(long double)); for (i = 0; i < len / 2; ++i) { byte = hex_to_dec(p[len - i * 2 - 1]) + hex_to_dec(p[len - i * 2 - 2]) * 16; if (byte < 0 || byte > 255) return (NULL); #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN ((unsigned char *)&f)[i] = (unsigned char)(byte); #else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ ((unsigned char *)&f)[sizeof(long double) - i - 1] = (unsigned char)(byte); #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ } rtn_len = 256; limit = 0; again: if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) return (NULL); if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) { free(rtn); if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) return (NULL); rtn_len *= BUFFER_GROWFACTOR; goto again; } return (rtn); } /* Simple hex to integer function used by decode_to_* function. */ static int hex_to_dec(char c) { switch (c) { case '0': return (0); case '1': return (1); case '2': return (2); case '3': return (3); case '4': return (4); case '5': return (5); case '6': return (6); case '7': return (7); case '8': return (8); case '9': return (9); case 'a': return (10); case 'b': return (11); case 'c': return (12); case 'd': return (13); case 'e': return (14); case 'f': return (15); default: return (-1); }; } /** * @brief Test input string is mangled by IA-64 C++ ABI style. * * Test string heads with "_Z" or "_GLOBAL__I_". * @return Return 0 at false. */ bool is_cpp_mangled_gnu3(const char *org) { size_t len; len = strlen(org); return ((len > 2 && *org == '_' && *(org + 1) == 'Z') || (len > 11 && !strncmp(org, "_GLOBAL__I_", 11))); } static void vector_read_cmd_dest(struct vector_read_cmd *v) { if (v == NULL) return; free(v->r_container); } /* return -1 at failed, 0 at not found, 1 at found. */ static int vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst) { size_t i; if (v == NULL || dst == READ_FAIL) return (-1); for (i = 0; i < v->size; ++i) if (v->r_container[i] == dst) return (1); return (0); } static int vector_read_cmd_init(struct vector_read_cmd *v) { if (v == NULL) return (0); v->size = 0; v->capacity = VECTOR_DEF_CAPACITY; if ((v->r_container = malloc(sizeof(enum read_cmd) * v->capacity)) == NULL) return (0); return (1); } static int vector_read_cmd_pop(struct vector_read_cmd *v) { if (v == NULL || v->size == 0) return (0); --v->size; v->r_container[v->size] = READ_FAIL; return (1); } static int vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd) { enum read_cmd *tmp_r_ctn; size_t tmp_cap; size_t i; if (v == NULL) return (0); if (v->size == v->capacity) { tmp_cap = v->capacity * BUFFER_GROWFACTOR; if ((tmp_r_ctn = malloc(sizeof(enum read_cmd) * tmp_cap)) == NULL) return (0); for (i = 0; i < v->size; ++i) tmp_r_ctn[i] = v->r_container[i]; free(v->r_container); v->r_container = tmp_r_ctn; v->capacity = tmp_cap; } v->r_container[v->size] = cmd; ++v->size; return (1); } static void vector_type_qualifier_dest(struct vector_type_qualifier *v) { if (v == NULL) return; free(v->q_container); vector_str_dest(&v->ext_name); } /* size, capacity, ext_name */ static int vector_type_qualifier_init(struct vector_type_qualifier *v) { if (v == NULL) return (0); v->size = 0; v->capacity = VECTOR_DEF_CAPACITY; if ((v->q_container = malloc(sizeof(enum type_qualifier) * v->capacity)) == NULL) return (0); assert(v->q_container != NULL); if (vector_str_init(&v->ext_name) == false) { free(v->q_container); return (0); } return (1); } static int vector_type_qualifier_push(struct vector_type_qualifier *v, enum type_qualifier t) { enum type_qualifier *tmp_ctn; size_t tmp_cap; size_t i; if (v == NULL) return (0); if (v->size == v->capacity) { tmp_cap = v->capacity * BUFFER_GROWFACTOR; if ((tmp_ctn = malloc(sizeof(enum type_qualifier) * tmp_cap)) == NULL) return (0); for (i = 0; i < v->size; ++i) tmp_ctn[i] = v->q_container[i]; free(v->q_container); v->q_container = tmp_ctn; v->capacity = tmp_cap; } v->q_container[v->size] = t; ++v->size; return (1); } diff --git a/mk/elftoolchain.lib.mk b/mk/elftoolchain.lib.mk index fab71507cb2c..f62dfc0ffdcc 100644 --- a/mk/elftoolchain.lib.mk +++ b/mk/elftoolchain.lib.mk @@ -1,61 +1,64 @@ # -# $Id: elftoolchain.lib.mk 2796 2012-12-19 12:44:09Z jkoshy $ +# $Id: elftoolchain.lib.mk 3026 2014-04-18 16:20:30Z jkoshy $ # .if !defined(TOP) .error Make variable \"TOP\" has not been defined. .endif .include "${TOP}/mk/elftoolchain.os.mk" .include # Support a 'clobber' target. -clobber: clean .PHONY +clobber: clean os-specific-clobber .PHONY + +# Remove '.depend' files on a "make clean". +CLEANFILES+= .depend # Adjust CFLAGS CFLAGS+= -I. # OBJDIR CFLAGS+= -I${.CURDIR} # Sources CFLAGS+= -I${TOP}/common # common code .if defined(LDADD) _LDADD_LIBELF=${LDADD:M-lelf} .if !empty(_LDADD_LIBELF) CFLAGS+= -I${TOP}/libelf LDFLAGS+= -L${TOP}/libelf .endif .endif # Note: include the M4 ruleset after bsd.lib.mk. .include "${TOP}/mk/elftoolchain.m4.mk" .if defined(DEBUG) CFLAGS:= ${CFLAGS:N-O*} -g .endif .if ${OS_HOST} == "DragonFly" || ${OS_HOST} == "FreeBSD" # Install headers too, in the 'install' phase. install: includes .elif ${OS_HOST} == "Linux" || ${OS_HOST} == "NetBSD" || ${OS_HOST} == "Minix" install: incinstall .elif ${OS_HOST} == "OpenBSD" # OpenBSD's standard make ruleset does not install header files. Provide # an alternative. NOBINMODE?= 444 install: ${INCS} incinstall .for inc in ${INCS} incinstall:: ${DESTDIR}${INCSDIR}/${inc} .PRECIOUS: ${DESTDIR}${INCSDIR}/${inc} ${DESTDIR}${INCSDIR}/${inc}: ${inc} cmp -s $> $@ > /dev/null 2>&1 || \ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${NOBINMODE} $> $@ .endfor .endif # OpenBSD # Bring in rules related to test code. .include "${TOP}/mk/elftoolchain.test.mk" diff --git a/mk/elftoolchain.os.mk b/mk/elftoolchain.os.mk index 31d37959f6bb..ab7c227dfeee 100644 --- a/mk/elftoolchain.os.mk +++ b/mk/elftoolchain.os.mk @@ -1,22 +1,26 @@ # -# $Id: elftoolchain.os.mk 2068 2011-10-26 15:49:07Z jkoshy $ +# $Id: elftoolchain.os.mk 2985 2014-03-06 03:24:35Z jkoshy $ # # OS specific build instructions .if !defined(OS_HOST) # Determine the host operating system flavor. OS_HOST != uname -s # Bring in OS-specific Makefiles, if they exist .if exists(${TOP}/mk/os.${OS_HOST}.mk) .include "${TOP}/mk/os.${OS_HOST}.mk" .endif # Bring in per-subproject OS-specific Makefiles, if they exist .if exists(${.CURDIR}/os.${OS_HOST}.mk) .include "${.CURDIR}/os.${OS_HOST}.mk" .endif +# Supply an OS-specific "clobber" rule, if one was not specified. +.if !target(os-specific-clobber) +os-specific-clobber: .PHONY +.endif .endif diff --git a/mk/elftoolchain.prog.mk b/mk/elftoolchain.prog.mk index 8d822cdf58ea..f19902a9a830 100644 --- a/mk/elftoolchain.prog.mk +++ b/mk/elftoolchain.prog.mk @@ -1,86 +1,86 @@ # # Rules for building programs. # -# $Id: elftoolchain.prog.mk 2796 2012-12-19 12:44:09Z jkoshy $ +# $Id: elftoolchain.prog.mk 2985 2014-03-06 03:24:35Z jkoshy $ .if !defined(TOP) .error Make variable \"TOP\" has not been defined. .endif .include "${TOP}/mk/elftoolchain.os.mk" LIBDWARF?= ${TOP}/libdwarf LIBELF?= ${TOP}/libelf LIBELFTC?= ${TOP}/libelftc BINDIR?= /usr/bin CFLAGS+= -I. -I${.CURDIR} -I${TOP}/common CLEANFILES+= .depend .if defined(LDADD) _LDADD_LIBDWARF=${LDADD:M-ldwarf} .if !empty(_LDADD_LIBDWARF) CFLAGS+= -I${TOP}/libdwarf LDFLAGS+= -L${TOP}/libdwarf .endif _LDADD_LIBELF=${LDADD:M-lelf} .if !empty(_LDADD_LIBELF) CFLAGS+= -I${TOP}/libelf LDFLAGS+= -L${TOP}/libelf .endif _LDADD_LIBELFTC=${LDADD:M-lelftc} .if !empty(_LDADD_LIBELFTC) CFLAGS+= -I${TOP}/libelftc LDFLAGS+= -L${TOP}/libelftc .endif .endif # # Handle lex(1) and yacc(1) in a portable fashion. # # New makefile variables used: # # LSRC -- a lexer definition suitable for use with lex(1) # YSRC -- a parser definition for use with yacc(1) # Use standard rules from for building lexers. .if defined(LSRC) SRCS+= ${LSRC} .endif # Handle the generation of yacc based parsers. # If the program uses a lexer, add an automatic dependency # on the generated parser header. .if defined(YSRC) .for _Y in ${YSRC} SRCS+= ${_Y:R}.c CLEANFILES+= ${_Y:R}.c ${_Y:R}.h ${_Y:R}.c ${_Y:R}.h: ${_Y} ${YACC} -d -o ${_Y:R}.c ${.ALLSRC} .if defined(LSRC) .for _L in ${LSRC} ${_L:R}.o: ${_Y:R}.h .endfor .endif .endfor .endif .include # Note: include the M4 ruleset after bsd.prog.mk. .include "${TOP}/mk/elftoolchain.m4.mk" # Support a 'clobber' target. -clobber: clean .PHONY +clobber: clean os-specific-clobber .PHONY .if defined(DEBUG) CFLAGS:= ${CFLAGS:N-O*} -g .endif # Bring in rules related to test code. .include "${TOP}/mk/elftoolchain.test.mk" diff --git a/mk/elftoolchain.subdir.mk b/mk/elftoolchain.subdir.mk index c41878d2f5c6..fa3c60e07187 100644 --- a/mk/elftoolchain.subdir.mk +++ b/mk/elftoolchain.subdir.mk @@ -1,19 +1,19 @@ # # Rules for recursing into directories -# $Id: elftoolchain.subdir.mk 2292 2011-12-04 08:09:17Z jkoshy $ +# $Id: elftoolchain.subdir.mk 3023 2014-04-17 18:06:06Z jkoshy $ # Pass down 'test' as a valid target. .include "$(TOP)/mk/elftoolchain.os.mk" .if ${OS_HOST} == DragonFly clobber test:: _SUBDIR .elif ${OS_HOST} == FreeBSD SUBDIR_TARGETS+= clobber test .elif ${OS_HOST} == OpenBSD clobber test:: _SUBDIRUSE -.else # NetBSD -TARGETS+= clobber test +.else # NetBSD, pmake on Linux +TARGETS+= cleandepend clobber test .endif .include diff --git a/test/libelf/Makefile b/mk/elftoolchain.tetbase.mk similarity index 55% copy from test/libelf/Makefile copy to mk/elftoolchain.tetbase.mk index 903221d9bafa..6eeebc1da722 100644 --- a/test/libelf/Makefile +++ b/mk/elftoolchain.tetbase.mk @@ -1,36 +1,46 @@ -# $Id: Makefile 2137 2011-11-10 13:09:30Z jkoshy $ +# $Id$ -TOP = ../.. +# Convenience rules for the top level directory containing a TET-based test +# suite. + +.if !defined(TOP) +.error Make variable \"TOP\" has not been defined. +.endif .include "${TOP}/mk/elftoolchain.tetvars.mk" +.MAIN: all +.PHONY: clobber execute tccbuild tccclean test + + +# Set up the environment for invoking "tcc", based on the target +# specified. + .if !defined(TET_EXECUTE) TET_EXECUTE= ${.OBJDIR} .endif .if make(tccbuild) TET_OPTIONS+= -b .endif .if make(tccclean) TET_OPTIONS+= -c .endif .if make(execute) || make(test) TET_OPTIONS+= -e .endif -.MAIN: all - -.PHONY: clobber execute tccbuild tccclean test - execute tccbuild tccclean test: TET_ROOT=${TET_ROOT} TET_EXECUTE=${TET_EXECUTE} \ TET_SUITE_ROOT=${.CURDIR} ${TET_ROOT}/bin/tcc ${TET_OPTIONS} . clobber: clean rm -rf ${TET_RESULTS_DIR} ${TET_TMP_DIR} -SUBDIR= tset - -.include +# Ensure that a 'make test' does not recurse further into the test suite's +# directory hierarchy. +.if !make(test) +.include "${TOP}/mk/elftoolchain.subdir.mk" +.endif diff --git a/mk/os.Linux.mk b/mk/os.Linux.mk index 553c3e14bc32..a8208c8a846f 100644 --- a/mk/os.Linux.mk +++ b/mk/os.Linux.mk @@ -1,21 +1,29 @@ -# $Id: os.Linux.mk 2569 2012-09-04 16:34:04Z jkoshy $ +# $Id: os.Linux.mk 3103 2014-11-02 10:07:01Z jkoshy $ # -# Build recipes for Debian GNU/Linux based operating systems. +# Build recipes for GNU/Linux based operating systems. + +OS_DISTRIBUTION != lsb_release -s -i || echo unknown +OS_DISTRIBUTION_VERSION != lsb_release -s -r || echo unknown + +.if ${OS_DISTRIBUTION} == "unknown" || \ + ${OS_DISTRIBUTION_VERSION} == "unknown" +.error ERROR: Unknown host OS distribution. +.endif MKDOC?= yes # Build documentation. MKLINT?= no MKPIC?= no MKNOWEB?= yes # Build literate programs. MKTESTS?= yes # Enable the test suites. MKTEX?= yes # Build TeX-based documentation. OBJECT_FORMAT= ELF # work around a bug in the pmake package YFLAGS+= -d # force bison to write y.tab.h EPSTOPDF?= /usr/bin/epstopdf MAKEINDEX?= /usr/bin/makeindex MPOST?= /usr/bin/mpost MPOSTTEX?= /usr/bin/latex NOWEB?= /usr/bin/noweb PDFLATEX?= /usr/bin/pdflatex diff --git a/mk/os.NetBSD.mk b/mk/os.NetBSD.mk index 99d6b9953e72..6ebd1c193e1f 100644 --- a/mk/os.NetBSD.mk +++ b/mk/os.NetBSD.mk @@ -1,13 +1,21 @@ -# $Id: os.NetBSD.mk 2569 2012-09-04 16:34:04Z jkoshy $ +# $Id: os.NetBSD.mk 2986 2014-03-06 03:29:12Z jkoshy $ # # Build recipes for NetBSD. LDSTATIC?= -static # link programs statically MKDOC?= yes # Build documentation. MKLINT?= no # lint dies with a sigbus MKTESTS?= yes # Enable the test suites. MKNOWEB?= no # Build literate programs. # Literate programming utility. NOWEB?= /usr/pkgsrc/bin/noweb + +# NetBSD's 'clean' target does not remove 'cat[0-9]' and 'html[0-9]' +# files generate from manual page sources. Augment the 'clobber' +# target to remove these. +os-specific-clobber: .PHONY +.for f in cat html + rm -f ${MANPAGES:@M@${M:R}.$f${M:E}@} +.endfor diff --git a/nm/nm.c b/nm/nm.c index 6c10e0dbf586..9afe0baa9b63 100644 --- a/nm/nm.c +++ b/nm/nm.c @@ -1,2096 +1,2096 @@ /*- * Copyright (c) 2007 Hyogeol Lee * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: nm.c 2484 2012-04-07 15:52:05Z kaiwang27 $"); +ELFTC_VCSID("$Id: nm.c 3124 2014-12-21 05:46:28Z kaiwang27 $"); /* symbol information list */ STAILQ_HEAD(sym_head, sym_entry); struct sym_entry { char *name; GElf_Sym *sym; STAILQ_ENTRY(sym_entry) sym_entries; }; typedef int (*fn_sort)(const void *, const void *); typedef void (*fn_elem_print)(char, const char *, const GElf_Sym *, const char *); typedef void (*fn_sym_print)(const GElf_Sym *); typedef int (*fn_filter)(char, const GElf_Sym *, const char *); /* output filter list */ -SLIST_HEAD(filter_head, filter_entry) nm_out_filter = +static SLIST_HEAD(filter_head, filter_entry) nm_out_filter = SLIST_HEAD_INITIALIZER(nm_out_filter); struct filter_entry { fn_filter fn; SLIST_ENTRY(filter_entry) filter_entries; }; struct sym_print_data { struct sym_head *headp; size_t sh_num, list_num; const char *t_table, **s_table, *filename, *objname; }; struct nm_prog_info { const char *name; const char *def_filename; }; /* List for line number information. */ struct line_info_entry { uint64_t addr; /* address */ uint64_t line; /* line number */ char *file; /* file name with path */ SLIST_ENTRY(line_info_entry) entries; }; SLIST_HEAD(line_info_head, line_info_entry); /* List for function line number information. */ struct func_info_entry { char *name; /* function name */ char *file; /* file name with path */ uint64_t lowpc; /* low address */ uint64_t highpc; /* high address */ uint64_t line; /* line number */ SLIST_ENTRY(func_info_entry) entries; }; SLIST_HEAD(func_info_head, func_info_entry); /* List for variable line number information. */ struct var_info_entry { char *name; /* variable name */ char *file; /* file name with path */ uint64_t addr; /* address */ uint64_t line; /* line number */ SLIST_ENTRY(var_info_entry) entries; }; SLIST_HEAD(var_info_head, var_info_entry); /* output numric type */ enum radix { RADIX_OCT, RADIX_HEX, RADIX_DEC }; /* output symbol type, PRINT_SYM_DYN for dynamic symbol only */ enum print_symbol { PRINT_SYM_SYM, PRINT_SYM_DYN }; /* output name type */ enum print_name { PRINT_NAME_NONE, PRINT_NAME_FULL, PRINT_NAME_MULTI }; struct nm_prog_options { enum print_symbol print_symbol; enum print_name print_name; enum radix t; int demangle_type; bool print_debug; bool print_armap; int print_size; bool debug_line; int def_only; bool undef_only; int sort_size; bool sort_reverse; int no_demangle; /* * function pointer to sort symbol list. * possible function - cmp_name, cmp_none, cmp_size, cmp_value */ fn_sort sort_fn; /* * function pointer to print symbol elem. * possible function - sym_elem_print_all * sym_elem_print_all_portable * sym_elem_print_all_sysv */ fn_elem_print elem_print_fn; fn_sym_print value_print_fn; fn_sym_print size_print_fn; }; #define CHECK_SYM_PRINT_DATA(p) (p->headp == NULL || p->sh_num == 0 || \ p->t_table == NULL || p->s_table == NULL || p->filename == NULL) #define IS_SYM_TYPE(t) ((t) == '?' || isalpha((t)) != 0) #define IS_UNDEF_SYM_TYPE(t) ((t) == 'U' || (t) == 'v' || (t) == 'w') #define UNUSED(p) ((void)p) static int cmp_name(const void *, const void *); static int cmp_none(const void *, const void *); static int cmp_size(const void *, const void *); static int cmp_value(const void *, const void *); static void filter_dest(void); static int filter_insert(fn_filter); static void get_opt(int, char **); static int get_sym(Elf *, struct sym_head *, int, size_t, size_t, const char *, const char **, int); static const char * get_sym_name(Elf *, const GElf_Sym *, size_t, const char **, int); static char get_sym_type(const GElf_Sym *, const char *); static void global_dest(void); static void global_init(void); static bool is_sec_data(GElf_Shdr *); static bool is_sec_debug(const char *); static bool is_sec_nobits(GElf_Shdr *); static bool is_sec_readonly(GElf_Shdr *); static bool is_sec_text(GElf_Shdr *); static void print_ar_index(int, Elf *); static void print_header(const char *, const char *); static void print_version(void); static int read_elf(Elf *, const char *, Elf_Kind); static int read_object(const char *); static int read_files(int, char **); static void set_opt_value_print_fn(enum radix); static int sym_elem_def(char, const GElf_Sym *, const char *); static int sym_elem_global(char, const GElf_Sym *, const char *); static int sym_elem_global_static(char, const GElf_Sym *, const char *); static int sym_elem_nondebug(char, const GElf_Sym *, const char *); static int sym_elem_nonzero_size(char, const GElf_Sym *, const char *); static void sym_elem_print_all(char, const char *, const GElf_Sym *, const char *); static void sym_elem_print_all_portable(char, const char *, const GElf_Sym *, const char *); static void sym_elem_print_all_sysv(char, const char *, const GElf_Sym *, const char *); static int sym_elem_undef(char, const GElf_Sym *, const char *); static void sym_list_dest(struct sym_head *); static int sym_list_insert(struct sym_head *, const char *, const GElf_Sym *); static void sym_list_print(struct sym_print_data *, struct func_info_head *, struct var_info_head *, struct line_info_head *); static void sym_list_print_each(struct sym_entry *, struct sym_print_data *, struct func_info_head *, struct var_info_head *, struct line_info_head *); static struct sym_entry *sym_list_sort(struct sym_print_data *); static void sym_size_oct_print(const GElf_Sym *); static void sym_size_hex_print(const GElf_Sym *); static void sym_size_dec_print(const GElf_Sym *); static void sym_value_oct_print(const GElf_Sym *); static void sym_value_hex_print(const GElf_Sym *); static void sym_value_dec_print(const GElf_Sym *); static void usage(int); static struct nm_prog_info nm_info; static struct nm_prog_options nm_opts; static int nm_elfclass; /* * Point to current sym_print_data to use portable qsort function. * (e.g. There is no qsort_r function in NetBSD.) * * Using in sym_list_sort. */ static struct sym_print_data *nm_print_data; static const struct option nm_longopts[] = { { "debug-syms", no_argument, NULL, 'a' }, { "defined-only", no_argument, &nm_opts.def_only, 1}, { "demangle", optional_argument, NULL, 'C' }, { "dynamic", no_argument, NULL, 'D' }, { "format", required_argument, NULL, 'F' }, { "help", no_argument, NULL, 'h' }, { "line-numbers", no_argument, NULL, 'l' }, { "no-demangle", no_argument, &nm_opts.no_demangle, 1}, { "no-sort", no_argument, NULL, 'p' }, { "numeric-sort", no_argument, NULL, 'v' }, { "print-armap", no_argument, NULL, 's' }, { "print-file-name", no_argument, NULL, 'A' }, { "print-size", no_argument, NULL, 'S' }, { "radix", required_argument, NULL, 't' }, { "reverse-sort", no_argument, NULL, 'r' }, { "size-sort", no_argument, &nm_opts.sort_size, 1}, { "undefined-only", no_argument, NULL, 'u' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; #if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS) static __inline uint32_t be32dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); } static __inline uint32_t le32dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); } static __inline uint64_t be64dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); } static __inline uint64_t le64dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); } #endif static int cmp_name(const void *l, const void *r) { assert(l != NULL); assert(r != NULL); assert(((const struct sym_entry *)l)->name != NULL); assert(((const struct sym_entry *)r)->name != NULL); return (strcmp(((const struct sym_entry *)l)->name, ((const struct sym_entry *)r)->name)); } static int cmp_none(const void *l, const void *r) { UNUSED(l); UNUSED(r); return (0); } /* Size comparison. If l and r have same size, compare their name. */ static int cmp_size(const void *lp, const void *rp) { const struct sym_entry *l, *r; l = lp; r = rp; assert(l != NULL); assert(l->name != NULL); assert(l->sym != NULL); assert(r != NULL); assert(r->name != NULL); assert(r->sym != NULL); if (l->sym->st_size == r->sym->st_size) return (strcmp(l->name, r->name)); return (l->sym->st_size - r->sym->st_size); } /* Value comparison. Undefined symbols come first. */ static int cmp_value(const void *lp, const void *rp) { const struct sym_entry *l, *r; const char *ttable; int l_is_undef, r_is_undef; l = lp; r = rp; assert(nm_print_data != NULL); ttable = nm_print_data->t_table; assert(l != NULL); assert(l->name != NULL); assert(l->sym != NULL); assert(r != NULL); assert(r->name != NULL); assert(r->sym != NULL); assert(ttable != NULL); l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0; r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0; assert(l_is_undef + r_is_undef >= 0); assert(l_is_undef + r_is_undef <= 2); switch (l_is_undef + r_is_undef) { case 0: /* Both defined */ if (l->sym->st_value == r->sym->st_value) return (strcmp(l->name, r->name)); return (l->sym->st_value - r->sym->st_value); case 1: /* One undefined */ return (l_is_undef == 0 ? 1 : -1); case 2: /* Both undefined */ return (strcmp(l->name, r->name)); } /* NOTREACHED */ return (l->sym->st_value - r->sym->st_value); } static void filter_dest(void) { struct filter_entry *e; while (!SLIST_EMPTY(&nm_out_filter)) { e = SLIST_FIRST(&nm_out_filter); SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries); free(e); } } static int filter_insert(fn_filter filter_fn) { struct filter_entry *e; assert(filter_fn != NULL); if ((e = malloc(sizeof(struct filter_entry))) == NULL) { warn("malloc"); return (0); } e->fn = filter_fn; SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries); return (1); } static int parse_demangle_option(const char *opt) { if (opt == NULL) return (ELFTC_DEM_UNKNOWN); else if (!strncasecmp(opt, "gnu-v2", 6)) return (ELFTC_DEM_GNU2); else if (!strncasecmp(opt, "gnu-v3", 6)) return (ELFTC_DEM_GNU3); else if (!strncasecmp(opt, "arm", 3)) return (ELFTC_DEM_ARM); else errx(EXIT_FAILURE, "unknown demangling style '%s'", opt); /* NOTREACHED */ return (0); } static void get_opt(int argc, char **argv) { int ch; bool is_posix, oflag; if (argc <= 0 || argv == NULL) return; oflag = is_posix = false; nm_opts.t = RADIX_HEX; while ((ch = getopt_long(argc, argv, "ABCDF:PSVaefghlnoprst:uvx", nm_longopts, NULL)) != -1) { switch (ch) { case 'A': nm_opts.print_name = PRINT_NAME_FULL; break; case 'B': nm_opts.elem_print_fn = &sym_elem_print_all; break; case 'C': nm_opts.demangle_type = parse_demangle_option(optarg); break; case 'D': nm_opts.print_symbol = PRINT_SYM_DYN; break; case 'F': /* sysv, bsd, posix */ switch (optarg[0]) { case 'B': case 'b': nm_opts.elem_print_fn = &sym_elem_print_all; break; case 'P': case 'p': is_posix = true; nm_opts.elem_print_fn = &sym_elem_print_all_portable; break; case 'S': case 's': nm_opts.elem_print_fn = &sym_elem_print_all_sysv; break; default: warnx("%s: Invalid format", optarg); usage(1); } break; case 'P': is_posix = true; nm_opts.elem_print_fn = &sym_elem_print_all_portable; break; case 'S': nm_opts.print_size = 1; break; case 'V': print_version(); /* NOTREACHED */ case 'a': nm_opts.print_debug = true; break; case 'e': filter_insert(sym_elem_global_static); break; case 'f': break; case 'g': filter_insert(sym_elem_global); break; case 'h': usage(0); break; case 'l': nm_opts.debug_line = true; break; case 'n': case 'v': nm_opts.sort_fn = &cmp_value; break; case 'o': oflag = true; break; case 'p': nm_opts.sort_fn = &cmp_none; break; case 'r': nm_opts.sort_reverse = true; break; case 's': nm_opts.print_armap = true; break; case 't': /* t require always argument to getopt_long */ switch (optarg[0]) { case 'd': nm_opts.t = RADIX_DEC; break; case 'o': nm_opts.t = RADIX_OCT; break; case 'x': nm_opts.t = RADIX_HEX; break; default: warnx("%s: Invalid radix", optarg); usage(1); } break; case 'u': filter_insert(sym_elem_undef); nm_opts.undef_only = true; break; /* case 'v': see case 'n' above. */ case 'x': nm_opts.t = RADIX_HEX; break; case 0: if (nm_opts.sort_size != 0) { nm_opts.sort_fn = &cmp_size; filter_insert(sym_elem_def); filter_insert(sym_elem_nonzero_size); } if (nm_opts.def_only != 0) filter_insert(sym_elem_def); if (nm_opts.no_demangle != 0) nm_opts.demangle_type = -1; break; default : usage(1); } } /* * In POSIX mode, the '-o' option controls the output radix. * In non-POSIX mode, the option is a synonym for the '-A' and * '--print-file-name' options. */ if (oflag) { if (is_posix) nm_opts.t = RADIX_OCT; else nm_opts.print_name = PRINT_NAME_FULL; } assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null"); assert(nm_opts.elem_print_fn != NULL && "nm_opts.elem_print_fn is null"); assert(nm_opts.value_print_fn != NULL && "nm_opts.value_print_fn is null"); set_opt_value_print_fn(nm_opts.t); if (nm_opts.undef_only == true) { if (nm_opts.sort_fn == &cmp_size) errx(EXIT_FAILURE, "--size-sort with -u is meaningless"); if (nm_opts.def_only != 0) errx(EXIT_FAILURE, "-u with --defined-only is meaningless"); } if (nm_opts.print_debug == false) filter_insert(sym_elem_nondebug); if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none) nm_opts.sort_reverse = false; } /* * Get symbol information from elf. */ static int get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx, size_t strndx, const char *type_table, const char **sec_table, int sec_table_size) { Elf_Scn *scn; Elf_Data *data; GElf_Shdr shdr; GElf_Sym sym; struct filter_entry *fep; size_t ndx; int rtn; const char *sym_name; char type; bool filter; int i, j; assert(elf != NULL); assert(headp != NULL); rtn = 0; for (i = 1; i < shnum; i++) { if ((scn = elf_getscn(elf, i)) == NULL) { warnx("elf_getscn failed: %s", elf_errmsg(-1)); continue; } if (gelf_getshdr(scn, &shdr) != &shdr) { warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); continue; } if (shdr.sh_type == SHT_SYMTAB) { if (nm_opts.print_symbol != PRINT_SYM_SYM) continue; } else if (shdr.sh_type == SHT_DYNSYM) { if (nm_opts.print_symbol != PRINT_SYM_DYN) continue; } else continue; ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx; data = NULL; while ((data = elf_getdata(scn, data)) != NULL) { j = 1; while (gelf_getsym(data, j++, &sym) != NULL) { sym_name = get_sym_name(elf, &sym, ndx, sec_table, sec_table_size); filter = false; type = get_sym_type(&sym, type_table); SLIST_FOREACH(fep, &nm_out_filter, filter_entries) { if (!fep->fn(type, &sym, sym_name)) { filter = true; break; } } if (filter == false) { if (sym_list_insert(headp, sym_name, &sym) == 0) return (0); rtn++; } } } } return (rtn); } static const char * get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table, int sec_table_size) { const char *sym_name; sym_name = NULL; /* Show section name as symbol name for STT_SECTION symbols. */ if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) { if (sec_table != NULL && sym->st_shndx < sec_table_size) sym_name = sec_table[sym->st_shndx]; } else sym_name = elf_strptr(elf, ndx, sym->st_name); if (sym_name == NULL) sym_name = "(null)"; return (sym_name); } static char get_sym_type(const GElf_Sym *sym, const char *type_table) { bool is_local; if (sym == NULL || type_table == NULL) return ('?'); is_local = sym->st_info >> 4 == STB_LOCAL; if (sym->st_shndx == SHN_ABS) /* absolute */ return (is_local ? 'a' : 'A'); if (sym->st_shndx == SHN_COMMON) /* common */ return ('C'); if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */ if ((sym->st_info & 0xf) == STT_OBJECT) return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V'); return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W'); } if (sym->st_shndx == SHN_UNDEF) /* undefined */ return ('U'); return (is_local == true && type_table[sym->st_shndx] != 'N' ? tolower((unsigned char) type_table[sym->st_shndx]) : type_table[sym->st_shndx]); } static void global_dest(void) { filter_dest(); } static void global_init(void) { if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "elf_version error"); nm_info.name = ELFTC_GETPROGNAME(); nm_info.def_filename = "a.out"; nm_opts.print_symbol = PRINT_SYM_SYM; nm_opts.print_name = PRINT_NAME_NONE; nm_opts.demangle_type = -1; nm_opts.print_debug = false; nm_opts.print_armap = false; nm_opts.print_size = 0; nm_opts.debug_line = false; nm_opts.def_only = 0; nm_opts.undef_only = false; nm_opts.sort_size = 0; nm_opts.sort_reverse = false; nm_opts.no_demangle = 0; nm_opts.sort_fn = &cmp_name; nm_opts.elem_print_fn = &sym_elem_print_all; nm_opts.value_print_fn = &sym_value_dec_print; nm_opts.size_print_fn = &sym_size_dec_print; SLIST_INIT(&nm_out_filter); } static bool is_sec_data(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS); } static bool is_sec_debug(const char *shname) { const char *dbg_sec[] = { ".debug", ".gnu.linkonce.wi.", ".line", ".rel.debug", ".rela.debug", ".stab", NULL }; const char **p; assert(shname != NULL && "shname is NULL"); for (p = dbg_sec; *p; p++) { if (!strncmp(shname, *p, strlen(*p))) return (true); } return (false); } static bool is_sec_nobits(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return (s->sh_type == SHT_NOBITS); } static bool is_sec_readonly(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return ((s->sh_flags & SHF_WRITE) == 0); } static bool is_sec_text(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return ((s->sh_flags & SHF_EXECINSTR) != 0); } static void print_ar_index(int fd, Elf *arf) { Elf *elf; Elf_Arhdr *arhdr; Elf_Arsym *arsym; Elf_Cmd cmd; off_t start; size_t arsym_size; if (arf == NULL) return; if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL) return; printf("\nArchive index:\n"); start = arsym->as_off; cmd = ELF_C_READ; while (arsym_size > 1) { if (elf_rand(arf, arsym->as_off) == arsym->as_off && (elf = elf_begin(fd, cmd, arf)) != NULL) { if ((arhdr = elf_getarhdr(elf)) != NULL) printf("%s in %s\n", arsym->as_name, arhdr->ar_name != NULL ? arhdr->ar_name : arhdr->ar_rawname); elf_end(elf); } ++arsym; --arsym_size; } elf_rand(arf, start); } #define DEMANGLED_BUFFER_SIZE (8 * 1024) #define PRINT_DEMANGLED_NAME(FORMAT, NAME) do { \ char _demangled[DEMANGLED_BUFFER_SIZE]; \ if (nm_opts.demangle_type < 0 || \ elftc_demangle((NAME), _demangled, sizeof(_demangled), \ nm_opts.demangle_type) < 0) \ printf((FORMAT), (NAME)); \ else \ printf((FORMAT), _demangled); \ } while (0) static void print_header(const char *file, const char *obj) { if (file == NULL) return; if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) { printf("\n\n%s from %s", nm_opts.undef_only == false ? "Symbols" : "Undefined symbols", file); if (obj != NULL) printf("[%s]", obj); printf(":\n\n"); printf("\ Name Value Class Type Size Line Section\n\n"); } else { /* archive file without -A option and POSIX */ if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) { if (nm_opts.elem_print_fn == sym_elem_print_all_portable) printf("%s[%s]:\n", file, obj); else if (nm_opts.elem_print_fn == sym_elem_print_all) printf("\n%s:\n", obj); /* multiple files(not archive) without -A option */ } else if (nm_opts.print_name == PRINT_NAME_MULTI) { if (nm_opts.elem_print_fn == sym_elem_print_all) printf("\n"); printf("%s:\n", file); } } } static void print_version(void) { (void) printf("%s (%s)\n", nm_info.name, elftc_version()); exit(0); } static uint64_t get_block_value(Dwarf_Debug dbg, Dwarf_Block *block) { Elf *elf; GElf_Ehdr eh; Dwarf_Error de; if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) { warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de)); return (0); } if (gelf_getehdr(elf, &eh) != &eh) { warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); return (0); } if (block->bl_len == 5) { if (eh.e_ident[EI_DATA] == ELFDATA2LSB) return (le32dec((uint8_t *) block->bl_data + 1)); else return (be32dec((uint8_t *) block->bl_data + 1)); } else if (block->bl_len == 9) { if (eh.e_ident[EI_DATA] == ELFDATA2LSB) return (le64dec((uint8_t *) block->bl_data + 1)); else return (be64dec((uint8_t *) block->bl_data + 1)); } return (0); } static void search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info, struct var_info_head *var_info, Dwarf_Die die, char **src_files, Dwarf_Signed filecount) { Dwarf_Attribute at; Dwarf_Unsigned udata; Dwarf_Half tag; Dwarf_Block *block; Dwarf_Bool flag; Dwarf_Die ret_die; Dwarf_Error de; struct func_info_entry *func; struct var_info_entry *var; const char *str; int ret; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); goto cont_search; } /* We're interested in DIEs which define functions or variables. */ if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point && tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable) goto cont_search; if (tag == DW_TAG_variable) { /* Ignore "artificial" variable. */ if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) == DW_DLV_OK && flag) goto cont_search; /* Ignore pure declaration. */ if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) == DW_DLV_OK && flag) goto cont_search; /* Ignore stack varaibles. */ if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) != DW_DLV_OK || !flag) goto cont_search; if ((var = calloc(1, sizeof(*var))) == NULL) { warn("calloc failed"); goto cont_search; } if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, &de) == DW_DLV_OK && udata > 0 && (Dwarf_Signed) (udata - 1) < filecount) { var->file = strdup(src_files[udata - 1]); if (var->file == NULL) { warn("strdup"); free(var); goto cont_search; } } if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == DW_DLV_OK) var->line = udata; if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == DW_DLV_OK) { var->name = strdup(str); if (var->name == NULL) { warn("strdup"); if (var->file) free(var->file); free(var); goto cont_search; } } if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK && dwarf_formblock(at, &block, &de) == DW_DLV_OK) { /* * Since we ignored stack variables, the rest are the * external varaibles which should always use DW_OP_addr * operator for DW_AT_location value. */ if (*((uint8_t *)block->bl_data) == DW_OP_addr) var->addr = get_block_value(dbg, block); } SLIST_INSERT_HEAD(var_info, var, entries); } else { if ((func = calloc(1, sizeof(*func))) == NULL) { warn("calloc failed"); goto cont_search; } /* * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line * attributes for inlined functions as well. */ if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, &de) == DW_DLV_OK && udata > 0 && (Dwarf_Signed) (udata - 1) < filecount) { func->file = strdup(src_files[udata - 1]); if (func->file == NULL) { warn("strdup"); free(func); goto cont_search; } } if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == DW_DLV_OK) func->line = udata; if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == DW_DLV_OK) { func->name = strdup(str); if (func->name == NULL) { warn("strdup"); if (func->file) free(func->file); free(func); goto cont_search; } } if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) == DW_DLV_OK) func->lowpc = udata; if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) == DW_DLV_OK) func->highpc = udata; SLIST_INSERT_HEAD(func_info, func, entries); } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_line_attr(dbg, func_info, var_info, ret_die, src_files, filecount); /* Search sibling. */ ret = dwarf_siblingof(dbg, die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_line_attr(dbg, func_info, var_info, ret_die, src_files, filecount); dwarf_dealloc(dbg, die, DW_DLA_DIE); } /* * Read elf file and collect symbol information, sort them, print. * Return 1 at failed, 0 at success. */ static int read_elf(Elf *elf, const char *filename, Elf_Kind kind) { Dwarf_Debug dbg; Dwarf_Die die; Dwarf_Error de; Dwarf_Half tag; Elf_Arhdr *arhdr; Elf_Scn *scn; GElf_Shdr shdr; GElf_Half i; Dwarf_Line *lbuf; Dwarf_Unsigned lineno; Dwarf_Signed lcount, filecount; Dwarf_Addr lineaddr; struct sym_print_data p_data; struct sym_head list_head; struct line_info_head *line_info; struct func_info_head *func_info; struct var_info_head *var_info; struct line_info_entry *lie; struct func_info_entry *func; struct var_info_entry *var; const char *shname, *objname; char *type_table, **sec_table, *sfile, **src_files; size_t shstrndx, shnum, dynndx, strndx; int ret, rtn, e_err; #define OBJNAME (objname == NULL ? filename : objname) assert(filename != NULL && "filename is null"); STAILQ_INIT(&list_head); type_table = NULL; sec_table = NULL; line_info = NULL; func_info = NULL; var_info = NULL; objname = NULL; dynndx = SHN_UNDEF; strndx = SHN_UNDEF; rtn = 0; nm_elfclass = gelf_getclass(elf); if (kind == ELF_K_AR) { if ((arhdr = elf_getarhdr(elf)) == NULL) goto next_cmd; objname = arhdr->ar_name != NULL ? arhdr->ar_name : arhdr->ar_rawname; } if (!elf_getshnum(elf, &shnum)) { if ((e_err = elf_errno()) != 0) warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); else warnx("%s: cannot get section number", OBJNAME); rtn = 1; goto next_cmd; } if (shnum == 0) { warnx("%s: has no section", OBJNAME); rtn = 1; goto next_cmd; } if (!elf_getshstrndx(elf, &shstrndx)) { warnx("%s: cannot get str index", OBJNAME); rtn = 1; goto next_cmd; } /* type_table for type determine */ if ((type_table = malloc(sizeof(char) * shnum)) == NULL) { warn("%s: malloc", OBJNAME); rtn = 1; goto next_cmd; } /* sec_table for section name to display in sysv format */ if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) { warn("%s: calloc", OBJNAME); rtn = 1; goto next_cmd; } type_table[0] = 'U'; if ((sec_table[0] = strdup("*UND*")) == NULL) { warn("strdup"); goto next_cmd; } for (i = 1; i < shnum; ++i) { type_table[i] = 'U'; if ((scn = elf_getscn(elf, i)) == NULL) { if ((e_err = elf_errno()) != 0) warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); else warnx("%s: cannot get section", OBJNAME); rtn = 1; goto next_cmd; } if (gelf_getshdr(scn, &shdr) == NULL) goto next_cmd; /* * Cannot test by type and attribute for dynstr, strtab */ shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name); if (shname != NULL) { if ((sec_table[i] = strdup(shname)) == NULL) { warn("strdup"); goto next_cmd; } if (!strncmp(shname, ".dynstr", 7)) { dynndx = elf_ndxscn(scn); if (dynndx == SHN_UNDEF) { warnx("%s: elf_ndxscn failed: %s", OBJNAME, elf_errmsg(-1)); goto next_cmd; } } if (!strncmp(shname, ".strtab", 7)) { strndx = elf_ndxscn(scn); if (strndx == SHN_UNDEF) { warnx("%s: elf_ndxscn failed: %s", OBJNAME, elf_errmsg(-1)); goto next_cmd; } } } else { sec_table[i] = strdup("*UND*"); if (sec_table[i] == NULL) { warn("strdup"); goto next_cmd; } } if (is_sec_text(&shdr)) type_table[i] = 'T'; else if (is_sec_data(&shdr)) { if (is_sec_readonly(&shdr)) type_table[i] = 'R'; else type_table[i] = 'D'; } else if (is_sec_nobits(&shdr)) type_table[i] = 'B'; else if (is_sec_debug(shname)) type_table[i] = 'N'; else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr)) type_table[i] = 'n'; } print_header(filename, objname); if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) || (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) { warnx("%s: no symbols", OBJNAME); /* This is not an error case */ goto next_cmd; } STAILQ_INIT(&list_head); if (!nm_opts.debug_line) goto process_sym; /* * Collect dwarf line number information. */ if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) != DW_DLV_OK) { warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de)); goto process_sym; } line_info = malloc(sizeof(struct line_info_head)); func_info = malloc(sizeof(struct func_info_head)); var_info = malloc(sizeof(struct var_info_head)); if (line_info == NULL || func_info == NULL || var_info == NULL) { warn("malloc"); (void) dwarf_finish(dbg, &de); goto process_sym; } SLIST_INIT(line_info); SLIST_INIT(func_info); SLIST_INIT(var_info); while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { die = NULL; while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) { if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); continue; } /* XXX: What about DW_TAG_partial_unit? */ if (tag == DW_TAG_compile_unit) break; } if (die == NULL) { warnx("could not find DW_TAG_compile_unit die"); continue; } /* Retrieve source file list. */ ret = dwarf_srcfiles(die, &src_files, &filecount, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_srclines: %s", dwarf_errmsg(de)); if (ret != DW_DLV_OK) continue; /* * Retrieve line number information from .debug_line section. */ ret = dwarf_srclines(die, &lbuf, &lcount, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_srclines: %s", dwarf_errmsg(de)); if (ret != DW_DLV_OK) goto line_attr; for (i = 0; (Dwarf_Signed) i < lcount; i++) { if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); continue; } if (dwarf_lineno(lbuf[i], &lineno, &de)) { warnx("dwarf_lineno: %s", dwarf_errmsg(de)); continue; } if (dwarf_linesrc(lbuf[i], &sfile, &de)) { warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); continue; } if ((lie = malloc(sizeof(*lie))) == NULL) { warn("malloc"); continue; } lie->addr = lineaddr; lie->line = lineno; lie->file = strdup(sfile); if (lie->file == NULL) { warn("strdup"); free(lie); continue; } SLIST_INSERT_HEAD(line_info, lie, entries); } line_attr: /* Retrieve line number information from DIEs. */ search_line_attr(dbg, func_info, var_info, die, src_files, filecount); } (void) dwarf_finish(dbg, &de); process_sym: p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx, type_table, (void *) sec_table, shnum); if (p_data.list_num == 0) goto next_cmd; p_data.headp = &list_head; p_data.sh_num = shnum; p_data.t_table = type_table; p_data.s_table = (void *) sec_table; p_data.filename = filename; p_data.objname = objname; sym_list_print(&p_data, func_info, var_info, line_info); next_cmd: if (nm_opts.debug_line) { if (func_info != NULL) { while (!SLIST_EMPTY(func_info)) { func = SLIST_FIRST(func_info); SLIST_REMOVE_HEAD(func_info, entries); free(func->file); free(func->name); free(func); } free(func_info); func_info = NULL; } if (var_info != NULL) { while (!SLIST_EMPTY(var_info)) { var = SLIST_FIRST(var_info); SLIST_REMOVE_HEAD(var_info, entries); free(var->file); free(var->name); free(var); } free(var_info); var_info = NULL; } if (line_info != NULL) { while (!SLIST_EMPTY(line_info)) { lie = SLIST_FIRST(line_info); SLIST_REMOVE_HEAD(line_info, entries); free(lie->file); free(lie); } free(line_info); line_info = NULL; } } if (sec_table != NULL) for (i = 0; i < shnum; ++i) free(sec_table[i]); free(sec_table); free(type_table); sym_list_dest(&list_head); return (rtn); #undef OBJNAME } static int read_object(const char *filename) { Elf *elf, *arf; Elf_Cmd elf_cmd; Elf_Kind kind; int fd, rtn, e_err; assert(filename != NULL && "filename is null"); if ((fd = open(filename, O_RDONLY)) == -1) { warn("'%s'", filename); return (1); } elf_cmd = ELF_C_READ; if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) { if ((e_err = elf_errno()) != 0) warnx("elf_begin error: %s", elf_errmsg(e_err)); else warnx("elf_begin error"); close(fd); return (1); } assert(arf != NULL && "arf is null."); rtn = 0; if ((kind = elf_kind(arf)) == ELF_K_NONE) { warnx("%s: File format not recognized", filename); elf_end(arf); close(fd); return (1); } if (kind == ELF_K_AR) { if (nm_opts.print_name == PRINT_NAME_MULTI && nm_opts.elem_print_fn == sym_elem_print_all) printf("\n%s:\n", filename); if (nm_opts.print_armap == true) print_ar_index(fd, arf); } while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) { rtn |= read_elf(elf, filename, kind); /* * If file is not archive, elf_next return ELF_C_NULL and * stop the loop. */ elf_cmd = elf_next(elf); elf_end(elf); } elf_end(arf); close(fd); return (rtn); } static int read_files(int argc, char **argv) { int rtn = 0; if (argc < 0 || argv == NULL) return (1); if (argc == 0) rtn |= read_object(nm_info.def_filename); else { if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1) nm_opts.print_name = PRINT_NAME_MULTI; while (argc > 0) { rtn |= read_object(*argv); --argc; ++argv; } } return (rtn); } static void print_lineno(struct sym_entry *ep, struct func_info_head *func_info, struct var_info_head *var_info, struct line_info_head *line_info) { struct func_info_entry *func; struct var_info_entry *var; struct line_info_entry *lie; /* For function symbol, search the function line information list. */ if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) { SLIST_FOREACH(func, func_info, entries) { if (!strcmp(ep->name, func->name) && ep->sym->st_value >= func->lowpc && ep->sym->st_value < func->highpc) { printf("\t%s:%" PRIu64, func->file, func->line); return; } } } /* For variable symbol, search the variable line information list. */ if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) { SLIST_FOREACH(var, var_info, entries) { if (!strcmp(ep->name, var->name) && ep->sym->st_value == var->addr) { printf("\t%s:%" PRIu64, var->file, var->line); return; } } } /* Otherwise search line number information the .debug_line section. */ if (line_info != NULL) { SLIST_FOREACH(lie, line_info, entries) { if (ep->sym->st_value == lie->addr) { printf("\t%s:%" PRIu64, lie->file, lie->line); return; } } } } static void set_opt_value_print_fn(enum radix t) { switch (t) { case RADIX_OCT: nm_opts.value_print_fn = &sym_value_oct_print; nm_opts.size_print_fn = &sym_size_oct_print; break; case RADIX_DEC: nm_opts.value_print_fn = &sym_value_dec_print; nm_opts.size_print_fn = &sym_size_dec_print; break; case RADIX_HEX: default : nm_opts.value_print_fn = &sym_value_hex_print; nm_opts.size_print_fn = &sym_size_hex_print; } assert(nm_opts.value_print_fn != NULL && "nm_opts.value_print_fn is null"); } static void sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym, const char *name) { if (sec == NULL || sym == NULL || name == NULL || nm_opts.value_print_fn == NULL) return; if (IS_UNDEF_SYM_TYPE(type)) { if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32) printf("%-8s", ""); else printf("%-16s", ""); } else { switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) + nm_opts.print_size) { case 3: if (sym->st_size != 0) { nm_opts.value_print_fn(sym); printf(" "); nm_opts.size_print_fn(sym); } break; case 2: if (sym->st_size != 0) nm_opts.size_print_fn(sym); break; case 1: nm_opts.value_print_fn(sym); if (sym->st_size != 0) { printf(" "); nm_opts.size_print_fn(sym); } break; case 0: default: nm_opts.value_print_fn(sym); } } printf(" %c ", type); PRINT_DEMANGLED_NAME("%s", name); } static void sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym, const char *name) { if (sec == NULL || sym == NULL || name == NULL || nm_opts.value_print_fn == NULL) return; PRINT_DEMANGLED_NAME("%s", name); printf(" %c ", type); if (!IS_UNDEF_SYM_TYPE(type)) { nm_opts.value_print_fn(sym); printf(" "); if (sym->st_size != 0) nm_opts.size_print_fn(sym); } else printf(" "); } static void sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym, const char *name) { if (sec == NULL || sym == NULL || name == NULL || nm_opts.value_print_fn == NULL) return; PRINT_DEMANGLED_NAME("%-20s|", name); if (IS_UNDEF_SYM_TYPE(type)) printf(" "); else nm_opts.value_print_fn(sym); printf("| %c |", type); switch (sym->st_info & 0xf) { case STT_OBJECT: printf("%18s|", "OBJECT"); break; case STT_FUNC: printf("%18s|", "FUNC"); break; case STT_SECTION: printf("%18s|", "SECTION"); break; case STT_FILE: printf("%18s|", "FILE"); break; case STT_LOPROC: printf("%18s|", "LOPROC"); break; case STT_HIPROC: printf("%18s|", "HIPROC"); break; case STT_NOTYPE: default: printf("%18s|", "NOTYPE"); }; if (sym->st_size != 0) nm_opts.size_print_fn(sym); else printf(" "); printf("| |%s", sec); } static int sym_elem_def(char type, const GElf_Sym *sym, const char *name) { assert(IS_SYM_TYPE((unsigned char) type)); UNUSED(sym); UNUSED(name); return (!IS_UNDEF_SYM_TYPE((unsigned char) type)); } static int sym_elem_global(char type, const GElf_Sym *sym, const char *name) { assert(IS_SYM_TYPE((unsigned char) type)); UNUSED(sym); UNUSED(name); /* weak symbols resemble global. */ return (isupper((unsigned char) type) || type == 'w'); } static int sym_elem_global_static(char type, const GElf_Sym *sym, const char *name) { unsigned char info; assert(sym != NULL); UNUSED(type); UNUSED(name); info = sym->st_info >> 4; return (info == STB_LOCAL || info == STB_GLOBAL || info == STB_WEAK); } static int sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name) { assert(sym != NULL); UNUSED(type); UNUSED(name); if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE) return (0); if (sym->st_name == 0) return (0); return (1); } static int sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name) { assert(sym != NULL); UNUSED(type); UNUSED(name); return (sym->st_size > 0); } static int sym_elem_undef(char type, const GElf_Sym *sym, const char *name) { assert(IS_SYM_TYPE((unsigned char) type)); UNUSED(sym); UNUSED(name); return (IS_UNDEF_SYM_TYPE((unsigned char) type)); } static void sym_list_dest(struct sym_head *headp) { struct sym_entry *ep, *ep_n; if (headp == NULL) return; ep = STAILQ_FIRST(headp); while (ep != NULL) { ep_n = STAILQ_NEXT(ep, sym_entries); free(ep->sym); free(ep->name); free(ep); ep = ep_n; } } static int sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym) { struct sym_entry *e; if (headp == NULL || name == NULL || sym == NULL) return (0); if ((e = malloc(sizeof(struct sym_entry))) == NULL) { warn("malloc"); return (0); } if ((e->name = strdup(name)) == NULL) { warn("strdup"); free(e); return (0); } if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) { warn("malloc"); free(e->name); free(e); return (0); } memcpy(e->sym, sym, sizeof(GElf_Sym)); /* Display size instead of value for common symbol. */ if (sym->st_shndx == SHN_COMMON) e->sym->st_value = sym->st_size; STAILQ_INSERT_TAIL(headp, e, sym_entries); return (1); } /* If file has not .debug_info, line_info will be NULL */ static void sym_list_print(struct sym_print_data *p, struct func_info_head *func_info, struct var_info_head *var_info, struct line_info_head *line_info) { struct sym_entry *e_v; size_t si; int i; if (p == NULL || CHECK_SYM_PRINT_DATA(p)) return; if ((e_v = sym_list_sort(p)) == NULL) return; if (nm_opts.sort_reverse == false) for (si = 0; si != p->list_num; ++si) sym_list_print_each(&e_v[si], p, func_info, var_info, line_info); else for (i = p->list_num - 1; i != -1; --i) sym_list_print_each(&e_v[i], p, func_info, var_info, line_info); free(e_v); } /* If file has not .debug_info, line_info will be NULL */ static void sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p, struct func_info_head *func_info, struct var_info_head *var_info, struct line_info_head *line_info) { const char *sec; char type; if (ep == NULL || CHECK_SYM_PRINT_DATA(p)) return; assert(ep->name != NULL); assert(ep->sym != NULL); type = get_sym_type(ep->sym, p->t_table); if (nm_opts.print_name == PRINT_NAME_FULL) { printf("%s", p->filename); if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) { if (p->objname != NULL) printf("[%s]", p->objname); printf(": "); } else { if (p->objname != NULL) printf(":%s", p->objname); printf(":"); } } switch (ep->sym->st_shndx) { case SHN_LOPROC: /* LOPROC or LORESERVE */ sec = "*LOPROC*"; break; case SHN_HIPROC: sec = "*HIPROC*"; break; case SHN_LOOS: sec = "*LOOS*"; break; case SHN_HIOS: sec = "*HIOS*"; break; case SHN_ABS: sec = "*ABS*"; break; case SHN_COMMON: sec = "*COM*"; break; case SHN_HIRESERVE: /* HIRESERVE or XINDEX */ sec = "*HIRESERVE*"; break; default: if (ep->sym->st_shndx > p->sh_num) return; sec = p->s_table[ep->sym->st_shndx]; break; }; nm_opts.elem_print_fn(type, sec, ep->sym, ep->name); if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type)) print_lineno(ep, func_info, var_info, line_info); printf("\n"); } static struct sym_entry * sym_list_sort(struct sym_print_data *p) { struct sym_entry *ep, *e_v; int idx; if (p == NULL || CHECK_SYM_PRINT_DATA(p)) return (NULL); if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) { warn("malloc"); return (NULL); } idx = 0; STAILQ_FOREACH(ep, p->headp, sym_entries) { if (ep->name != NULL && ep->sym != NULL) { e_v[idx].name = ep->name; e_v[idx].sym = ep->sym; ++idx; } } assert((size_t)idx == p->list_num); if (nm_opts.sort_fn != &cmp_none) { nm_print_data = p; assert(nm_print_data != NULL); qsort(e_v, p->list_num, sizeof(struct sym_entry), nm_opts.sort_fn); } return (e_v); } static void sym_size_oct_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRIo64, sym->st_size); } static void sym_size_hex_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); if (nm_elfclass == ELFCLASS32) printf("%08" PRIx64, sym->st_size); else printf("%016" PRIx64, sym->st_size); } static void sym_size_dec_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRId64, sym->st_size); } static void sym_value_oct_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRIo64, sym->st_value); } static void sym_value_hex_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); if (nm_elfclass == ELFCLASS32) printf("%08" PRIx64, sym->st_value); else printf("%016" PRIx64, sym->st_value); } static void sym_value_dec_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRId64, sym->st_value); } static void usage(int exitcode) { printf("Usage: %s [options] file ...\ \n Display symbolic information in file.\n\ \n Options: \ \n -A, --print-file-name Write the full pathname or library name of an\ \n object on each line.\ \n -a, --debug-syms Display all symbols include debugger-only\ \n symbols.", nm_info.name); printf("\ \n -B Equivalent to specifying \"--format=bsd\".\ \n -C, --demangle[=style] Decode low-level symbol names.\ \n --no-demangle Do not demangle low-level symbol names.\ \n -D, --dynamic Display only dynamic symbols.\ \n -e Display only global and static symbols."); printf("\ \n -f Produce full output (default).\ \n --format=format Display output in specific format. Allowed\ \n formats are: \"bsd\", \"posix\" and \"sysv\".\ \n -g Display only global symbol information.\ \n -h, --help Show this help message.\ \n -l, --line-numbers Display filename and linenumber using\ \n debugging information.\ \n -n, --numeric-sort Sort symbols numerically by value."); printf("\ \n -o Write numeric values in octal. Equivalent to\ \n specifying \"-t o\".\ \n -p, --no-sort Do not sort symbols.\ \n -P Write information in a portable output format.\ \n Equivalent to specifying \"--format=posix\".\ \n -r, --reverse-sort Reverse the order of the sort.\ \n -S, --print-size Print symbol sizes instead values.\ \n -s, --print-armap Include an index of archive members.\ \n --size-sort Sort symbols by size."); printf("\ \n -t, --radix=format Write each numeric value in the specified\ \n format:\ \n d In decimal,\ \n o In octal,\ \n x In hexadecimal."); printf("\ \n -u, --undefined-only Display only undefined symbols.\ \n --defined-only Display only defined symbols.\ \n -V, --version Show the version identifier for %s.\ \n -v Sort output by value.\ \n -x Write numeric values in hexadecimal.\ \n Equivalent to specifying \"-t x\".", nm_info.name); printf("\n\ \n The default options are: output in bsd format, use a hexadecimal radix,\ \n sort by symbol name, do not demangle names.\n"); exit(exitcode); } /* * Display symbolic information in file. * Return 0 at success, >0 at failed. */ int main(int argc, char **argv) { int rtn; global_init(); get_opt(argc, argv); rtn = read_files(argc - optind, argv + optind); global_dest(); exit(rtn); } diff --git a/readelf/readelf.1 b/readelf/readelf.1 index 9a6efe58fab0..8419d95fbce8 100644 --- a/readelf/readelf.1 +++ b/readelf/readelf.1 @@ -1,197 +1,197 @@ .\" Copyright (c) 2009,2011 Joseph Koshy .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer .\" in this position and unchanged. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $Id: readelf.1 2577 2012-09-13 16:07:04Z jkoshy $ +.\" $Id: readelf.1 3059 2014-06-02 00:42:32Z kaiwang27 $ .\" .Dd September 13, 2012 .Os .Dt READELF 1 .Sh NAME .Nm readelf .Nd display information about ELF objects .Sh SYNOPSIS .Nm .Op Fl a | Fl -all .Op Fl c | Fl -archive-index .Op Fl d | Fl -dynamic .Op Fl e | Fl -headers .Op Fl g | Fl -section-groups .Op Fl h | Fl -file-header .Op Fl l | Fl -program-headers .Op Fl n | Fl -notes .Op Fl p Ar section | Fl -string-dump Ns = Ns Ar section .Op Fl r | Fl -relocs .Op Fl t | Fl -section-details .Op Fl x Ar section | Fl -hex-dump Ns = Ns Ar section .Op Fl v | Fl -version .Oo .Fl w Ns Oo Ns Ar afilmoprsFLR Ns Oc | .Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ... .Oc .Op Fl A | Fl -arch-specific .Op Fl D | Fl -use-dynamic .Op Fl H | Fl -help .Op Fl I | Fl -histogram .Op Fl N | -full-section-name .Op Fl S | Fl -sections | Fl -section-headers .Op Fl V | Fl -version-info .Op Fl W | Fl -wide .Ar file... .Sh DESCRIPTION The .Nm utility displays information about ELF objects and .Xr ar 1 archives. .Pp The .Nm utility recognizes the following options: .Bl -tag -width indent .It Fl a | Fl -all Turn on the following flags: .Fl d , .Fl h , .Fl I , .Fl l , .Fl r , .Fl s , .Fl A , .Fl S and .Fl V . .It Fl c | Fl -archive-index Print the archive symbol table for archives. .It Fl d | Fl -dynamic Print the contents of the .Li SHT_DYNAMIC sections in the ELF object. .It Fl e | Fl -headers Print all program, file and section headers in the ELF object. .It Fl g | Fl -section-groups This option is recognized, but is ignored. .It Fl h | Fl -file-header Print the file header of the ELF object. .It Fl l | Fl -program-headers Print the content of the program header table for the object. .It Fl n | Fl -notes Print the contents of .Li PT_NOTE segments or .Li SHT_NOTE sections present in the ELF object. .It Fl p Ar section | Fl -string-dump Ns = Ns Ar section Print the contents of the specified section as printable strings. The argument .Ar section should be the name of a section or a numeric section index. .It Fl r | Fl -relocs Print relocation information. .It Fl s | Fl -syms | Fl -symbols Print symbol tables. .It Fl t | Fl -section-details Print additional information about sections, such as the flags fields in section headers. .It Fl v | Fl -version Prints a version identifier for .Nm and exits. .It Fl w Ns Oo afilmoprsFLR Oc | Xo .Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ... .Xc Display DWARF information. The .Fl w option is used with the short options in the following table; the .Fl -debug-dump option is used with a comma-separated list of the corresponding long option names: .Bl -column ".Em Short Option" "aranges|ranges" .It Em Short Option Ta Em Long Option Ta Em Description .It a Ta abbrev Ta Show abbreviation information. .It f Ta frames Ta Show frame information, displaying frame instructions. .It i Ta info Ta Show debugging information entries. .It l Ta rawline Ta Show line information in raw form. .It m Ta macro Ta Show macro information. .It o Ta loc Ta Show location list information. .It p Ta pubnames Ta Show global names. .It r Ta aranges|ranges Ta Show address range information. .It s Ta str Ta Show the debug string table. -.It F Ta Ta Show frame information, displaying register rules. +.It F Ta frames-interp Ta Show frame information, displaying register rules. .It L Ta decodedline Ta Show line information in decoded form. .It R Ta Ranges Ta Show range lists. .El .Pp If no sub-options are specified, the default is to show information corresponding to the .Ar a , f , i, l , o , p , r , s and .Ar R short options. .It Fl x Ar section | Fl -hex-dump Ns = Ns Ar section Display the contents of the specified section in hexadecimal. The argument .Ar section should be the name of a section or a numeric section index. .It Fl A | Fl -arch-specific This option is accepted but is currently unimplemented. .It Fl D | Fl -use-dynamic Print the symbol table specified by the .Li DT_SYMTAB entry in the .Dq Li .dynamic section. .It Fl H | Fl -help Print a help message. .It Fl I | Fl -histogram Print information on bucket list lengths for sections of type .Li SHT_HASH and .Li SHT_GNU_HASH . .It Fl N | Fl -full-section-name This option is accepted but is currently unimplemented. .It Fl S | Fl -sections | Fl -section-headers Print information in the section headers for each ELF object. .It Fl V | Fl -version-info Print symbol versioning information. .It Fl W | Fl -wide Print information about ELF structures using one long line per structure. If this option is not specified, .Nm will list information in the headers of 64 bit ELF objects on two separate lines. .El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr nm 1 , .Xr addr2line 1 , .Xr elfcopy 1 , .Sh AUTHORS The .Nm utility was written by .An "Kai Wang" Aq kaiwang27@users.sourceforge.net . diff --git a/readelf/readelf.c b/readelf/readelf.c index 779a7ba9e875..16159ad09ea9 100644 --- a/readelf/readelf.c +++ b/readelf/readelf.c @@ -1,6845 +1,7348 @@ /*- - * Copyright (c) 2009,2010 Kai Wang + * Copyright (c) 2009-2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: readelf.c 2946 2013-05-26 08:00:11Z kaiwang27 $"); +ELFTC_VCSID("$Id: readelf.c 3110 2014-12-20 08:32:46Z kaiwang27 $"); /* * readelf(1) options. */ #define RE_AA 0x00000001 #define RE_C 0x00000002 #define RE_DD 0x00000004 #define RE_D 0x00000008 #define RE_G 0x00000010 #define RE_H 0x00000020 #define RE_II 0x00000040 #define RE_I 0x00000080 #define RE_L 0x00000100 #define RE_NN 0x00000200 #define RE_N 0x00000400 #define RE_P 0x00000800 #define RE_R 0x00001000 #define RE_SS 0x00002000 #define RE_S 0x00004000 #define RE_T 0x00008000 #define RE_U 0x00010000 #define RE_VV 0x00020000 #define RE_WW 0x00040000 #define RE_W 0x00080000 #define RE_X 0x00100000 /* * dwarf dump options. */ #define DW_A 0x00000001 #define DW_FF 0x00000002 #define DW_F 0x00000004 #define DW_I 0x00000008 #define DW_LL 0x00000010 #define DW_L 0x00000020 #define DW_M 0x00000040 #define DW_O 0x00000080 #define DW_P 0x00000100 #define DW_RR 0x00000200 #define DW_R 0x00000400 #define DW_S 0x00000800 #define DW_DEFAULT_OPTIONS (DW_A | DW_F | DW_I | DW_L | DW_O | DW_P | \ DW_R | DW_RR | DW_S) /* * readelf(1) run control flags. */ #define DISPLAY_FILENAME 0x0001 /* * Internal data structure for sections. */ struct section { const char *name; /* section name */ Elf_Scn *scn; /* section scn */ uint64_t off; /* section offset */ uint64_t sz; /* section size */ uint64_t entsize; /* section entsize */ uint64_t align; /* section alignment */ uint64_t type; /* section type */ uint64_t flags; /* section flags */ uint64_t addr; /* section virtual addr */ uint32_t link; /* section link ndx */ uint32_t info; /* section info ndx */ }; struct dumpop { union { size_t si; /* section index */ const char *sn; /* section name */ } u; enum { DUMP_BY_INDEX = 0, DUMP_BY_NAME } type; /* dump type */ #define HEX_DUMP 0x0001 #define STR_DUMP 0x0002 int op; /* dump operation */ STAILQ_ENTRY(dumpop) dumpop_list; }; struct symver { const char *name; int type; }; /* * Structure encapsulates the global data for readelf(1). */ struct readelf { const char *filename; /* current processing file. */ int options; /* command line options. */ int flags; /* run control flags. */ int dop; /* dwarf dump options. */ Elf *elf; /* underlying ELF descriptor. */ Elf *ar; /* archive ELF descriptor. */ Dwarf_Debug dbg; /* DWARF handle. */ + Dwarf_Half cu_psize; /* DWARF CU pointer size. */ + Dwarf_Half cu_osize; /* DWARF CU offset size. */ + Dwarf_Half cu_ver; /* DWARF CU version. */ GElf_Ehdr ehdr; /* ELF header. */ int ec; /* ELF class. */ size_t shnum; /* #sections. */ struct section *vd_s; /* Verdef section. */ struct section *vn_s; /* Verneed section. */ struct section *vs_s; /* Versym section. */ uint16_t *vs; /* Versym array. */ int vs_sz; /* Versym array size. */ struct symver *ver; /* Version array. */ int ver_sz; /* Size of version array. */ struct section *sl; /* list of sections. */ STAILQ_HEAD(, dumpop) v_dumpop; /* list of dump ops. */ uint64_t (*dw_read)(Elf_Data *, uint64_t *, int); uint64_t (*dw_decode)(uint8_t **, int); }; enum options { OPTION_DEBUG_DUMP }; static struct option longopts[] = { {"all", no_argument, NULL, 'a'}, {"arch-specific", no_argument, NULL, 'A'}, {"archive-index", no_argument, NULL, 'c'}, {"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP}, {"dynamic", no_argument, NULL, 'd'}, {"file-header", no_argument, NULL, 'h'}, {"full-section-name", no_argument, NULL, 'N'}, {"headers", no_argument, NULL, 'e'}, {"help", no_argument, 0, 'H'}, {"hex-dump", required_argument, NULL, 'x'}, {"histogram", no_argument, NULL, 'I'}, {"notes", no_argument, NULL, 'n'}, {"program-headers", no_argument, NULL, 'l'}, {"relocs", no_argument, NULL, 'r'}, {"sections", no_argument, NULL, 'S'}, {"section-headers", no_argument, NULL, 'S'}, {"section-groups", no_argument, NULL, 'g'}, {"section-details", no_argument, NULL, 't'}, {"segments", no_argument, NULL, 'l'}, {"string-dump", required_argument, NULL, 'p'}, {"symbols", no_argument, NULL, 's'}, {"syms", no_argument, NULL, 's'}, {"unwind", no_argument, NULL, 'u'}, {"use-dynamic", no_argument, NULL, 'D'}, {"version-info", no_argument, 0, 'V'}, {"version", no_argument, 0, 'v'}, {"wide", no_argument, 0, 'W'}, {NULL, 0, NULL, 0} }; struct eflags_desc { uint64_t flag; const char *desc; }; struct mips_option { uint64_t flag; const char *desc; }; static void add_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t); static const char *aeabi_adv_simd_arch(uint64_t simd); static const char *aeabi_align_needed(uint64_t an); static const char *aeabi_align_preserved(uint64_t ap); static const char *aeabi_arm_isa(uint64_t ai); static const char *aeabi_cpu_arch(uint64_t arch); static const char *aeabi_cpu_arch_profile(uint64_t pf); static const char *aeabi_div(uint64_t du); static const char *aeabi_enum_size(uint64_t es); static const char *aeabi_fp_16bit_format(uint64_t fp16); static const char *aeabi_fp_arch(uint64_t fp); static const char *aeabi_fp_denormal(uint64_t fd); static const char *aeabi_fp_exceptions(uint64_t fe); static const char *aeabi_fp_hpext(uint64_t fh); static const char *aeabi_fp_number_model(uint64_t fn); static const char *aeabi_fp_optm_goal(uint64_t fog); static const char *aeabi_fp_rounding(uint64_t fr); static const char *aeabi_hardfp(uint64_t hfp); static const char *aeabi_mpext(uint64_t mp); static const char *aeabi_optm_goal(uint64_t og); static const char *aeabi_pcs_config(uint64_t pcs); static const char *aeabi_pcs_got(uint64_t got); static const char *aeabi_pcs_r9(uint64_t r9); static const char *aeabi_pcs_ro(uint64_t ro); static const char *aeabi_pcs_rw(uint64_t rw); static const char *aeabi_pcs_wchar_t(uint64_t wt); static const char *aeabi_t2ee(uint64_t t2ee); static const char *aeabi_thumb_isa(uint64_t ti); static const char *aeabi_fp_user_exceptions(uint64_t fu); static const char *aeabi_unaligned_access(uint64_t ua); static const char *aeabi_vfp_args(uint64_t va); static const char *aeabi_virtual(uint64_t vt); static const char *aeabi_wmmx_arch(uint64_t wmmx); static const char *aeabi_wmmx_args(uint64_t wa); static const char *elf_class(unsigned int class); static const char *elf_endian(unsigned int endian); static const char *elf_machine(unsigned int mach); static const char *elf_osabi(unsigned int abi); static const char *elf_type(unsigned int type); static const char *elf_ver(unsigned int ver); static const char *dt_type(unsigned int mach, unsigned int dtype); static void dump_ar(struct readelf *re, int); static void dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe); static void dump_attributes(struct readelf *re); static uint8_t *dump_compatibility_tag(uint8_t *p); static void dump_dwarf(struct readelf *re); +static void dump_dwarf_abbrev(struct readelf *re); +static void dump_dwarf_aranges(struct readelf *re); +static void dump_dwarf_block(struct readelf *re, uint8_t *b, + Dwarf_Unsigned len); +static void dump_dwarf_die(struct readelf *re, Dwarf_Die die, int level); +static void dump_dwarf_frame(struct readelf *re, int alt); +static void dump_dwarf_frame_inst(struct readelf *re, Dwarf_Cie cie, + uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, + Dwarf_Addr pc, Dwarf_Debug dbg); +static int dump_dwarf_frame_regtable(struct readelf *re, Dwarf_Fde fde, + Dwarf_Addr pc, Dwarf_Unsigned func_len, Dwarf_Half cie_ra); +static void dump_dwarf_frame_section(struct readelf *re, struct section *s, + int alt); +static void dump_dwarf_info(struct readelf *re, Dwarf_Bool is_info); +static void dump_dwarf_macinfo(struct readelf *re); +static void dump_dwarf_line(struct readelf *re); +static void dump_dwarf_line_decoded(struct readelf *re); +static void dump_dwarf_loc(struct readelf *re, Dwarf_Loc *lr); +static void dump_dwarf_loclist(struct readelf *re); +static void dump_dwarf_pubnames(struct readelf *re); +static void dump_dwarf_ranges(struct readelf *re); +static void dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die, + Dwarf_Addr base); +static void dump_dwarf_str(struct readelf *re); static void dump_eflags(struct readelf *re, uint64_t e_flags); static void dump_elf(struct readelf *re); static void dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab); static void dump_dynamic(struct readelf *re); static void dump_liblist(struct readelf *re); static void dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe); static void dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz); static void dump_mips_options(struct readelf *re, struct section *s); static void dump_mips_option_flags(const char *name, struct mips_option *opt, uint64_t info); static void dump_mips_reginfo(struct readelf *re, struct section *s); static void dump_mips_specific_info(struct readelf *re); static void dump_notes(struct readelf *re); static void dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off); static void dump_svr4_hash(struct section *s); static void dump_svr4_hash64(struct readelf *re, struct section *s); static void dump_gnu_hash(struct readelf *re, struct section *s); static void dump_hash(struct readelf *re); static void dump_phdr(struct readelf *re); static void dump_ppc_attributes(uint8_t *p, uint8_t *pe); static void dump_symtab(struct readelf *re, int i); static void dump_symtabs(struct readelf *re); static uint8_t *dump_unknown_tag(uint64_t tag, uint8_t *p); static void dump_ver(struct readelf *re); static void dump_verdef(struct readelf *re, int dump); static void dump_verneed(struct readelf *re, int dump); static void dump_versym(struct readelf *re); -static struct dumpop *find_dumpop(struct readelf *re, size_t si, const char *sn, - int op, int t); +static const char *dwarf_reg(unsigned int mach, unsigned int reg); +static const char *dwarf_regname(struct readelf *re, unsigned int num); +static struct dumpop *find_dumpop(struct readelf *re, size_t si, + const char *sn, int op, int t); +static char *get_regoff_str(struct readelf *re, Dwarf_Half reg, + Dwarf_Addr off); static const char *get_string(struct readelf *re, int strtab, size_t off); static const char *get_symbol_name(struct readelf *re, int symtab, int i); static uint64_t get_symbol_value(struct readelf *re, int symtab, int i); static void load_sections(struct readelf *re); static const char *mips_abi_fp(uint64_t fp); static const char *note_type(unsigned int osabi, unsigned int et, unsigned int nt); static const char *option_kind(uint8_t kind); static const char *phdr_type(unsigned int ptype); static const char *ppc_abi_fp(uint64_t fp); static const char *ppc_abi_vector(uint64_t vec); static const char *r_type(unsigned int mach, unsigned int type); static void readelf_usage(void); static void readelf_version(void); +static void search_loclist_at(struct readelf *re, Dwarf_Die die, + Dwarf_Unsigned lowpc); static void search_ver(struct readelf *re); static const char *section_type(unsigned int mach, unsigned int stype); +static void set_cu_context(struct readelf *re, Dwarf_Half psize, + Dwarf_Half osize, Dwarf_Half ver); static const char *st_bind(unsigned int sbind); static const char *st_shndx(unsigned int shndx); static const char *st_type(unsigned int stype); static const char *st_vis(unsigned int svis); static const char *top_tag(unsigned int tag); static void unload_sections(struct readelf *re); static uint64_t _read_lsb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read); static uint64_t _read_msb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read); static uint64_t _decode_lsb(uint8_t **data, int bytes_to_read); static uint64_t _decode_msb(uint8_t **data, int bytes_to_read); static int64_t _decode_sleb128(uint8_t **dp); static uint64_t _decode_uleb128(uint8_t **dp); static struct eflags_desc arm_eflags_desc[] = { {EF_ARM_RELEXEC, "relocatable executable"}, {EF_ARM_HASENTRY, "has entry point"}, {EF_ARM_SYMSARESORTED, "sorted symbol tables"}, {EF_ARM_DYNSYMSUSESEGIDX, "dynamic symbols use segment index"}, {EF_ARM_MAPSYMSFIRST, "mapping symbols precede others"}, {EF_ARM_BE8, "BE8"}, {EF_ARM_LE8, "LE8"}, {EF_ARM_INTERWORK, "interworking enabled"}, {EF_ARM_APCS_26, "uses APCS/26"}, {EF_ARM_APCS_FLOAT, "uses APCS/float"}, {EF_ARM_PIC, "position independent"}, {EF_ARM_ALIGN8, "8 bit structure alignment"}, {EF_ARM_NEW_ABI, "uses new ABI"}, {EF_ARM_OLD_ABI, "uses old ABI"}, {EF_ARM_SOFT_FLOAT, "software FP"}, {EF_ARM_VFP_FLOAT, "VFP"}, {EF_ARM_MAVERICK_FLOAT, "Maverick FP"}, {0, NULL} }; static struct eflags_desc mips_eflags_desc[] = { {EF_MIPS_NOREORDER, "noreorder"}, {EF_MIPS_PIC, "pic"}, {EF_MIPS_CPIC, "cpic"}, {EF_MIPS_UCODE, "ugen_reserved"}, {EF_MIPS_ABI2, "abi2"}, {EF_MIPS_OPTIONS_FIRST, "odk first"}, {EF_MIPS_ARCH_ASE_MDMX, "mdmx"}, {EF_MIPS_ARCH_ASE_M16, "mips16"}, {0, NULL} }; static struct eflags_desc powerpc_eflags_desc[] = { {EF_PPC_EMB, "emb"}, {EF_PPC_RELOCATABLE, "relocatable"}, {EF_PPC_RELOCATABLE_LIB, "relocatable-lib"}, {0, NULL} }; static struct eflags_desc sparc_eflags_desc[] = { {EF_SPARC_32PLUS, "v8+"}, {EF_SPARC_SUN_US1, "ultrasparcI"}, {EF_SPARC_HAL_R1, "halr1"}, {EF_SPARC_SUN_US3, "ultrasparcIII"}, {0, NULL} }; static const char * elf_osabi(unsigned int abi) { static char s_abi[32]; switch(abi) { case ELFOSABI_SYSV: return "SYSV"; case ELFOSABI_HPUX: return "HPUS"; case ELFOSABI_NETBSD: return "NetBSD"; case ELFOSABI_GNU: return "GNU"; case ELFOSABI_HURD: return "HURD"; case ELFOSABI_86OPEN: return "86OPEN"; case ELFOSABI_SOLARIS: return "Solaris"; case ELFOSABI_AIX: return "AIX"; case ELFOSABI_IRIX: return "IRIX"; case ELFOSABI_FREEBSD: return "FreeBSD"; case ELFOSABI_TRU64: return "TRU64"; case ELFOSABI_MODESTO: return "MODESTO"; case ELFOSABI_OPENBSD: return "OpenBSD"; case ELFOSABI_OPENVMS: return "OpenVMS"; case ELFOSABI_NSK: return "NSK"; case ELFOSABI_ARM: return "ARM"; case ELFOSABI_STANDALONE: return "StandAlone"; default: snprintf(s_abi, sizeof(s_abi), "", abi); return (s_abi); } }; static const char * elf_machine(unsigned int mach) { static char s_mach[32]; switch (mach) { case EM_NONE: return "Unknown machine"; case EM_M32: return "AT&T WE32100"; case EM_SPARC: return "Sun SPARC"; case EM_386: return "Intel i386"; case EM_68K: return "Motorola 68000"; case EM_88K: return "Motorola 88000"; case EM_860: return "Intel i860"; case EM_MIPS: return "MIPS R3000 Big-Endian only"; case EM_S370: return "IBM System/370"; case EM_MIPS_RS3_LE: return "MIPS R3000 Little-Endian"; case EM_PARISC: return "HP PA-RISC"; case EM_VPP500: return "Fujitsu VPP500"; case EM_SPARC32PLUS: return "SPARC v8plus"; case EM_960: return "Intel 80960"; case EM_PPC: return "PowerPC 32-bit"; case EM_PPC64: return "PowerPC 64-bit"; case EM_S390: return "IBM System/390"; case EM_V800: return "NEC V800"; case EM_FR20: return "Fujitsu FR20"; case EM_RH32: return "TRW RH-32"; case EM_RCE: return "Motorola RCE"; case EM_ARM: return "ARM"; case EM_SH: return "Hitachi SH"; case EM_SPARCV9: return "SPARC v9 64-bit"; case EM_TRICORE: return "Siemens TriCore embedded processor"; case EM_ARC: return "Argonaut RISC Core"; case EM_H8_300: return "Hitachi H8/300"; case EM_H8_300H: return "Hitachi H8/300H"; case EM_H8S: return "Hitachi H8S"; case EM_H8_500: return "Hitachi H8/500"; case EM_IA_64: return "Intel IA-64 Processor"; case EM_MIPS_X: return "Stanford MIPS-X"; case EM_COLDFIRE: return "Motorola ColdFire"; case EM_68HC12: return "Motorola M68HC12"; case EM_MMA: return "Fujitsu MMA"; case EM_PCP: return "Siemens PCP"; case EM_NCPU: return "Sony nCPU"; case EM_NDR1: return "Denso NDR1 microprocessor"; case EM_STARCORE: return "Motorola Star*Core processor"; case EM_ME16: return "Toyota ME16 processor"; case EM_ST100: return "STMicroelectronics ST100 processor"; case EM_TINYJ: return "Advanced Logic Corp. TinyJ processor"; case EM_X86_64: return "Advanced Micro Devices x86-64"; case EM_PDSP: return "Sony DSP Processor"; case EM_FX66: return "Siemens FX66 microcontroller"; case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 microcontroller"; case EM_ST7: return "STmicroelectronics ST7 8-bit microcontroller"; case EM_68HC16: return "Motorola MC68HC16 microcontroller"; case EM_68HC11: return "Motorola MC68HC11 microcontroller"; case EM_68HC08: return "Motorola MC68HC08 microcontroller"; case EM_68HC05: return "Motorola MC68HC05 microcontroller"; case EM_SVX: return "Silicon Graphics SVx"; case EM_ST19: return "STMicroelectronics ST19 8-bit mc"; case EM_VAX: return "Digital VAX"; case EM_CRIS: return "Axis Communications 32-bit embedded processor"; case EM_JAVELIN: return "Infineon Tech. 32bit embedded processor"; case EM_FIREPATH: return "Element 14 64-bit DSP Processor"; case EM_ZSP: return "LSI Logic 16-bit DSP Processor"; case EM_MMIX: return "Donald Knuth's educational 64-bit proc"; case EM_HUANY: return "Harvard University MI object files"; case EM_PRISM: return "SiTera Prism"; case EM_AVR: return "Atmel AVR 8-bit microcontroller"; case EM_FR30: return "Fujitsu FR30"; case EM_D10V: return "Mitsubishi D10V"; case EM_D30V: return "Mitsubishi D30V"; case EM_V850: return "NEC v850"; case EM_M32R: return "Mitsubishi M32R"; case EM_MN10300: return "Matsushita MN10300"; case EM_MN10200: return "Matsushita MN10200"; case EM_PJ: return "picoJava"; case EM_OPENRISC: return "OpenRISC 32-bit embedded processor"; case EM_ARC_A5: return "ARC Cores Tangent-A5"; case EM_XTENSA: return "Tensilica Xtensa Architecture"; case EM_VIDEOCORE: return "Alphamosaic VideoCore processor"; case EM_TMM_GPP: return "Thompson Multimedia General Purpose Processor"; case EM_NS32K: return "National Semiconductor 32000 series"; case EM_TPC: return "Tenor Network TPC processor"; case EM_SNP1K: return "Trebia SNP 1000 processor"; case EM_ST200: return "STMicroelectronics ST200 microcontroller"; case EM_IP2K: return "Ubicom IP2xxx microcontroller family"; case EM_MAX: return "MAX Processor"; case EM_CR: return "National Semiconductor CompactRISC microprocessor"; case EM_F2MC16: return "Fujitsu F2MC16"; case EM_MSP430: return "TI embedded microcontroller msp430"; case EM_BLACKFIN: return "Analog Devices Blackfin (DSP) processor"; case EM_SE_C33: return "S1C33 Family of Seiko Epson processors"; case EM_SEP: return "Sharp embedded microprocessor"; case EM_ARCA: return "Arca RISC Microprocessor"; case EM_UNICORE: return "Microprocessor series from PKU-Unity Ltd"; + case EM_AARCH64: return "AArch64"; default: snprintf(s_mach, sizeof(s_mach), "", mach); return (s_mach); } } static const char * elf_class(unsigned int class) { static char s_class[32]; switch (class) { case ELFCLASSNONE: return "none"; case ELFCLASS32: return "ELF32"; case ELFCLASS64: return "ELF64"; default: snprintf(s_class, sizeof(s_class), "", class); return (s_class); } } static const char * elf_endian(unsigned int endian) { static char s_endian[32]; switch (endian) { case ELFDATANONE: return "none"; case ELFDATA2LSB: return "2's complement, little endian"; case ELFDATA2MSB: return "2's complement, big endian"; default: snprintf(s_endian, sizeof(s_endian), "", endian); return (s_endian); } } static const char * elf_type(unsigned int type) { static char s_type[32]; switch (type) { case ET_NONE: return "NONE (None)"; case ET_REL: return "REL (Relocatable file)"; case ET_EXEC: return "EXEC (Executable file)"; case ET_DYN: return "DYN (Shared object file)"; case ET_CORE: return "CORE (Core file)"; default: if (type >= ET_LOPROC) snprintf(s_type, sizeof(s_type), "", type); else if (type >= ET_LOOS && type <= ET_HIOS) snprintf(s_type, sizeof(s_type), "", type); else snprintf(s_type, sizeof(s_type), "", type); return (s_type); } } static const char * elf_ver(unsigned int ver) { static char s_ver[32]; switch (ver) { case EV_CURRENT: return "(current)"; case EV_NONE: return "(none)"; default: snprintf(s_ver, sizeof(s_ver), "", ver); return (s_ver); } } static const char * phdr_type(unsigned int ptype) { static char s_ptype[32]; switch (ptype) { case PT_NULL: return "NULL"; case PT_LOAD: return "LOAD"; case PT_DYNAMIC: return "DYNAMIC"; case PT_INTERP: return "INTERP"; case PT_NOTE: return "NOTE"; case PT_SHLIB: return "SHLIB"; case PT_PHDR: return "PHDR"; case PT_TLS: return "TLS"; case PT_GNU_EH_FRAME: return "GNU_EH_FRAME"; case PT_GNU_STACK: return "GNU_STACK"; case PT_GNU_RELRO: return "GNU_RELRO"; default: if (ptype >= PT_LOPROC && ptype <= PT_HIPROC) snprintf(s_ptype, sizeof(s_ptype), "LOPROC+%#x", ptype - PT_LOPROC); else if (ptype >= PT_LOOS && ptype <= PT_HIOS) snprintf(s_ptype, sizeof(s_ptype), "LOOS+%#x", ptype - PT_LOOS); else snprintf(s_ptype, sizeof(s_ptype), "", ptype); return (s_ptype); } } static const char * section_type(unsigned int mach, unsigned int stype) { static char s_stype[32]; if (stype >= SHT_LOPROC && stype <= SHT_HIPROC) { switch (mach) { case EM_X86_64: switch (stype) { case SHT_AMD64_UNWIND: return "AMD64_UNWIND"; default: break; } break; case EM_MIPS: case EM_MIPS_RS3_LE: switch (stype) { case SHT_MIPS_LIBLIST: return "MIPS_LIBLIST"; case SHT_MIPS_MSYM: return "MIPS_MSYM"; case SHT_MIPS_CONFLICT: return "MIPS_CONFLICT"; case SHT_MIPS_GPTAB: return "MIPS_GPTAB"; case SHT_MIPS_UCODE: return "MIPS_UCODE"; case SHT_MIPS_DEBUG: return "MIPS_DEBUG"; case SHT_MIPS_REGINFO: return "MIPS_REGINFO"; case SHT_MIPS_PACKAGE: return "MIPS_PACKAGE"; case SHT_MIPS_PACKSYM: return "MIPS_PACKSYM"; case SHT_MIPS_RELD: return "MIPS_RELD"; case SHT_MIPS_IFACE: return "MIPS_IFACE"; case SHT_MIPS_CONTENT: return "MIPS_CONTENT"; case SHT_MIPS_OPTIONS: return "MIPS_OPTIONS"; case SHT_MIPS_DELTASYM: return "MIPS_DELTASYM"; case SHT_MIPS_DELTAINST: return "MIPS_DELTAINST"; case SHT_MIPS_DELTACLASS: return "MIPS_DELTACLASS"; case SHT_MIPS_DWARF: return "MIPS_DWARF"; case SHT_MIPS_DELTADECL: return "MIPS_DELTADECL"; case SHT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB"; case SHT_MIPS_EVENTS: return "MIPS_EVENTS"; case SHT_MIPS_TRANSLATE: return "MIPS_TRANSLATE"; case SHT_MIPS_PIXIE: return "MIPS_PIXIE"; case SHT_MIPS_XLATE: return "MIPS_XLATE"; case SHT_MIPS_XLATE_DEBUG: return "MIPS_XLATE_DEBUG"; case SHT_MIPS_WHIRL: return "MIPS_WHIRL"; case SHT_MIPS_EH_REGION: return "MIPS_EH_REGION"; case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD"; case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION"; default: break; } break; default: break; } snprintf(s_stype, sizeof(s_stype), "LOPROC+%#x", stype - SHT_LOPROC); return (s_stype); } switch (stype) { case SHT_NULL: return "NULL"; case SHT_PROGBITS: return "PROGBITS"; case SHT_SYMTAB: return "SYMTAB"; case SHT_STRTAB: return "STRTAB"; case SHT_RELA: return "RELA"; case SHT_HASH: return "HASH"; case SHT_DYNAMIC: return "DYNAMIC"; case SHT_NOTE: return "NOTE"; case SHT_NOBITS: return "NOBITS"; case SHT_REL: return "REL"; case SHT_SHLIB: return "SHLIB"; case SHT_DYNSYM: return "DYNSYM"; case SHT_INIT_ARRAY: return "INIT_ARRAY"; case SHT_FINI_ARRAY: return "FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY"; case SHT_GROUP: return "GROUP"; case SHT_SYMTAB_SHNDX: return "SYMTAB_SHNDX"; case SHT_SUNW_dof: return "SUNW_dof"; case SHT_SUNW_cap: return "SUNW_cap"; case SHT_GNU_HASH: return "GNU_HASH"; case SHT_SUNW_ANNOTATE: return "SUNW_ANNOTATE"; case SHT_SUNW_DEBUGSTR: return "SUNW_DEBUGSTR"; case SHT_SUNW_DEBUG: return "SUNW_DEBUG"; case SHT_SUNW_move: return "SUNW_move"; case SHT_SUNW_COMDAT: return "SUNW_COMDAT"; case SHT_SUNW_syminfo: return "SUNW_syminfo"; case SHT_SUNW_verdef: return "SUNW_verdef"; case SHT_SUNW_verneed: return "SUNW_verneed"; case SHT_SUNW_versym: return "SUNW_versym"; default: if (stype >= SHT_LOOS && stype <= SHT_HIOS) snprintf(s_stype, sizeof(s_stype), "LOOS+%#x", stype - SHT_LOOS); else if (stype >= SHT_LOUSER) snprintf(s_stype, sizeof(s_stype), "LOUSER+%#x", stype - SHT_LOUSER); else snprintf(s_stype, sizeof(s_stype), "", stype); return (s_stype); } } static const char * dt_type(unsigned int mach, unsigned int dtype) { static char s_dtype[32]; if (dtype >= DT_LOPROC && dtype <= DT_HIPROC) { switch (mach) { case EM_ARM: switch (dtype) { case DT_ARM_SYMTABSZ: return "ARM_SYMTABSZ"; default: break; } break; case EM_MIPS: case EM_MIPS_RS3_LE: switch (dtype) { case DT_MIPS_RLD_VERSION: return "MIPS_RLD_VERSION"; case DT_MIPS_TIME_STAMP: return "MIPS_TIME_STAMP"; case DT_MIPS_ICHECKSUM: return "MIPS_ICHECKSUM"; case DT_MIPS_IVERSION: return "MIPS_IVERSION"; case DT_MIPS_FLAGS: return "MIPS_FLAGS"; case DT_MIPS_BASE_ADDRESS: return "MIPS_BASE_ADDRESS"; case DT_MIPS_CONFLICT: return "MIPS_CONFLICT"; case DT_MIPS_LIBLIST: return "MIPS_LIBLIST"; case DT_MIPS_LOCAL_GOTNO: return "MIPS_LOCAL_GOTNO"; case DT_MIPS_CONFLICTNO: return "MIPS_CONFLICTNO"; case DT_MIPS_LIBLISTNO: return "MIPS_LIBLISTNO"; case DT_MIPS_SYMTABNO: return "MIPS_SYMTABNO"; case DT_MIPS_UNREFEXTNO: return "MIPS_UNREFEXTNO"; case DT_MIPS_GOTSYM: return "MIPS_GOTSYM"; case DT_MIPS_HIPAGENO: return "MIPS_HIPAGENO"; case DT_MIPS_RLD_MAP: return "MIPS_RLD_MAP"; case DT_MIPS_DELTA_CLASS: return "MIPS_DELTA_CLASS"; case DT_MIPS_DELTA_CLASS_NO: return "MIPS_DELTA_CLASS_NO"; case DT_MIPS_DELTA_INSTANCE: return "MIPS_DELTA_INSTANCE"; case DT_MIPS_DELTA_INSTANCE_NO: return "MIPS_DELTA_INSTANCE_NO"; case DT_MIPS_DELTA_RELOC: return "MIPS_DELTA_RELOC"; case DT_MIPS_DELTA_RELOC_NO: return "MIPS_DELTA_RELOC_NO"; case DT_MIPS_DELTA_SYM: return "MIPS_DELTA_SYM"; case DT_MIPS_DELTA_SYM_NO: return "MIPS_DELTA_SYM_NO"; case DT_MIPS_DELTA_CLASSSYM: return "MIPS_DELTA_CLASSSYM"; case DT_MIPS_DELTA_CLASSSYM_NO: return "MIPS_DELTA_CLASSSYM_NO"; case DT_MIPS_CXX_FLAGS: return "MIPS_CXX_FLAGS"; case DT_MIPS_PIXIE_INIT: return "MIPS_PIXIE_INIT"; case DT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB"; case DT_MIPS_LOCALPAGE_GOTIDX: return "MIPS_LOCALPAGE_GOTIDX"; case DT_MIPS_LOCAL_GOTIDX: return "MIPS_LOCAL_GOTIDX"; case DT_MIPS_HIDDEN_GOTIDX: return "MIPS_HIDDEN_GOTIDX"; case DT_MIPS_PROTECTED_GOTIDX: return "MIPS_PROTECTED_GOTIDX"; case DT_MIPS_OPTIONS: return "MIPS_OPTIONS"; case DT_MIPS_INTERFACE: return "MIPS_INTERFACE"; case DT_MIPS_DYNSTR_ALIGN: return "MIPS_DYNSTR_ALIGN"; case DT_MIPS_INTERFACE_SIZE: return "MIPS_INTERFACE_SIZE"; case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: return "MIPS_RLD_TEXT_RESOLVE_ADDR"; case DT_MIPS_PERF_SUFFIX: return "MIPS_PERF_SUFFIX"; case DT_MIPS_COMPACT_SIZE: return "MIPS_COMPACT_SIZE"; case DT_MIPS_GP_VALUE: return "MIPS_GP_VALUE"; case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC"; case DT_MIPS_PLTGOT: return "MIPS_PLTGOT"; case DT_MIPS_RLD_OBJ_UPDATE: return "MIPS_RLD_OBJ_UPDATE"; case DT_MIPS_RWPLT: return "MIPS_RWPLT"; default: break; } break; case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: switch (dtype) { case DT_SPARC_REGISTER: return "DT_SPARC_REGISTER"; default: break; } break; default: break; } snprintf(s_dtype, sizeof(s_dtype), "", dtype); return (s_dtype); } switch (dtype) { case DT_NULL: return "NULL"; case DT_NEEDED: return "NEEDED"; case DT_PLTRELSZ: return "PLTRELSZ"; case DT_PLTGOT: return "PLTGOT"; case DT_HASH: return "HASH"; case DT_STRTAB: return "STRTAB"; case DT_SYMTAB: return "SYMTAB"; case DT_RELA: return "RELA"; case DT_RELASZ: return "RELASZ"; case DT_RELAENT: return "RELAENT"; case DT_STRSZ: return "STRSZ"; case DT_SYMENT: return "SYMENT"; case DT_INIT: return "INIT"; case DT_FINI: return "FINI"; case DT_SONAME: return "SONAME"; case DT_RPATH: return "RPATH"; case DT_SYMBOLIC: return "SYMBOLIC"; case DT_REL: return "REL"; case DT_RELSZ: return "RELSZ"; case DT_RELENT: return "RELENT"; case DT_PLTREL: return "PLTREL"; case DT_DEBUG: return "DEBUG"; case DT_TEXTREL: return "TEXTREL"; case DT_JMPREL: return "JMPREL"; case DT_BIND_NOW: return "BIND_NOW"; case DT_INIT_ARRAY: return "INIT_ARRAY"; case DT_FINI_ARRAY: return "FINI_ARRAY"; case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ"; case DT_RUNPATH: return "RUNPATH"; case DT_FLAGS: return "FLAGS"; case DT_PREINIT_ARRAY: return "PREINIT_ARRAY"; case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ"; case DT_MAXPOSTAGS: return "MAXPOSTAGS"; case DT_SUNW_AUXILIARY: return "SUNW_AUXILIARY"; case DT_SUNW_RTLDINF: return "SUNW_RTLDINF"; case DT_SUNW_FILTER: return "SUNW_FILTER"; case DT_SUNW_CAP: return "SUNW_CAP"; case DT_CHECKSUM: return "CHECKSUM"; case DT_PLTPADSZ: return "PLTPADSZ"; case DT_MOVEENT: return "MOVEENT"; case DT_MOVESZ: return "MOVESZ"; case DT_FEATURE_1: return "FEATURE_1"; case DT_POSFLAG_1: return "POSFLAG_1"; case DT_SYMINSZ: return "SYMINSZ"; case DT_SYMINENT: return "SYMINENT"; case DT_GNU_HASH: return "GNU_HASH"; case DT_GNU_CONFLICT: return "GNU_CONFLICT"; case DT_GNU_LIBLIST: return "GNU_LIBLIST"; case DT_CONFIG: return "CONFIG"; case DT_DEPAUDIT: return "DEPAUDIT"; case DT_AUDIT: return "AUDIT"; case DT_PLTPAD: return "PLTPAD"; case DT_MOVETAB: return "MOVETAB"; case DT_SYMINFO: return "SYMINFO"; case DT_VERSYM: return "VERSYM"; case DT_RELACOUNT: return "RELACOUNT"; case DT_RELCOUNT: return "RELCOUNT"; case DT_FLAGS_1: return "FLAGS_1"; case DT_VERDEF: return "VERDEF"; case DT_VERDEFNUM: return "VERDEFNUM"; case DT_VERNEED: return "VERNEED"; case DT_VERNEEDNUM: return "VERNEEDNUM"; case DT_AUXILIARY: return "AUXILIARY"; case DT_USED: return "USED"; case DT_FILTER: return "FILTER"; case DT_GNU_PRELINKED: return "GNU_PRELINKED"; case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; default: snprintf(s_dtype, sizeof(s_dtype), "", dtype); return (s_dtype); } } static const char * st_bind(unsigned int sbind) { static char s_sbind[32]; switch (sbind) { case STB_LOCAL: return "LOCAL"; case STB_GLOBAL: return "GLOBAL"; case STB_WEAK: return "WEAK"; default: if (sbind >= STB_LOOS && sbind <= STB_HIOS) return "OS"; else if (sbind >= STB_LOPROC && sbind <= STB_HIPROC) return "PROC"; else snprintf(s_sbind, sizeof(s_sbind), "", sbind); return (s_sbind); } } static const char * st_type(unsigned int stype) { static char s_stype[32]; switch (stype) { case STT_NOTYPE: return "NOTYPE"; case STT_OBJECT: return "OBJECT"; case STT_FUNC: return "FUNC"; case STT_SECTION: return "SECTION"; case STT_FILE: return "FILE"; case STT_COMMON: return "COMMON"; case STT_TLS: return "TLS"; default: if (stype >= STT_LOOS && stype <= STT_HIOS) snprintf(s_stype, sizeof(s_stype), "OS+%#x", stype - STT_LOOS); else if (stype >= STT_LOPROC && stype <= STT_HIPROC) snprintf(s_stype, sizeof(s_stype), "PROC+%#x", stype - STT_LOPROC); else snprintf(s_stype, sizeof(s_stype), "", stype); return (s_stype); } } static const char * st_vis(unsigned int svis) { static char s_svis[32]; switch(svis) { case STV_DEFAULT: return "DEFAULT"; case STV_INTERNAL: return "INTERNAL"; case STV_HIDDEN: return "HIDDEN"; case STV_PROTECTED: return "PROTECTED"; default: snprintf(s_svis, sizeof(s_svis), "", svis); return (s_svis); } } static const char * st_shndx(unsigned int shndx) { static char s_shndx[32]; switch (shndx) { case SHN_UNDEF: return "UND"; case SHN_ABS: return "ABS"; case SHN_COMMON: return "COM"; default: if (shndx >= SHN_LOPROC && shndx <= SHN_HIPROC) return "PRC"; else if (shndx >= SHN_LOOS && shndx <= SHN_HIOS) return "OS"; else snprintf(s_shndx, sizeof(s_shndx), "%u", shndx); return (s_shndx); } } static struct { const char *ln; char sn; int value; } section_flag[] = { {"WRITE", 'W', SHF_WRITE}, {"ALLOC", 'A', SHF_ALLOC}, {"EXEC", 'X', SHF_EXECINSTR}, {"MERGE", 'M', SHF_MERGE}, {"STRINGS", 'S', SHF_STRINGS}, {"INFO LINK", 'I', SHF_INFO_LINK}, {"OS NONCONF", 'O', SHF_OS_NONCONFORMING}, {"GROUP", 'G', SHF_GROUP}, {"TLS", 'T', SHF_TLS}, {NULL, 0, 0} }; static const char * r_type(unsigned int mach, unsigned int type) { switch(mach) { case EM_NONE: return ""; case EM_386: switch(type) { case 0: return "R_386_NONE"; case 1: return "R_386_32"; case 2: return "R_386_PC32"; case 3: return "R_386_GOT32"; case 4: return "R_386_PLT32"; case 5: return "R_386_COPY"; case 6: return "R_386_GLOB_DAT"; case 7: return "R_386_JMP_SLOT"; case 8: return "R_386_RELATIVE"; case 9: return "R_386_GOTOFF"; case 10: return "R_386_GOTPC"; case 14: return "R_386_TLS_TPOFF"; case 15: return "R_386_TLS_IE"; case 16: return "R_386_TLS_GOTIE"; case 17: return "R_386_TLS_LE"; case 18: return "R_386_TLS_GD"; case 19: return "R_386_TLS_LDM"; case 24: return "R_386_TLS_GD_32"; case 25: return "R_386_TLS_GD_PUSH"; case 26: return "R_386_TLS_GD_CALL"; case 27: return "R_386_TLS_GD_POP"; case 28: return "R_386_TLS_LDM_32"; case 29: return "R_386_TLS_LDM_PUSH"; case 30: return "R_386_TLS_LDM_CALL"; case 31: return "R_386_TLS_LDM_POP"; case 32: return "R_386_TLS_LDO_32"; case 33: return "R_386_TLS_IE_32"; case 34: return "R_386_TLS_LE_32"; case 35: return "R_386_TLS_DTPMOD32"; case 36: return "R_386_TLS_DTPOFF32"; case 37: return "R_386_TLS_TPOFF32"; default: return ""; } + case EM_AARCH64: + switch(type) { + case 0: return "R_AARCH64_NONE"; + case 257: return "R_AARCH64_ABS64"; + case 258: return "R_AARCH64_ABS32"; + case 259: return "R_AARCH64_ABS16"; + case 260: return "R_AARCH64_PREL64"; + case 261: return "R_AARCH64_PREL32"; + case 262: return "R_AARCH64_PREL16"; + case 263: return "R_AARCH64_MOVW_UABS_G0"; + case 264: return "R_AARCH64_MOVW_UABS_G0_NC"; + case 265: return "R_AARCH64_MOVW_UABS_G1"; + case 266: return "R_AARCH64_MOVW_UABS_G1_NC"; + case 267: return "R_AARCH64_MOVW_UABS_G2"; + case 268: return "R_AARCH64_MOVW_UABS_G2_NC"; + case 269: return "R_AARCH64_MOVW_UABS_G3"; + case 270: return "R_AARCH64_MOVW_SABS_G0"; + case 271: return "R_AARCH64_MOVW_SABS_G1"; + case 272: return "R_AARCH64_MOVW_SABS_G2"; + case 273: return "R_AARCH64_LD_PREL_LO19"; + case 274: return "R_AARCH64_ADR_PREL_LO21"; + case 275: return "R_AARCH64_ADR_PREL_PG_HI21"; + case 276: return "R_AARCH64_ADR_PREL_PG_HI21_NC"; + case 277: return "R_AARCH64_ADD_ABS_LO12_NC"; + case 278: return "R_AARCH64_LDST8_ABS_LO12_NC"; + case 279: return "R_AARCH64_TSTBR14"; + case 280: return "R_AARCH64_CONDBR19"; + case 282: return "R_AARCH64_JUMP26"; + case 283: return "R_AARCH64_CALL26"; + case 284: return "R_AARCH64_LDST16_ABS_LO12_NC"; + case 285: return "R_AARCH64_LDST32_ABS_LO12_NC"; + case 286: return "R_AARCH64_LDST64_ABS_LO12_NC"; + case 287: return "R_AARCH64_MOVW_PREL_G0"; + case 288: return "R_AARCH64_MOVW_PREL_G0_NC"; + case 289: return "R_AARCH64_MOVW_PREL_G1"; + case 290: return "R_AARCH64_MOVW_PREL_G1_NC"; + case 291: return "R_AARCH64_MOVW_PREL_G2"; + case 292: return "R_AARCH64_MOVW_PREL_G2_NC"; + case 293: return "R_AARCH64_MOVW_PREL_G3"; + case 299: return "R_AARCH64_LDST128_ABS_LO12_NC"; + case 300: return "R_AARCH64_MOVW_GOTOFF_G0"; + case 301: return "R_AARCH64_MOVW_GOTOFF_G0_NC"; + case 302: return "R_AARCH64_MOVW_GOTOFF_G1"; + case 303: return "R_AARCH64_MOVW_GOTOFF_G1_NC"; + case 304: return "R_AARCH64_MOVW_GOTOFF_G2"; + case 305: return "R_AARCH64_MOVW_GOTOFF_G2_NC"; + case 306: return "R_AARCH64_MOVW_GOTOFF_G3"; + case 307: return "R_AARCH64_GOTREL64"; + case 308: return "R_AARCH64_GOTREL32"; + case 309: return "R_AARCH64_GOT_LD_PREL19"; + case 310: return "R_AARCH64_LD64_GOTOFF_LO15"; + case 311: return "R_AARCH64_ADR_GOT_PAGE"; + case 312: return "R_AARCH64_LD64_GOT_LO12_NC"; + case 313: return "R_AARCH64_LD64_GOTPAGE_LO15"; + case 1024: return "R_AARCH64_COPY"; + case 1025: return "R_AARCH64_GLOB_DAT"; + case 1026: return "R_AARCH64_JUMP_SLOT"; + case 1027: return "R_AARCH64_RELATIVE"; + case 1031: return "R_AARCH64_TLSDESC"; + default: return ""; + } case EM_ARM: switch(type) { case 0: return "R_ARM_NONE"; case 1: return "R_ARM_PC24"; case 2: return "R_ARM_ABS32"; case 3: return "R_ARM_REL32"; case 4: return "R_ARM_PC13"; case 5: return "R_ARM_ABS16"; case 6: return "R_ARM_ABS12"; case 7: return "R_ARM_THM_ABS5"; case 8: return "R_ARM_ABS8"; case 9: return "R_ARM_SBREL32"; case 10: return "R_ARM_THM_PC22"; case 11: return "R_ARM_THM_PC8"; case 12: return "R_ARM_AMP_VCALL9"; case 13: return "R_ARM_SWI24"; case 14: return "R_ARM_THM_SWI8"; case 15: return "R_ARM_XPC25"; case 16: return "R_ARM_THM_XPC22"; case 20: return "R_ARM_COPY"; case 21: return "R_ARM_GLOB_DAT"; case 22: return "R_ARM_JUMP_SLOT"; case 23: return "R_ARM_RELATIVE"; case 24: return "R_ARM_GOTOFF"; case 25: return "R_ARM_GOTPC"; case 26: return "R_ARM_GOT32"; case 27: return "R_ARM_PLT32"; case 100: return "R_ARM_GNU_VTENTRY"; case 101: return "R_ARM_GNU_VTINHERIT"; case 250: return "R_ARM_RSBREL32"; case 251: return "R_ARM_THM_RPC22"; case 252: return "R_ARM_RREL32"; case 253: return "R_ARM_RABS32"; case 254: return "R_ARM_RPC24"; case 255: return "R_ARM_RBASE"; default: return ""; } case EM_IA_64: switch(type) { case 0: return "R_IA_64_NONE"; case 33: return "R_IA_64_IMM14"; case 34: return "R_IA_64_IMM22"; case 35: return "R_IA_64_IMM64"; case 36: return "R_IA_64_DIR32MSB"; case 37: return "R_IA_64_DIR32LSB"; case 38: return "R_IA_64_DIR64MSB"; case 39: return "R_IA_64_DIR64LSB"; case 42: return "R_IA_64_GPREL22"; case 43: return "R_IA_64_GPREL64I"; case 44: return "R_IA_64_GPREL32MSB"; case 45: return "R_IA_64_GPREL32LSB"; case 46: return "R_IA_64_GPREL64MSB"; case 47: return "R_IA_64_GPREL64LSB"; case 50: return "R_IA_64_LTOFF22"; case 51: return "R_IA_64_LTOFF64I"; case 58: return "R_IA_64_PLTOFF22"; case 59: return "R_IA_64_PLTOFF64I"; case 62: return "R_IA_64_PLTOFF64MSB"; case 63: return "R_IA_64_PLTOFF64LSB"; case 67: return "R_IA_64_FPTR64I"; case 68: return "R_IA_64_FPTR32MSB"; case 69: return "R_IA_64_FPTR32LSB"; case 70: return "R_IA_64_FPTR64MSB"; case 71: return "R_IA_64_FPTR64LSB"; case 72: return "R_IA_64_PCREL60B"; case 73: return "R_IA_64_PCREL21B"; case 74: return "R_IA_64_PCREL21M"; case 75: return "R_IA_64_PCREL21F"; case 76: return "R_IA_64_PCREL32MSB"; case 77: return "R_IA_64_PCREL32LSB"; case 78: return "R_IA_64_PCREL64MSB"; case 79: return "R_IA_64_PCREL64LSB"; case 82: return "R_IA_64_LTOFF_FPTR22"; case 83: return "R_IA_64_LTOFF_FPTR64I"; case 84: return "R_IA_64_LTOFF_FPTR32MSB"; case 85: return "R_IA_64_LTOFF_FPTR32LSB"; case 86: return "R_IA_64_LTOFF_FPTR64MSB"; case 87: return "R_IA_64_LTOFF_FPTR64LSB"; case 92: return "R_IA_64_SEGREL32MSB"; case 93: return "R_IA_64_SEGREL32LSB"; case 94: return "R_IA_64_SEGREL64MSB"; case 95: return "R_IA_64_SEGREL64LSB"; case 100: return "R_IA_64_SECREL32MSB"; case 101: return "R_IA_64_SECREL32LSB"; case 102: return "R_IA_64_SECREL64MSB"; case 103: return "R_IA_64_SECREL64LSB"; case 108: return "R_IA_64_REL32MSB"; case 109: return "R_IA_64_REL32LSB"; case 110: return "R_IA_64_REL64MSB"; case 111: return "R_IA_64_REL64LSB"; case 116: return "R_IA_64_LTV32MSB"; case 117: return "R_IA_64_LTV32LSB"; case 118: return "R_IA_64_LTV64MSB"; case 119: return "R_IA_64_LTV64LSB"; case 121: return "R_IA_64_PCREL21BI"; case 122: return "R_IA_64_PCREL22"; case 123: return "R_IA_64_PCREL64I"; case 128: return "R_IA_64_IPLTMSB"; case 129: return "R_IA_64_IPLTLSB"; case 133: return "R_IA_64_SUB"; case 134: return "R_IA_64_LTOFF22X"; case 135: return "R_IA_64_LDXMOV"; case 145: return "R_IA_64_TPREL14"; case 146: return "R_IA_64_TPREL22"; case 147: return "R_IA_64_TPREL64I"; case 150: return "R_IA_64_TPREL64MSB"; case 151: return "R_IA_64_TPREL64LSB"; case 154: return "R_IA_64_LTOFF_TPREL22"; case 166: return "R_IA_64_DTPMOD64MSB"; case 167: return "R_IA_64_DTPMOD64LSB"; case 170: return "R_IA_64_LTOFF_DTPMOD22"; case 177: return "R_IA_64_DTPREL14"; case 178: return "R_IA_64_DTPREL22"; case 179: return "R_IA_64_DTPREL64I"; case 180: return "R_IA_64_DTPREL32MSB"; case 181: return "R_IA_64_DTPREL32LSB"; case 182: return "R_IA_64_DTPREL64MSB"; case 183: return "R_IA_64_DTPREL64LSB"; case 186: return "R_IA_64_LTOFF_DTPREL22"; default: return ""; } case EM_MIPS: switch(type) { case 0: return "R_MIPS_NONE"; case 1: return "R_MIPS_16"; case 2: return "R_MIPS_32"; case 3: return "R_MIPS_REL32"; case 4: return "R_MIPS_26"; case 5: return "R_MIPS_HI16"; case 6: return "R_MIPS_LO16"; case 7: return "R_MIPS_GPREL16"; case 8: return "R_MIPS_LITERAL"; case 9: return "R_MIPS_GOT16"; case 10: return "R_MIPS_PC16"; case 11: return "R_MIPS_CALL16"; case 12: return "R_MIPS_GPREL32"; case 21: return "R_MIPS_GOTHI16"; case 22: return "R_MIPS_GOTLO16"; case 30: return "R_MIPS_CALLHI16"; case 31: return "R_MIPS_CALLLO16"; default: return ""; } case EM_PPC: switch(type) { case 0: return "R_PPC_NONE"; case 1: return "R_PPC_ADDR32"; case 2: return "R_PPC_ADDR24"; case 3: return "R_PPC_ADDR16"; case 4: return "R_PPC_ADDR16_LO"; case 5: return "R_PPC_ADDR16_HI"; case 6: return "R_PPC_ADDR16_HA"; case 7: return "R_PPC_ADDR14"; case 8: return "R_PPC_ADDR14_BRTAKEN"; case 9: return "R_PPC_ADDR14_BRNTAKEN"; case 10: return "R_PPC_REL24"; case 11: return "R_PPC_REL14"; case 12: return "R_PPC_REL14_BRTAKEN"; case 13: return "R_PPC_REL14_BRNTAKEN"; case 14: return "R_PPC_GOT16"; case 15: return "R_PPC_GOT16_LO"; case 16: return "R_PPC_GOT16_HI"; case 17: return "R_PPC_GOT16_HA"; case 18: return "R_PPC_PLTREL24"; case 19: return "R_PPC_COPY"; case 20: return "R_PPC_GLOB_DAT"; case 21: return "R_PPC_JMP_SLOT"; case 22: return "R_PPC_RELATIVE"; case 23: return "R_PPC_LOCAL24PC"; case 24: return "R_PPC_UADDR32"; case 25: return "R_PPC_UADDR16"; case 26: return "R_PPC_REL32"; case 27: return "R_PPC_PLT32"; case 28: return "R_PPC_PLTREL32"; case 29: return "R_PPC_PLT16_LO"; case 30: return "R_PPC_PLT16_HI"; case 31: return "R_PPC_PLT16_HA"; case 32: return "R_PPC_SDAREL16"; case 33: return "R_PPC_SECTOFF"; case 34: return "R_PPC_SECTOFF_LO"; case 35: return "R_PPC_SECTOFF_HI"; case 36: return "R_PPC_SECTOFF_HA"; case 67: return "R_PPC_TLS"; case 68: return "R_PPC_DTPMOD32"; case 69: return "R_PPC_TPREL16"; case 70: return "R_PPC_TPREL16_LO"; case 71: return "R_PPC_TPREL16_HI"; case 72: return "R_PPC_TPREL16_HA"; case 73: return "R_PPC_TPREL32"; case 74: return "R_PPC_DTPREL16"; case 75: return "R_PPC_DTPREL16_LO"; case 76: return "R_PPC_DTPREL16_HI"; case 77: return "R_PPC_DTPREL16_HA"; case 78: return "R_PPC_DTPREL32"; case 79: return "R_PPC_GOT_TLSGD16"; case 80: return "R_PPC_GOT_TLSGD16_LO"; case 81: return "R_PPC_GOT_TLSGD16_HI"; case 82: return "R_PPC_GOT_TLSGD16_HA"; case 83: return "R_PPC_GOT_TLSLD16"; case 84: return "R_PPC_GOT_TLSLD16_LO"; case 85: return "R_PPC_GOT_TLSLD16_HI"; case 86: return "R_PPC_GOT_TLSLD16_HA"; case 87: return "R_PPC_GOT_TPREL16"; case 88: return "R_PPC_GOT_TPREL16_LO"; case 89: return "R_PPC_GOT_TPREL16_HI"; case 90: return "R_PPC_GOT_TPREL16_HA"; case 101: return "R_PPC_EMB_NADDR32"; case 102: return "R_PPC_EMB_NADDR16"; case 103: return "R_PPC_EMB_NADDR16_LO"; case 104: return "R_PPC_EMB_NADDR16_HI"; case 105: return "R_PPC_EMB_NADDR16_HA"; case 106: return "R_PPC_EMB_SDAI16"; case 107: return "R_PPC_EMB_SDA2I16"; case 108: return "R_PPC_EMB_SDA2REL"; case 109: return "R_PPC_EMB_SDA21"; case 110: return "R_PPC_EMB_MRKREF"; case 111: return "R_PPC_EMB_RELSEC16"; case 112: return "R_PPC_EMB_RELST_LO"; case 113: return "R_PPC_EMB_RELST_HI"; case 114: return "R_PPC_EMB_RELST_HA"; case 115: return "R_PPC_EMB_BIT_FLD"; case 116: return "R_PPC_EMB_RELSDA"; default: return ""; } case EM_SPARC: case EM_SPARCV9: switch(type) { case 0: return "R_SPARC_NONE"; case 1: return "R_SPARC_8"; case 2: return "R_SPARC_16"; case 3: return "R_SPARC_32"; case 4: return "R_SPARC_DISP8"; case 5: return "R_SPARC_DISP16"; case 6: return "R_SPARC_DISP32"; case 7: return "R_SPARC_WDISP30"; case 8: return "R_SPARC_WDISP22"; case 9: return "R_SPARC_HI22"; case 10: return "R_SPARC_22"; case 11: return "R_SPARC_13"; case 12: return "R_SPARC_LO10"; case 13: return "R_SPARC_GOT10"; case 14: return "R_SPARC_GOT13"; case 15: return "R_SPARC_GOT22"; case 16: return "R_SPARC_PC10"; case 17: return "R_SPARC_PC22"; case 18: return "R_SPARC_WPLT30"; case 19: return "R_SPARC_COPY"; case 20: return "R_SPARC_GLOB_DAT"; case 21: return "R_SPARC_JMP_SLOT"; case 22: return "R_SPARC_RELATIVE"; case 23: return "R_SPARC_UA32"; case 24: return "R_SPARC_PLT32"; case 25: return "R_SPARC_HIPLT22"; case 26: return "R_SPARC_LOPLT10"; case 27: return "R_SPARC_PCPLT32"; case 28: return "R_SPARC_PCPLT22"; case 29: return "R_SPARC_PCPLT10"; case 30: return "R_SPARC_10"; case 31: return "R_SPARC_11"; case 32: return "R_SPARC_64"; case 33: return "R_SPARC_OLO10"; case 34: return "R_SPARC_HH22"; case 35: return "R_SPARC_HM10"; case 36: return "R_SPARC_LM22"; case 37: return "R_SPARC_PC_HH22"; case 38: return "R_SPARC_PC_HM10"; case 39: return "R_SPARC_PC_LM22"; case 40: return "R_SPARC_WDISP16"; case 41: return "R_SPARC_WDISP19"; case 42: return "R_SPARC_GLOB_JMP"; case 43: return "R_SPARC_7"; case 44: return "R_SPARC_5"; case 45: return "R_SPARC_6"; case 46: return "R_SPARC_DISP64"; case 47: return "R_SPARC_PLT64"; case 48: return "R_SPARC_HIX22"; case 49: return "R_SPARC_LOX10"; case 50: return "R_SPARC_H44"; case 51: return "R_SPARC_M44"; case 52: return "R_SPARC_L44"; case 53: return "R_SPARC_REGISTER"; case 54: return "R_SPARC_UA64"; case 55: return "R_SPARC_UA16"; case 56: return "R_SPARC_TLS_GD_HI22"; case 57: return "R_SPARC_TLS_GD_LO10"; case 58: return "R_SPARC_TLS_GD_ADD"; case 59: return "R_SPARC_TLS_GD_CALL"; case 60: return "R_SPARC_TLS_LDM_HI22"; case 61: return "R_SPARC_TLS_LDM_LO10"; case 62: return "R_SPARC_TLS_LDM_ADD"; case 63: return "R_SPARC_TLS_LDM_CALL"; case 64: return "R_SPARC_TLS_LDO_HIX22"; case 65: return "R_SPARC_TLS_LDO_LOX10"; case 66: return "R_SPARC_TLS_LDO_ADD"; case 67: return "R_SPARC_TLS_IE_HI22"; case 68: return "R_SPARC_TLS_IE_LO10"; case 69: return "R_SPARC_TLS_IE_LD"; case 70: return "R_SPARC_TLS_IE_LDX"; case 71: return "R_SPARC_TLS_IE_ADD"; case 72: return "R_SPARC_TLS_LE_HIX22"; case 73: return "R_SPARC_TLS_LE_LOX10"; case 74: return "R_SPARC_TLS_DTPMOD32"; case 75: return "R_SPARC_TLS_DTPMOD64"; case 76: return "R_SPARC_TLS_DTPOFF32"; case 77: return "R_SPARC_TLS_DTPOFF64"; case 78: return "R_SPARC_TLS_TPOFF32"; case 79: return "R_SPARC_TLS_TPOFF64"; default: return ""; } case EM_X86_64: switch(type) { case 0: return "R_X86_64_NONE"; case 1: return "R_X86_64_64"; case 2: return "R_X86_64_PC32"; case 3: return "R_X86_64_GOT32"; case 4: return "R_X86_64_PLT32"; case 5: return "R_X86_64_COPY"; case 6: return "R_X86_64_GLOB_DAT"; case 7: return "R_X86_64_JMP_SLOT"; case 8: return "R_X86_64_RELATIVE"; case 9: return "R_X86_64_GOTPCREL"; case 10: return "R_X86_64_32"; case 11: return "R_X86_64_32S"; case 12: return "R_X86_64_16"; case 13: return "R_X86_64_PC16"; case 14: return "R_X86_64_8"; case 15: return "R_X86_64_PC8"; case 16: return "R_X86_64_DTPMOD64"; case 17: return "R_X86_64_DTPOFF64"; case 18: return "R_X86_64_TPOFF64"; case 19: return "R_X86_64_TLSGD"; case 20: return "R_X86_64_TLSLD"; case 21: return "R_X86_64_DTPOFF32"; case 22: return "R_X86_64_GOTTPOFF"; case 23: return "R_X86_64_TPOFF32"; default: return ""; } default: return ""; } } static const char * note_type(unsigned int osabi, unsigned int et, unsigned int nt) { static char s_nt[32]; if (et == ET_CORE) { switch (nt) { case NT_PRSTATUS: return "NT_PRSTATUS (Process status)"; case NT_FPREGSET: return "NT_FPREGSET (Floating point information)"; case NT_PRPSINFO: return "NT_PRPSINFO (Process information)"; case NT_AUXV: return "NT_AUXV (Auxiliary vector)"; case NT_PRXFPREG: return "NT_PRXFPREG (Linux user_xfpregs structure)"; case NT_PSTATUS: return "NT_PSTATUS (Linux process status)"; case NT_FPREGS: return "NT_FPREGS (Linux floating point regset)"; case NT_PSINFO: return "NT_PSINFO (Linux process information)"; case NT_LWPSTATUS: return "NT_LWPSTATUS (Linux lwpstatus_t type)"; case NT_LWPSINFO: return "NT_LWPSINFO (Linux lwpinfo_t type)"; default: snprintf(s_nt, sizeof(s_nt), "", nt); return (s_nt); } } else { switch (nt) { case NT_ABI_TAG: switch (osabi) { case ELFOSABI_FREEBSD: return "NT_FREEBSD_ABI_TAG"; case ELFOSABI_NETBSD: return "NT_NETBSD_IDENT"; case ELFOSABI_OPENBSD: return "NT_OPENBSD_IDENT"; default: return "NT_GNU_ABI_TAG"; } case NT_GNU_HWCAP: return "NT_GNU_HWCAP (Hardware capabilities)"; case NT_GNU_BUILD_ID: return "NT_GNU_BUILD_ID (Build id set by ld(1))"; case NT_GNU_GOLD_VERSION: return "NT_GNU_GOLD_VERSION (GNU gold version)"; default: snprintf(s_nt, sizeof(s_nt), "", nt); return (s_nt); } } } static struct { const char *name; int value; } l_flag[] = { {"EXACT_MATCH", LL_EXACT_MATCH}, {"IGNORE_INT_VER", LL_IGNORE_INT_VER}, {"REQUIRE_MINOR", LL_REQUIRE_MINOR}, {"EXPORTS", LL_EXPORTS}, {"DELAY_LOAD", LL_DELAY_LOAD}, {"DELTA", LL_DELTA}, {NULL, 0} }; static struct mips_option mips_exceptions_option[] = { {OEX_PAGE0, "PAGE0"}, {OEX_SMM, "SMM"}, {OEX_PRECISEFP, "PRECISEFP"}, {OEX_DISMISS, "DISMISS"}, {0, NULL} }; static struct mips_option mips_pad_option[] = { {OPAD_PREFIX, "PREFIX"}, {OPAD_POSTFIX, "POSTFIX"}, {OPAD_SYMBOL, "SYMBOL"}, {0, NULL} }; static struct mips_option mips_hwpatch_option[] = { {OHW_R4KEOP, "R4KEOP"}, {OHW_R8KPFETCH, "R8KPFETCH"}, {OHW_R5KEOP, "R5KEOP"}, {OHW_R5KCVTL, "R5KCVTL"}, {0, NULL} }; static struct mips_option mips_hwa_option[] = { {OHWA0_R4KEOP_CHECKED, "R4KEOP_CHECKED"}, {OHWA0_R4KEOP_CLEAN, "R4KEOP_CLEAN"}, {0, NULL} }; static struct mips_option mips_hwo_option[] = { {OHWO0_FIXADE, "FIXADE"}, {0, NULL} }; static const char * option_kind(uint8_t kind) { static char s_kind[32]; switch (kind) { case ODK_NULL: return "NULL"; case ODK_REGINFO: return "REGINFO"; case ODK_EXCEPTIONS: return "EXCEPTIONS"; case ODK_PAD: return "PAD"; case ODK_HWPATCH: return "HWPATCH"; case ODK_FILL: return "FILL"; case ODK_TAGS: return "TAGS"; case ODK_HWAND: return "HWAND"; case ODK_HWOR: return "HWOR"; case ODK_GP_GROUP: return "GP_GROUP"; case ODK_IDENT: return "IDENT"; default: snprintf(s_kind, sizeof(s_kind), "", kind); return (s_kind); } } static const char * top_tag(unsigned int tag) { static char s_top_tag[32]; switch (tag) { case 1: return "File Attributes"; case 2: return "Section Attributes"; case 3: return "Symbol Attributes"; default: snprintf(s_top_tag, sizeof(s_top_tag), "Unknown tag: %u", tag); return (s_top_tag); } } static const char * aeabi_cpu_arch(uint64_t arch) { static char s_cpu_arch[32]; switch (arch) { case 0: return "Pre-V4"; case 1: return "ARM v4"; case 2: return "ARM v4T"; case 3: return "ARM v5T"; case 4: return "ARM v5TE"; case 5: return "ARM v5TEJ"; case 6: return "ARM v6"; case 7: return "ARM v6KZ"; case 8: return "ARM v6T2"; case 9: return "ARM v6K"; case 10: return "ARM v7"; case 11: return "ARM v6-M"; case 12: return "ARM v6S-M"; case 13: return "ARM v7E-M"; default: snprintf(s_cpu_arch, sizeof(s_cpu_arch), "Unknown (%ju)", (uintmax_t) arch); return (s_cpu_arch); } } static const char * aeabi_cpu_arch_profile(uint64_t pf) { static char s_arch_profile[32]; switch (pf) { case 0: return "Not applicable"; case 0x41: /* 'A' */ return "Application Profile"; case 0x52: /* 'R' */ return "Real-Time Profile"; case 0x4D: /* 'M' */ return "Microcontroller Profile"; case 0x53: /* 'S' */ return "Application or Real-Time Profile"; default: snprintf(s_arch_profile, sizeof(s_arch_profile), "Unknown (%ju)\n", (uintmax_t) pf); return (s_arch_profile); } } static const char * aeabi_arm_isa(uint64_t ai) { static char s_ai[32]; switch (ai) { case 0: return "No"; case 1: return "Yes"; default: snprintf(s_ai, sizeof(s_ai), "Unknown (%ju)\n", (uintmax_t) ai); return (s_ai); } } static const char * aeabi_thumb_isa(uint64_t ti) { static char s_ti[32]; switch (ti) { case 0: return "No"; case 1: return "16-bit Thumb"; case 2: return "32-bit Thumb"; default: snprintf(s_ti, sizeof(s_ti), "Unknown (%ju)\n", (uintmax_t) ti); return (s_ti); } } static const char * aeabi_fp_arch(uint64_t fp) { static char s_fp_arch[32]; switch (fp) { case 0: return "No"; case 1: return "VFPv1"; case 2: return "VFPv2"; case 3: return "VFPv3"; case 4: return "VFPv3-D16"; case 5: return "VFPv4"; case 6: return "VFPv4-D16"; default: snprintf(s_fp_arch, sizeof(s_fp_arch), "Unknown (%ju)", (uintmax_t) fp); return (s_fp_arch); } } static const char * aeabi_wmmx_arch(uint64_t wmmx) { static char s_wmmx[32]; switch (wmmx) { case 0: return "No"; case 1: return "WMMXv1"; case 2: return "WMMXv2"; default: snprintf(s_wmmx, sizeof(s_wmmx), "Unknown (%ju)", (uintmax_t) wmmx); return (s_wmmx); } } static const char * aeabi_adv_simd_arch(uint64_t simd) { static char s_simd[32]; switch (simd) { case 0: return "No"; case 1: return "NEONv1"; case 2: return "NEONv2"; default: snprintf(s_simd, sizeof(s_simd), "Unknown (%ju)", (uintmax_t) simd); return (s_simd); } } static const char * aeabi_pcs_config(uint64_t pcs) { static char s_pcs[32]; switch (pcs) { case 0: return "None"; case 1: return "Bare platform"; case 2: return "Linux"; case 3: return "Linux DSO"; case 4: return "Palm OS 2004"; case 5: return "Palm OS (future)"; case 6: return "Symbian OS 2004"; case 7: return "Symbian OS (future)"; default: snprintf(s_pcs, sizeof(s_pcs), "Unknown (%ju)", (uintmax_t) pcs); return (s_pcs); } } static const char * aeabi_pcs_r9(uint64_t r9) { static char s_r9[32]; switch (r9) { case 0: return "V6"; case 1: return "SB"; case 2: return "TLS pointer"; case 3: return "Unused"; default: snprintf(s_r9, sizeof(s_r9), "Unknown (%ju)", (uintmax_t) r9); return (s_r9); } } static const char * aeabi_pcs_rw(uint64_t rw) { static char s_rw[32]; switch (rw) { case 0: return "Absolute"; case 1: return "PC-relative"; case 2: return "SB-relative"; case 3: return "None"; default: snprintf(s_rw, sizeof(s_rw), "Unknown (%ju)", (uintmax_t) rw); return (s_rw); } } static const char * aeabi_pcs_ro(uint64_t ro) { static char s_ro[32]; switch (ro) { case 0: return "Absolute"; case 1: return "PC-relative"; case 2: return "None"; default: snprintf(s_ro, sizeof(s_ro), "Unknown (%ju)", (uintmax_t) ro); return (s_ro); } } static const char * aeabi_pcs_got(uint64_t got) { static char s_got[32]; switch (got) { case 0: return "None"; case 1: return "direct"; case 2: return "indirect via GOT"; default: snprintf(s_got, sizeof(s_got), "Unknown (%ju)", (uintmax_t) got); return (s_got); } } static const char * aeabi_pcs_wchar_t(uint64_t wt) { static char s_wt[32]; switch (wt) { case 0: return "None"; case 2: return "wchar_t size 2"; case 4: return "wchar_t size 4"; default: snprintf(s_wt, sizeof(s_wt), "Unknown (%ju)", (uintmax_t) wt); return (s_wt); } } static const char * aeabi_enum_size(uint64_t es) { static char s_es[32]; switch (es) { case 0: return "None"; case 1: return "smallest"; case 2: return "32-bit"; case 3: return "visible 32-bit"; default: snprintf(s_es, sizeof(s_es), "Unknown (%ju)", (uintmax_t) es); return (s_es); } } static const char * aeabi_align_needed(uint64_t an) { static char s_align_n[64]; switch (an) { case 0: return "No"; case 1: return "8-byte align"; case 2: return "4-byte align"; case 3: return "Reserved"; default: if (an >= 4 && an <= 12) snprintf(s_align_n, sizeof(s_align_n), "8-byte align" " and up to 2^%ju-byte extended align", (uintmax_t) an); else snprintf(s_align_n, sizeof(s_align_n), "Unknown (%ju)", (uintmax_t) an); return (s_align_n); } } static const char * aeabi_align_preserved(uint64_t ap) { static char s_align_p[128]; switch (ap) { case 0: return "No"; case 1: return "8-byte align"; case 2: return "8-byte align and SP % 8 == 0"; case 3: return "Reserved"; default: if (ap >= 4 && ap <= 12) snprintf(s_align_p, sizeof(s_align_p), "8-byte align" " and SP %% 8 == 0 and up to 2^%ju-byte extended" " align", (uintmax_t) ap); else snprintf(s_align_p, sizeof(s_align_p), "Unknown (%ju)", (uintmax_t) ap); return (s_align_p); } } static const char * aeabi_fp_rounding(uint64_t fr) { static char s_fp_r[32]; switch (fr) { case 0: return "Unused"; case 1: return "Needed"; default: snprintf(s_fp_r, sizeof(s_fp_r), "Unknown (%ju)", (uintmax_t) fr); return (s_fp_r); } } static const char * aeabi_fp_denormal(uint64_t fd) { static char s_fp_d[32]; switch (fd) { case 0: return "Unused"; case 1: return "Needed"; case 2: return "Sign Only"; default: snprintf(s_fp_d, sizeof(s_fp_d), "Unknown (%ju)", (uintmax_t) fd); return (s_fp_d); } } static const char * aeabi_fp_exceptions(uint64_t fe) { static char s_fp_e[32]; switch (fe) { case 0: return "Unused"; case 1: return "Needed"; default: snprintf(s_fp_e, sizeof(s_fp_e), "Unknown (%ju)", (uintmax_t) fe); return (s_fp_e); } } static const char * aeabi_fp_user_exceptions(uint64_t fu) { static char s_fp_u[32]; switch (fu) { case 0: return "Unused"; case 1: return "Needed"; default: snprintf(s_fp_u, sizeof(s_fp_u), "Unknown (%ju)", (uintmax_t) fu); return (s_fp_u); } } static const char * aeabi_fp_number_model(uint64_t fn) { static char s_fp_n[32]; switch (fn) { case 0: return "Unused"; case 1: return "IEEE 754 normal"; case 2: return "RTABI"; case 3: return "IEEE 754"; default: snprintf(s_fp_n, sizeof(s_fp_n), "Unknown (%ju)", (uintmax_t) fn); return (s_fp_n); } } static const char * aeabi_fp_16bit_format(uint64_t fp16) { static char s_fp_16[64]; switch (fp16) { case 0: return "None"; case 1: return "IEEE 754"; case 2: return "VFPv3/Advanced SIMD (alternative format)"; default: snprintf(s_fp_16, sizeof(s_fp_16), "Unknown (%ju)", (uintmax_t) fp16); return (s_fp_16); } } static const char * aeabi_mpext(uint64_t mp) { static char s_mp[32]; switch (mp) { case 0: return "Not allowed"; case 1: return "Allowed"; default: snprintf(s_mp, sizeof(s_mp), "Unknown (%ju)", (uintmax_t) mp); return (s_mp); } } static const char * aeabi_div(uint64_t du) { static char s_du[32]; switch (du) { case 0: return "Yes (V7-R/V7-M)"; case 1: return "No"; case 2: return "Yes (V7-A)"; default: snprintf(s_du, sizeof(s_du), "Unknown (%ju)", (uintmax_t) du); return (s_du); } } static const char * aeabi_t2ee(uint64_t t2ee) { static char s_t2ee[32]; switch (t2ee) { case 0: return "Not allowed"; case 1: return "Allowed"; default: snprintf(s_t2ee, sizeof(s_t2ee), "Unknown(%ju)", (uintmax_t) t2ee); return (s_t2ee); } } static const char * aeabi_hardfp(uint64_t hfp) { static char s_hfp[32]; switch (hfp) { case 0: return "Tag_FP_arch"; case 1: return "only SP"; case 2: return "only DP"; case 3: return "both SP and DP"; default: snprintf(s_hfp, sizeof(s_hfp), "Unknown (%ju)", (uintmax_t) hfp); return (s_hfp); } } static const char * aeabi_vfp_args(uint64_t va) { static char s_va[32]; switch (va) { case 0: return "AAPCS (base variant)"; case 1: return "AAPCS (VFP variant)"; case 2: return "toolchain-specific"; default: snprintf(s_va, sizeof(s_va), "Unknown (%ju)", (uintmax_t) va); return (s_va); } } static const char * aeabi_wmmx_args(uint64_t wa) { static char s_wa[32]; switch (wa) { case 0: return "AAPCS (base variant)"; case 1: return "Intel WMMX"; case 2: return "toolchain-specific"; default: snprintf(s_wa, sizeof(s_wa), "Unknown(%ju)", (uintmax_t) wa); return (s_wa); } } static const char * aeabi_unaligned_access(uint64_t ua) { static char s_ua[32]; switch (ua) { case 0: return "Not allowed"; case 1: return "Allowed"; default: snprintf(s_ua, sizeof(s_ua), "Unknown(%ju)", (uintmax_t) ua); return (s_ua); } } static const char * aeabi_fp_hpext(uint64_t fh) { static char s_fh[32]; switch (fh) { case 0: return "Not allowed"; case 1: return "Allowed"; default: snprintf(s_fh, sizeof(s_fh), "Unknown(%ju)", (uintmax_t) fh); return (s_fh); } } static const char * aeabi_optm_goal(uint64_t og) { static char s_og[32]; switch (og) { case 0: return "None"; case 1: return "Speed"; case 2: return "Speed aggressive"; case 3: return "Space"; case 4: return "Space aggressive"; case 5: return "Debugging"; case 6: return "Best Debugging"; default: snprintf(s_og, sizeof(s_og), "Unknown(%ju)", (uintmax_t) og); return (s_og); } } static const char * aeabi_fp_optm_goal(uint64_t fog) { static char s_fog[32]; switch (fog) { case 0: return "None"; case 1: return "Speed"; case 2: return "Speed aggressive"; case 3: return "Space"; case 4: return "Space aggressive"; case 5: return "Accurary"; case 6: return "Best Accurary"; default: snprintf(s_fog, sizeof(s_fog), "Unknown(%ju)", (uintmax_t) fog); return (s_fog); } } static const char * aeabi_virtual(uint64_t vt) { static char s_virtual[64]; switch (vt) { case 0: return "No"; case 1: return "TrustZone"; case 2: return "Virtualization extension"; case 3: return "TrustZone and virtualization extension"; default: snprintf(s_virtual, sizeof(s_virtual), "Unknown(%ju)", (uintmax_t) vt); return (s_virtual); } } static struct { uint64_t tag; const char *s_tag; const char *(*get_desc)(uint64_t val); } aeabi_tags[] = { {4, "Tag_CPU_raw_name", NULL}, {5, "Tag_CPU_name", NULL}, {6, "Tag_CPU_arch", aeabi_cpu_arch}, {7, "Tag_CPU_arch_profile", aeabi_cpu_arch_profile}, {8, "Tag_ARM_ISA_use", aeabi_arm_isa}, {9, "Tag_THUMB_ISA_use", aeabi_thumb_isa}, {10, "Tag_FP_arch", aeabi_fp_arch}, {11, "Tag_WMMX_arch", aeabi_wmmx_arch}, {12, "Tag_Advanced_SIMD_arch", aeabi_adv_simd_arch}, {13, "Tag_PCS_config", aeabi_pcs_config}, {14, "Tag_ABI_PCS_R9_use", aeabi_pcs_r9}, {15, "Tag_ABI_PCS_RW_data", aeabi_pcs_rw}, {16, "Tag_ABI_PCS_RO_data", aeabi_pcs_ro}, {17, "Tag_ABI_PCS_GOT_use", aeabi_pcs_got}, {18, "Tag_ABI_PCS_wchar_t", aeabi_pcs_wchar_t}, {19, "Tag_ABI_FP_rounding", aeabi_fp_rounding}, {20, "Tag_ABI_FP_denormal", aeabi_fp_denormal}, {21, "Tag_ABI_FP_exceptions", aeabi_fp_exceptions}, {22, "Tag_ABI_FP_user_exceptions", aeabi_fp_user_exceptions}, {23, "Tag_ABI_FP_number_model", aeabi_fp_number_model}, {24, "Tag_ABI_align_needed", aeabi_align_needed}, {25, "Tag_ABI_align_preserved", aeabi_align_preserved}, {26, "Tag_ABI_enum_size", aeabi_enum_size}, {27, "Tag_ABI_HardFP_use", aeabi_hardfp}, {28, "Tag_ABI_VFP_args", aeabi_vfp_args}, {29, "Tag_ABI_WMMX_args", aeabi_wmmx_args}, {30, "Tag_ABI_optimization_goals", aeabi_optm_goal}, {31, "Tag_ABI_FP_optimization_goals", aeabi_fp_optm_goal}, {32, "Tag_compatibility", NULL}, {34, "Tag_CPU_unaligned_access", aeabi_unaligned_access}, {36, "Tag_FP_HP_extension", aeabi_fp_hpext}, {38, "Tag_ABI_FP_16bit_format", aeabi_fp_16bit_format}, {42, "Tag_MPextension_use", aeabi_mpext}, {44, "Tag_DIV_use", aeabi_div}, {64, "Tag_nodefaults", NULL}, {65, "Tag_also_compatible_with", NULL}, {66, "Tag_T2EE_use", aeabi_t2ee}, {67, "Tag_conformance", NULL}, {68, "Tag_Virtualization_use", aeabi_virtual}, {70, "Tag_MPextension_use", aeabi_mpext}, }; static const char * mips_abi_fp(uint64_t fp) { static char s_mips_abi_fp[64]; switch (fp) { case 0: return "N/A"; case 1: return "Hard float (double precision)"; case 2: return "Hard float (single precision)"; case 3: return "Soft float"; case 4: return "64-bit float (-mips32r2 -mfp64)"; default: snprintf(s_mips_abi_fp, sizeof(s_mips_abi_fp), "Unknown(%ju)", (uintmax_t) fp); return (s_mips_abi_fp); } } static const char * ppc_abi_fp(uint64_t fp) { static char s_ppc_abi_fp[64]; switch (fp) { case 0: return "N/A"; case 1: return "Hard float (double precision)"; case 2: return "Soft float"; case 3: return "Hard float (single precision)"; default: snprintf(s_ppc_abi_fp, sizeof(s_ppc_abi_fp), "Unknown(%ju)", (uintmax_t) fp); return (s_ppc_abi_fp); } } static const char * ppc_abi_vector(uint64_t vec) { static char s_vec[64]; switch (vec) { case 0: return "N/A"; case 1: return "Generic purpose registers"; case 2: return "AltiVec registers"; case 3: return "SPE registers"; default: snprintf(s_vec, sizeof(s_vec), "Unknown(%ju)", (uintmax_t) vec); return (s_vec); } } +static const char * +dwarf_reg(unsigned int mach, unsigned int reg) +{ + + switch (mach) { + case EM_386: + switch (reg) { + case 0: return "eax"; + case 1: return "ecx"; + case 2: return "edx"; + case 3: return "ebx"; + case 4: return "esp"; + case 5: return "ebp"; + case 6: return "esi"; + case 7: return "edi"; + case 8: return "eip"; + case 9: return "eflags"; + case 11: return "st0"; + case 12: return "st1"; + case 13: return "st2"; + case 14: return "st3"; + case 15: return "st4"; + case 16: return "st5"; + case 17: return "st6"; + case 18: return "st7"; + case 21: return "xmm0"; + case 22: return "xmm1"; + case 23: return "xmm2"; + case 24: return "xmm3"; + case 25: return "xmm4"; + case 26: return "xmm5"; + case 27: return "xmm6"; + case 28: return "xmm7"; + case 29: return "mm0"; + case 30: return "mm1"; + case 31: return "mm2"; + case 32: return "mm3"; + case 33: return "mm4"; + case 34: return "mm5"; + case 35: return "mm6"; + case 36: return "mm7"; + case 37: return "fcw"; + case 38: return "fsw"; + case 39: return "mxcsr"; + case 40: return "es"; + case 41: return "cs"; + case 42: return "ss"; + case 43: return "ds"; + case 44: return "fs"; + case 45: return "gs"; + case 48: return "tr"; + case 49: return "ldtr"; + default: return (NULL); + } + case EM_X86_64: + switch (reg) { + case 0: return "rax"; + case 1: return "rdx"; + case 2: return "rcx"; + case 3: return "rbx"; + case 4: return "rsi"; + case 5: return "rdi"; + case 6: return "rbp"; + case 7: return "rsp"; + case 16: return "rip"; + case 17: return "xmm0"; + case 18: return "xmm1"; + case 19: return "xmm2"; + case 20: return "xmm3"; + case 21: return "xmm4"; + case 22: return "xmm5"; + case 23: return "xmm6"; + case 24: return "xmm7"; + case 25: return "xmm8"; + case 26: return "xmm9"; + case 27: return "xmm10"; + case 28: return "xmm11"; + case 29: return "xmm12"; + case 30: return "xmm13"; + case 31: return "xmm14"; + case 32: return "xmm15"; + case 33: return "st0"; + case 34: return "st1"; + case 35: return "st2"; + case 36: return "st3"; + case 37: return "st4"; + case 38: return "st5"; + case 39: return "st6"; + case 40: return "st7"; + case 41: return "mm0"; + case 42: return "mm1"; + case 43: return "mm2"; + case 44: return "mm3"; + case 45: return "mm4"; + case 46: return "mm5"; + case 47: return "mm6"; + case 48: return "mm7"; + case 49: return "rflags"; + case 50: return "es"; + case 51: return "cs"; + case 52: return "ss"; + case 53: return "ds"; + case 54: return "fs"; + case 55: return "gs"; + case 58: return "fs.base"; + case 59: return "gs.base"; + case 62: return "tr"; + case 63: return "ldtr"; + case 64: return "mxcsr"; + case 65: return "fcw"; + case 66: return "fsw"; + default: return (NULL); + } + default: + return (NULL); + } +} + static void dump_ehdr(struct readelf *re) { size_t shnum, shstrndx; int i; printf("ELF Header:\n"); /* e_ident[]. */ printf(" Magic: "); for (i = 0; i < EI_NIDENT; i++) printf("%.2x ", re->ehdr.e_ident[i]); putchar('\n'); /* EI_CLASS. */ printf("%-37s%s\n", " Class:", elf_class(re->ehdr.e_ident[EI_CLASS])); /* EI_DATA. */ printf("%-37s%s\n", " Data:", elf_endian(re->ehdr.e_ident[EI_DATA])); /* EI_VERSION. */ printf("%-37s%d %s\n", " Version:", re->ehdr.e_ident[EI_VERSION], elf_ver(re->ehdr.e_ident[EI_VERSION])); /* EI_OSABI. */ printf("%-37s%s\n", " OS/ABI:", elf_osabi(re->ehdr.e_ident[EI_OSABI])); /* EI_ABIVERSION. */ printf("%-37s%d\n", " ABI Version:", re->ehdr.e_ident[EI_ABIVERSION]); /* e_type. */ printf("%-37s%s\n", " Type:", elf_type(re->ehdr.e_type)); /* e_machine. */ printf("%-37s%s\n", " Machine:", elf_machine(re->ehdr.e_machine)); /* e_version. */ printf("%-37s%#x\n", " Version:", re->ehdr.e_version); /* e_entry. */ printf("%-37s%#jx\n", " Entry point address:", (uintmax_t)re->ehdr.e_entry); /* e_phoff. */ printf("%-37s%ju (bytes into file)\n", " Start of program headers:", (uintmax_t)re->ehdr.e_phoff); /* e_shoff. */ printf("%-37s%ju (bytes into file)\n", " Start of section headers:", (uintmax_t)re->ehdr.e_shoff); /* e_flags. */ printf("%-37s%#x", " Flags:", re->ehdr.e_flags); dump_eflags(re, re->ehdr.e_flags); putchar('\n'); /* e_ehsize. */ printf("%-37s%u (bytes)\n", " Size of this header:", re->ehdr.e_ehsize); /* e_phentsize. */ printf("%-37s%u (bytes)\n", " Size of program headers:", re->ehdr.e_phentsize); /* e_phnum. */ printf("%-37s%u\n", " Number of program headers:", re->ehdr.e_phnum); /* e_shentsize. */ printf("%-37s%u (bytes)\n", " Size of section headers:", re->ehdr.e_shentsize); /* e_shnum. */ printf("%-37s%u", " Number of section headers:", re->ehdr.e_shnum); if (re->ehdr.e_shnum == SHN_UNDEF) { /* Extended section numbering is in use. */ if (elf_getshnum(re->elf, &shnum)) printf(" (%ju)", (uintmax_t)shnum); } putchar('\n'); /* e_shstrndx. */ printf("%-37s%u", " Section header string table index:", re->ehdr.e_shstrndx); if (re->ehdr.e_shstrndx == SHN_XINDEX) { /* Extended section numbering is in use. */ if (elf_getshstrndx(re->elf, &shstrndx)) printf(" (%ju)", (uintmax_t)shstrndx); } putchar('\n'); } static void dump_eflags(struct readelf *re, uint64_t e_flags) { struct eflags_desc *edesc; int arm_eabi; edesc = NULL; switch (re->ehdr.e_machine) { case EM_ARM: arm_eabi = (e_flags & EF_ARM_EABIMASK) >> 24; if (arm_eabi == 0) printf(", GNU EABI"); else if (arm_eabi <= 5) printf(", Version%d EABI", arm_eabi); edesc = arm_eflags_desc; break; case EM_MIPS: case EM_MIPS_RS3_LE: switch ((e_flags & EF_MIPS_ARCH) >> 28) { case 0: printf(", mips1"); break; case 1: printf(", mips2"); break; case 2: printf(", mips3"); break; case 3: printf(", mips4"); break; case 4: printf(", mips5"); break; case 5: printf(", mips32"); break; case 6: printf(", mips64"); break; case 7: printf(", mips32r2"); break; case 8: printf(", mips64r2"); break; default: break; } switch ((e_flags & 0x00FF0000) >> 16) { case 0x81: printf(", 3900"); break; case 0x82: printf(", 4010"); break; case 0x83: printf(", 4100"); break; case 0x85: printf(", 4650"); break; case 0x87: printf(", 4120"); break; case 0x88: printf(", 4111"); break; case 0x8a: printf(", sb1"); break; case 0x8b: printf(", octeon"); break; case 0x8c: printf(", xlr"); break; case 0x91: printf(", 5400"); break; case 0x98: printf(", 5500"); break; case 0x99: printf(", 9000"); break; case 0xa0: printf(", loongson-2e"); break; case 0xa1: printf(", loongson-2f"); break; default: break; } switch ((e_flags & 0x0000F000) >> 12) { case 1: printf(", o32"); break; case 2: printf(", o64"); break; case 3: printf(", eabi32"); break; case 4: printf(", eabi64"); break; default: break; } edesc = mips_eflags_desc; break; case EM_PPC: case EM_PPC64: edesc = powerpc_eflags_desc; break; case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: switch ((e_flags & EF_SPARCV9_MM)) { case EF_SPARCV9_TSO: printf(", tso"); break; case EF_SPARCV9_PSO: printf(", pso"); break; case EF_SPARCV9_MM: printf(", rmo"); break; default: break; } edesc = sparc_eflags_desc; break; default: break; } if (edesc != NULL) { while (edesc->desc != NULL) { if (e_flags & edesc->flag) printf(", %s", edesc->desc); edesc++; } } } static void dump_phdr(struct readelf *re) { const char *rawfile; GElf_Phdr phdr; size_t phnum; int i, j; #define PH_HDR "Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz", \ "MemSiz", "Flg", "Align" #define PH_CT phdr_type(phdr.p_type), (uintmax_t)phdr.p_offset, \ (uintmax_t)phdr.p_vaddr, (uintmax_t)phdr.p_paddr, \ (uintmax_t)phdr.p_filesz, (uintmax_t)phdr.p_memsz, \ phdr.p_flags & PF_R ? 'R' : ' ', \ phdr.p_flags & PF_W ? 'W' : ' ', \ phdr.p_flags & PF_X ? 'E' : ' ', \ (uintmax_t)phdr.p_align if (elf_getphnum(re->elf, &phnum) == 0) { warnx("elf_getphnum failed: %s", elf_errmsg(-1)); return; } if (phnum == 0) { printf("\nThere are no program headers in this file.\n"); return; } printf("\nElf file type is %s", elf_type(re->ehdr.e_type)); printf("\nEntry point 0x%jx\n", (uintmax_t)re->ehdr.e_entry); printf("There are %ju program headers, starting at offset %ju\n", (uintmax_t)phnum, (uintmax_t)re->ehdr.e_phoff); /* Dump program headers. */ printf("\nProgram Headers:\n"); if (re->ec == ELFCLASS32) printf(" %-15s%-9s%-11s%-11s%-8s%-8s%-4s%s\n", PH_HDR); else if (re->options & RE_WW) printf(" %-15s%-9s%-19s%-19s%-9s%-9s%-4s%s\n", PH_HDR); else printf(" %-15s%-19s%-19s%s\n %-19s%-20s" "%-7s%s\n", PH_HDR); for (i = 0; (size_t) i < phnum; i++) { if (gelf_getphdr(re->elf, i, &phdr) != &phdr) { warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); continue; } /* TODO: Add arch-specific segment type dump. */ if (re->ec == ELFCLASS32) printf(" %-14.14s 0x%6.6jx 0x%8.8jx 0x%8.8jx " "0x%5.5jx 0x%5.5jx %c%c%c %#jx\n", PH_CT); else if (re->options & RE_WW) printf(" %-14.14s 0x%6.6jx 0x%16.16jx 0x%16.16jx " "0x%6.6jx 0x%6.6jx %c%c%c %#jx\n", PH_CT); else printf(" %-14.14s 0x%16.16jx 0x%16.16jx 0x%16.16jx\n" " 0x%16.16jx 0x%16.16jx %c%c%c" " %#jx\n", PH_CT); if (phdr.p_type == PT_INTERP) { if ((rawfile = elf_rawfile(re->elf, NULL)) == NULL) { warnx("elf_rawfile failed: %s", elf_errmsg(-1)); continue; } printf(" [Requesting program interpreter: %s]\n", rawfile + phdr.p_offset); } } /* Dump section to segment mapping. */ if (re->shnum == 0) return; printf("\n Section to Segment mapping:\n"); printf(" Segment Sections...\n"); for (i = 0; (size_t)i < phnum; i++) { if (gelf_getphdr(re->elf, i, &phdr) != &phdr) { warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); continue; } printf(" %2.2d ", i); /* skip NULL section. */ for (j = 1; (size_t)j < re->shnum; j++) if (re->sl[j].off >= phdr.p_offset && re->sl[j].off + re->sl[j].sz <= phdr.p_offset + phdr.p_memsz) printf("%s ", re->sl[j].name); printf("\n"); } #undef PH_HDR #undef PH_CT } static char * section_flags(struct readelf *re, struct section *s) { #define BUF_SZ 256 static char buf[BUF_SZ]; int i, p, nb; p = 0; nb = re->ec == ELFCLASS32 ? 8 : 16; if (re->options & RE_T) { snprintf(buf, BUF_SZ, "[%*.*jx]: ", nb, nb, (uintmax_t)s->flags); p += nb + 4; } for (i = 0; section_flag[i].ln != NULL; i++) { if ((s->flags & section_flag[i].value) == 0) continue; if (re->options & RE_T) { snprintf(&buf[p], BUF_SZ - p, "%s, ", section_flag[i].ln); p += strlen(section_flag[i].ln) + 2; } else buf[p++] = section_flag[i].sn; } if (re->options & RE_T && p > nb + 4) p -= 2; buf[p] = '\0'; return (buf); } static void dump_shdr(struct readelf *re) { struct section *s; int i; #define S_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \ "Flg", "Lk", "Inf", "Al" #define S_HDRL "[Nr] Name", "Type", "Address", "Offset", "Size", \ "EntSize", "Flags", "Link", "Info", "Align" #define ST_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \ "Lk", "Inf", "Al", "Flags" #define ST_HDRL "[Nr] Name", "Type", "Address", "Offset", "Link", \ "Size", "EntSize", "Info", "Align", "Flags" #define S_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ (uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\ (uintmax_t)s->entsize, section_flags(re, s), \ s->link, s->info, (uintmax_t)s->align #define ST_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ (uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\ (uintmax_t)s->entsize, s->link, s->info, \ (uintmax_t)s->align, section_flags(re, s) #define ST_CTL i, s->name, section_type(re->ehdr.e_machine, s->type), \ (uintmax_t)s->addr, (uintmax_t)s->off, s->link, \ (uintmax_t)s->sz, (uintmax_t)s->entsize, s->info, \ (uintmax_t)s->align, section_flags(re, s) if (re->shnum == 0) { printf("\nThere are no sections in this file.\n"); return; } printf("There are %ju section headers, starting at offset 0x%jx:\n", (uintmax_t)re->shnum, (uintmax_t)re->ehdr.e_shoff); printf("\nSection Headers:\n"); if (re->ec == ELFCLASS32) { if (re->options & RE_T) printf(" %s\n %-16s%-9s%-7s%-7s%-5s%-3s%-4s%s\n" "%12s\n", ST_HDR); else printf(" %-23s%-16s%-9s%-7s%-7s%-3s%-4s%-3s%-4s%s\n", S_HDR); } else if (re->options & RE_WW) { if (re->options & RE_T) printf(" %s\n %-16s%-17s%-7s%-7s%-5s%-3s%-4s%s\n" "%12s\n", ST_HDR); else printf(" %-23s%-16s%-17s%-7s%-7s%-3s%-4s%-3s%-4s%s\n", S_HDR); } else { if (re->options & RE_T) printf(" %s\n %-18s%-17s%-18s%s\n %-18s" "%-17s%-18s%s\n%12s\n", ST_HDRL); else printf(" %-23s%-17s%-18s%s\n %-18s%-17s%-7s%" "-6s%-6s%s\n", S_HDRL); } for (i = 0; (size_t)i < re->shnum; i++) { s = &re->sl[i]; if (re->ec == ELFCLASS32) { if (re->options & RE_T) printf(" [%2d] %s\n %-15.15s %8.8jx" " %6.6jx %6.6jx %2.2jx %2u %3u %2ju\n" " %s\n", ST_CT); else printf(" [%2d] %-17.17s %-15.15s %8.8jx" " %6.6jx %6.6jx %2.2jx %3s %2u %3u %2ju\n", S_CT); } else if (re->options & RE_WW) { if (re->options & RE_T) printf(" [%2d] %s\n %-15.15s %16.16jx" " %6.6jx %6.6jx %2.2jx %2u %3u %2ju\n" " %s\n", ST_CT); else printf(" [%2d] %-17.17s %-15.15s %16.16jx" " %6.6jx %6.6jx %2.2jx %3s %2u %3u %2ju\n", S_CT); } else { if (re->options & RE_T) printf(" [%2d] %s\n %-15.15s %16.16jx" " %16.16jx %u\n %16.16jx %16.16jx" " %-16u %ju\n %s\n", ST_CTL); else printf(" [%2d] %-17.17s %-15.15s %16.16jx" " %8.8jx\n %16.16jx %16.16jx " "%3s %2u %3u %ju\n", S_CT); } } if ((re->options & RE_T) == 0) printf("Key to Flags:\n W (write), A (alloc)," " X (execute), M (merge), S (strings)\n" " I (info), L (link order), G (group), x (unknown)\n" " O (extra OS processing required)" " o (OS specific), p (processor specific)\n"); #undef S_HDR #undef S_HDRL #undef ST_HDR #undef ST_HDRL #undef S_CT #undef ST_CT #undef ST_CTL } static void dump_dynamic(struct readelf *re) { GElf_Dyn dyn; Elf_Data *d; struct section *s; int elferr, i, is_dynamic, j, jmax, nentries; is_dynamic = 0; for (i = 0; (size_t)i < re->shnum; i++) { s = &re->sl[i]; if (s->type != SHT_DYNAMIC) continue; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(-1)); continue; } if (d->d_size <= 0) continue; is_dynamic = 1; /* Determine the actual number of table entries. */ nentries = 0; jmax = (int) (s->sz / s->entsize); for (j = 0; j < jmax; j++) { if (gelf_getdyn(d, j, &dyn) != &dyn) { warnx("gelf_getdyn failed: %s", elf_errmsg(-1)); continue; } nentries ++; if (dyn.d_tag == DT_NULL) break; } printf("\nDynamic section at offset 0x%jx", (uintmax_t)s->off); printf(" contains %u entries:\n", nentries); if (re->ec == ELFCLASS32) printf("%5s%12s%28s\n", "Tag", "Type", "Name/Value"); else printf("%5s%20s%28s\n", "Tag", "Type", "Name/Value"); for (j = 0; j < nentries; j++) { if (gelf_getdyn(d, j, &dyn) != &dyn) continue; /* Dump dynamic entry type. */ if (re->ec == ELFCLASS32) printf(" 0x%8.8jx", (uintmax_t)dyn.d_tag); else printf(" 0x%16.16jx", (uintmax_t)dyn.d_tag); printf(" %-20s", dt_type(re->ehdr.e_machine, dyn.d_tag)); /* Dump dynamic entry value. */ dump_dyn_val(re, &dyn, s->link); } } if (!is_dynamic) printf("\nThere is no dynamic section in this file.\n"); } static char * timestamp(time_t ti) { static char ts[32]; struct tm *t; t = gmtime(&ti); snprintf(ts, sizeof(ts), "%04d-%02d-%02dT%02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); return (ts); } static const char * dyn_str(struct readelf *re, uint32_t stab, uint64_t d_val) { const char *name; if (stab == SHN_UNDEF) name = "ERROR"; else if ((name = elf_strptr(re->elf, stab, d_val)) == NULL) { (void) elf_errno(); /* clear error */ name = "ERROR"; } return (name); } static void dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab) { const char *name; switch (re->ehdr.e_machine) { case EM_MIPS: case EM_MIPS_RS3_LE: switch (dyn->d_tag) { case DT_MIPS_RLD_VERSION: case DT_MIPS_LOCAL_GOTNO: case DT_MIPS_CONFLICTNO: case DT_MIPS_LIBLISTNO: case DT_MIPS_SYMTABNO: case DT_MIPS_UNREFEXTNO: case DT_MIPS_GOTSYM: case DT_MIPS_HIPAGENO: case DT_MIPS_DELTA_CLASS_NO: case DT_MIPS_DELTA_INSTANCE_NO: case DT_MIPS_DELTA_RELOC_NO: case DT_MIPS_DELTA_SYM_NO: case DT_MIPS_DELTA_CLASSSYM_NO: case DT_MIPS_LOCALPAGE_GOTIDX: case DT_MIPS_LOCAL_GOTIDX: case DT_MIPS_HIDDEN_GOTIDX: case DT_MIPS_PROTECTED_GOTIDX: printf(" %ju\n", (uintmax_t) dyn->d_un.d_val); break; case DT_MIPS_ICHECKSUM: case DT_MIPS_FLAGS: case DT_MIPS_BASE_ADDRESS: case DT_MIPS_CONFLICT: case DT_MIPS_LIBLIST: case DT_MIPS_RLD_MAP: case DT_MIPS_DELTA_CLASS: case DT_MIPS_DELTA_INSTANCE: case DT_MIPS_DELTA_RELOC: case DT_MIPS_DELTA_SYM: case DT_MIPS_DELTA_CLASSSYM: case DT_MIPS_CXX_FLAGS: case DT_MIPS_PIXIE_INIT: case DT_MIPS_SYMBOL_LIB: case DT_MIPS_OPTIONS: case DT_MIPS_INTERFACE: case DT_MIPS_DYNSTR_ALIGN: case DT_MIPS_INTERFACE_SIZE: case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: case DT_MIPS_COMPACT_SIZE: case DT_MIPS_GP_VALUE: case DT_MIPS_AUX_DYNAMIC: case DT_MIPS_PLTGOT: case DT_MIPS_RLD_OBJ_UPDATE: case DT_MIPS_RWPLT: printf(" 0x%jx\n", (uintmax_t) dyn->d_un.d_val); break; case DT_MIPS_IVERSION: case DT_MIPS_PERF_SUFFIX: case DT_AUXILIARY: case DT_FILTER: name = dyn_str(re, stab, dyn->d_un.d_val); printf(" %s\n", name); break; case DT_MIPS_TIME_STAMP: printf(" %s\n", timestamp(dyn->d_un.d_val)); break; } break; default: printf("\n"); break; } } static void dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab) { const char *name; if (dyn->d_tag >= DT_LOPROC && dyn->d_tag <= DT_HIPROC) { dump_arch_dyn_val(re, dyn, stab); return; } /* These entry values are index into the string table. */ name = NULL; if (dyn->d_tag == DT_NEEDED || dyn->d_tag == DT_SONAME || dyn->d_tag == DT_RPATH || dyn->d_tag == DT_RUNPATH) name = dyn_str(re, stab, dyn->d_un.d_val); switch(dyn->d_tag) { case DT_NULL: case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_RELA: case DT_INIT: case DT_SYMBOLIC: case DT_REL: case DT_DEBUG: case DT_TEXTREL: case DT_JMPREL: case DT_FINI: case DT_VERDEF: case DT_VERNEED: case DT_VERSYM: case DT_GNU_HASH: case DT_GNU_LIBLIST: case DT_GNU_CONFLICT: printf(" 0x%jx\n", (uintmax_t) dyn->d_un.d_val); break; case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_RELSZ: case DT_RELENT: case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_GNU_CONFLICTSZ: case DT_GNU_LIBLISTSZ: printf(" %ju (bytes)\n", (uintmax_t) dyn->d_un.d_val); break; case DT_RELACOUNT: case DT_RELCOUNT: case DT_VERDEFNUM: case DT_VERNEEDNUM: printf(" %ju\n", (uintmax_t) dyn->d_un.d_val); break; case DT_NEEDED: printf(" Shared library: [%s]\n", name); break; case DT_SONAME: printf(" Library soname: [%s]\n", name); break; case DT_RPATH: printf(" Library rpath: [%s]\n", name); break; case DT_RUNPATH: printf(" Library runpath: [%s]\n", name); break; case DT_PLTREL: printf(" %s\n", dt_type(re->ehdr.e_machine, dyn->d_un.d_val)); break; case DT_GNU_PRELINKED: printf(" %s\n", timestamp(dyn->d_un.d_val)); break; default: printf("\n"); } } static void dump_rel(struct readelf *re, struct section *s, Elf_Data *d) { GElf_Rel r; const char *symname; uint64_t symval; int i, len; #define REL_HDR "r_offset", "r_info", "r_type", "st_value", "st_name" #define REL_CT32 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \ r_type(re->ehdr.e_machine, ELF32_R_TYPE(r.r_info)), \ (uintmax_t)symval, symname #define REL_CT64 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \ r_type(re->ehdr.e_machine, ELF64_R_TYPE(r.r_info)), \ (uintmax_t)symval, symname printf("\nRelocation section (%s):\n", s->name); if (re->ec == ELFCLASS32) printf("%-8s %-8s %-19s %-8s %s\n", REL_HDR); else { if (re->options & RE_WW) printf("%-16s %-16s %-24s %-16s %s\n", REL_HDR); else printf("%-12s %-12s %-19s %-16s %s\n", REL_HDR); } len = d->d_size / s->entsize; for (i = 0; i < len; i++) { if (gelf_getrel(d, i, &r) != &r) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info)); symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info)); if (re->ec == ELFCLASS32) { r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info), ELF64_R_TYPE(r.r_info)); printf("%8.8jx %8.8jx %-19.19s %8.8jx %s\n", REL_CT32); } else { if (re->options & RE_WW) printf("%16.16jx %16.16jx %-24.24s" " %16.16jx %s\n", REL_CT64); else printf("%12.12jx %12.12jx %-19.19s" " %16.16jx %s\n", REL_CT64); } } #undef REL_HDR #undef REL_CT } static void dump_rela(struct readelf *re, struct section *s, Elf_Data *d) { GElf_Rela r; const char *symname; uint64_t symval; int i, len; #define RELA_HDR "r_offset", "r_info", "r_type", "st_value", \ "st_name + r_addend" #define RELA_CT32 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \ r_type(re->ehdr.e_machine, ELF32_R_TYPE(r.r_info)), \ (uintmax_t)symval, symname #define RELA_CT64 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \ r_type(re->ehdr.e_machine, ELF64_R_TYPE(r.r_info)), \ (uintmax_t)symval, symname printf("\nRelocation section with addend (%s):\n", s->name); if (re->ec == ELFCLASS32) printf("%-8s %-8s %-19s %-8s %s\n", RELA_HDR); else { if (re->options & RE_WW) printf("%-16s %-16s %-24s %-16s %s\n", RELA_HDR); else printf("%-12s %-12s %-19s %-16s %s\n", RELA_HDR); } len = d->d_size / s->entsize; for (i = 0; i < len; i++) { if (gelf_getrela(d, i, &r) != &r) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info)); symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info)); if (re->ec == ELFCLASS32) { r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info), ELF64_R_TYPE(r.r_info)); printf("%8.8jx %8.8jx %-19.19s %8.8jx %s", RELA_CT32); printf(" + %x\n", (uint32_t) r.r_addend); } else { if (re->options & RE_WW) printf("%16.16jx %16.16jx %-24.24s" " %16.16jx %s", RELA_CT64); else printf("%12.12jx %12.12jx %-19.19s" " %16.16jx %s", RELA_CT64); printf(" + %jx\n", (uintmax_t) r.r_addend); } } #undef RELA_HDR #undef RELA_CT } static void dump_reloc(struct readelf *re) { struct section *s; Elf_Data *d; int i, elferr; for (i = 0; (size_t)i < re->shnum; i++) { s = &re->sl[i]; if (s->type == SHT_REL || s->type == SHT_RELA) { (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } if (s->type == SHT_REL) dump_rel(re, s, d); else dump_rela(re, s, d); } } } static void dump_symtab(struct readelf *re, int i) { struct section *s; Elf_Data *d; GElf_Sym sym; const char *name; int elferr, stab, j; s = &re->sl[i]; stab = s->link; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size <= 0) return; printf("Symbol table (%s)", s->name); printf(" contains %ju entries:\n", s->sz / s->entsize); printf("%7s%9s%14s%5s%8s%6s%9s%5s\n", "Num:", "Value", "Size", "Type", "Bind", "Vis", "Ndx", "Name"); for (j = 0; (uint64_t)j < s->sz / s->entsize; j++) { if (gelf_getsym(d, j, &sym) != &sym) { warnx("gelf_getsym failed: %s", elf_errmsg(-1)); continue; } printf("%6d:", j); printf(" %16.16jx", (uintmax_t)sym.st_value); printf(" %5ju", sym.st_size); printf(" %-7s", st_type(GELF_ST_TYPE(sym.st_info))); printf(" %-6s", st_bind(GELF_ST_BIND(sym.st_info))); printf(" %-8s", st_vis(GELF_ST_VISIBILITY(sym.st_other))); printf(" %3s", st_shndx(sym.st_shndx)); if ((name = elf_strptr(re->elf, stab, sym.st_name)) != NULL) printf(" %s", name); /* Append symbol version string for SHT_DYNSYM symbol table. */ if (s->type == SHT_DYNSYM && re->ver != NULL && re->vs != NULL && re->vs[j] > 1) { if (re->vs[j] & 0x8000 || re->ver[re->vs[j] & 0x7fff].type == 0) printf("@%s (%d)", re->ver[re->vs[j] & 0x7fff].name, re->vs[j] & 0x7fff); else printf("@@%s (%d)", re->ver[re->vs[j]].name, re->vs[j]); } putchar('\n'); } } static void dump_symtabs(struct readelf *re) { GElf_Dyn dyn; Elf_Data *d; struct section *s; uint64_t dyn_off; int elferr, i; /* * If -D is specified, only dump the symbol table specified by * the DT_SYMTAB entry in the .dynamic section. */ dyn_off = 0; if (re->options & RE_DD) { s = NULL; for (i = 0; (size_t)i < re->shnum; i++) if (re->sl[i].type == SHT_DYNAMIC) { s = &re->sl[i]; break; } if (s == NULL) return; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(-1)); return; } if (d->d_size <= 0) return; for (i = 0; (uint64_t)i < s->sz / s->entsize; i++) { if (gelf_getdyn(d, i, &dyn) != &dyn) { warnx("gelf_getdyn failed: %s", elf_errmsg(-1)); continue; } if (dyn.d_tag == DT_SYMTAB) { dyn_off = dyn.d_un.d_val; break; } } } /* Find and dump symbol tables. */ for (i = 0; (size_t)i < re->shnum; i++) { s = &re->sl[i]; if (s->type == SHT_SYMTAB || s->type == SHT_DYNSYM) { if (re->options & RE_DD) { if (dyn_off == s->addr) { dump_symtab(re, i); break; } } else dump_symtab(re, i); } } } static void dump_svr4_hash(struct section *s) { Elf_Data *d; uint32_t *buf; uint32_t nbucket, nchain; uint32_t *bucket, *chain; uint32_t *bl, *c, maxl, total; int elferr, i, j; /* Read and parse the content of .hash section. */ (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size < 2 * sizeof(uint32_t)) { warnx(".hash section too small"); return; } buf = d->d_buf; nbucket = buf[0]; nchain = buf[1]; if (nbucket <= 0 || nchain <= 0) { warnx("Malformed .hash section"); return; } if (d->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) { warnx("Malformed .hash section"); return; } bucket = &buf[2]; chain = &buf[2 + nbucket]; maxl = 0; if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) errx(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j]) if (++bl[i] > maxl) maxl = bl[i]; if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) errx(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) c[bl[i]]++; printf("\nHistogram for bucket list length (total of %u buckets):\n", nbucket); printf(" Length\tNumber\t\t%% of total\tCoverage\n"); total = 0; for (i = 0; (uint32_t)i <= maxl; i++) { total += c[i] * i; printf("%7u\t%-10u\t(%5.1f%%)\t%5.1f%%\n", i, c[i], c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1)); } free(c); free(bl); } static void dump_svr4_hash64(struct readelf *re, struct section *s) { Elf_Data *d, dst; uint64_t *buf; uint64_t nbucket, nchain; uint64_t *bucket, *chain; uint64_t *bl, *c, maxl, total; int elferr, i, j; /* * ALPHA uses 64-bit hash entries. Since libelf assumes that * .hash section contains only 32-bit entry, an explicit * gelf_xlatetom is needed here. */ (void) elf_errno(); if ((d = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_rawdata failed: %s", elf_errmsg(elferr)); return; } d->d_type = ELF_T_XWORD; memcpy(&dst, d, sizeof(Elf_Data)); if (gelf_xlatetom(re->elf, &dst, d, re->ehdr.e_ident[EI_DATA]) != &dst) { warnx("gelf_xlatetom failed: %s", elf_errmsg(-1)); return; } if (dst.d_size < 2 * sizeof(uint64_t)) { warnx(".hash section too small"); return; } buf = dst.d_buf; nbucket = buf[0]; nchain = buf[1]; if (nbucket <= 0 || nchain <= 0) { warnx("Malformed .hash section"); return; } if (d->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) { warnx("Malformed .hash section"); return; } bucket = &buf[2]; chain = &buf[2 + nbucket]; maxl = 0; if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) errx(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j]) if (++bl[i] > maxl) maxl = bl[i]; if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) errx(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint64_t)i < nbucket; i++) c[bl[i]]++; printf("Histogram for bucket list length (total of %ju buckets):\n", (uintmax_t)nbucket); printf(" Length\tNumber\t\t%% of total\tCoverage\n"); total = 0; for (i = 0; (uint64_t)i <= maxl; i++) { total += c[i] * i; printf("%7u\t%-10ju\t(%5.1f%%)\t%5.1f%%\n", i, (uintmax_t)c[i], c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1)); } free(c); free(bl); } static void dump_gnu_hash(struct readelf *re, struct section *s) { struct section *ds; Elf_Data *d; uint32_t *buf; uint32_t *bucket, *chain; - uint32_t nbucket, nchain, symndx, maskwords, shift2; + uint32_t nbucket, nchain, symndx, maskwords; uint32_t *bl, *c, maxl, total; int elferr, dynsymcount, i, j; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size < 4 * sizeof(uint32_t)) { warnx(".gnu.hash section too small"); return; } buf = d->d_buf; nbucket = buf[0]; symndx = buf[1]; maskwords = buf[2]; - shift2 = buf[3]; buf += 4; ds = &re->sl[s->link]; dynsymcount = ds->sz / ds->entsize; nchain = dynsymcount - symndx; if (d->d_size != 4 * sizeof(uint32_t) + maskwords * (re->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) + (nbucket + nchain) * sizeof(uint32_t)) { warnx("Malformed .gnu.hash section"); return; } bucket = buf + (re->ec == ELFCLASS32 ? maskwords : maskwords * 2); chain = bucket + nbucket; maxl = 0; if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) errx(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) for (j = bucket[i]; j > 0 && (uint32_t)j - symndx < nchain; j++) { if (++bl[i] > maxl) maxl = bl[i]; if (chain[j - symndx] & 1) break; } if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) errx(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) c[bl[i]]++; printf("Histogram for bucket list length (total of %u buckets):\n", nbucket); printf(" Length\tNumber\t\t%% of total\tCoverage\n"); total = 0; for (i = 0; (uint32_t)i <= maxl; i++) { total += c[i] * i; printf("%7u\t%-10u\t(%5.1f%%)\t%5.1f%%\n", i, c[i], c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1)); } free(c); free(bl); } static void dump_hash(struct readelf *re) { struct section *s; int i; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type == SHT_HASH || s->type == SHT_GNU_HASH) { if (s->type == SHT_GNU_HASH) dump_gnu_hash(re, s); else if (re->ehdr.e_machine == EM_ALPHA && s->entsize == 8) dump_svr4_hash64(re, s); else dump_svr4_hash(s); } } } static void dump_notes(struct readelf *re) { struct section *s; const char *rawfile; GElf_Phdr phdr; Elf_Data *d; size_t phnum; int i, elferr; if (re->ehdr.e_type == ET_CORE) { /* * Search program headers in the core file for * PT_NOTE entry. */ if (elf_getphnum(re->elf, &phnum) == 0) { warnx("elf_getphnum failed: %s", elf_errmsg(-1)); return; } if (phnum == 0) return; if ((rawfile = elf_rawfile(re->elf, NULL)) == NULL) { warnx("elf_rawfile failed: %s", elf_errmsg(-1)); return; } for (i = 0; (size_t) i < phnum; i++) { if (gelf_getphdr(re->elf, i, &phdr) != &phdr) { warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); continue; } if (phdr.p_type == PT_NOTE) dump_notes_content(re, rawfile + phdr.p_offset, phdr.p_filesz, phdr.p_offset); } } else { /* * For objects other than core files, Search for * SHT_NOTE sections. */ for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type == SHT_NOTE) { (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } dump_notes_content(re, d->d_buf, d->d_size, s->off); } } } } static void dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off) { Elf_Note *note; const char *end; printf("\nNotes at offset %#010jx with length %#010jx:\n", (uintmax_t) off, (uintmax_t) sz); printf(" %-13s %-15s %s\n", "Owner", "Data size", "Description"); end = buf + sz; while (buf < end) { note = (Elf_Note *)(uintptr_t) buf; printf(" %-13s %#010jx", (char *)(uintptr_t) (note + 1), (uintmax_t) note->n_descsz); printf(" %s\n", note_type(re->ehdr.e_ident[EI_OSABI], re->ehdr.e_type, note->n_type)); buf += sizeof(Elf_Note); if (re->ec == ELFCLASS32) buf += roundup2(note->n_namesz, 4) + roundup2(note->n_descsz, 4); else buf += roundup2(note->n_namesz, 8) + roundup2(note->n_descsz, 8); } } /* * Symbol versioning sections are the same for 32bit and 64bit * ELF objects. */ #define Elf_Verdef Elf32_Verdef #define Elf_Verdaux Elf32_Verdaux #define Elf_Verneed Elf32_Verneed #define Elf_Vernaux Elf32_Vernaux #define SAVE_VERSION_NAME(x, n, t) \ do { \ while (x >= re->ver_sz) { \ nv = realloc(re->ver, \ sizeof(*re->ver) * re->ver_sz * 2); \ if (nv == NULL) { \ warn("realloc failed"); \ free(re->ver); \ return; \ } \ re->ver = nv; \ for (i = re->ver_sz; i < re->ver_sz * 2; i++) { \ re->ver[i].name = NULL; \ re->ver[i].type = 0; \ } \ re->ver_sz *= 2; \ } \ if (x > 1) { \ re->ver[x].name = n; \ re->ver[x].type = t; \ } \ } while (0) static void dump_verdef(struct readelf *re, int dump) { struct section *s; struct symver *nv; Elf_Data *d; Elf_Verdef *vd; Elf_Verdaux *vda; uint8_t *buf, *end, *buf2; const char *name; int elferr, i, j; if ((s = re->vd_s) == NULL) return; if (re->ver == NULL) { re->ver_sz = 16; if ((re->ver = calloc(re->ver_sz, sizeof(*re->ver))) == NULL) { warn("calloc failed"); return; } re->ver[0].name = "*local*"; re->ver[1].name = "*global*"; } if (dump) printf("\nVersion definition section (%s):\n", s->name); (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size == 0) return; buf = d->d_buf; end = buf + d->d_size; while (buf + sizeof(Elf_Verdef) <= end) { vd = (Elf_Verdef *) (uintptr_t) buf; if (dump) { printf(" 0x%4.4lx", (unsigned long) (buf - (uint8_t *)d->d_buf)); printf(" vd_version: %u vd_flags: %d" " vd_ndx: %u vd_cnt: %u", vd->vd_version, vd->vd_flags, vd->vd_ndx, vd->vd_cnt); } buf2 = buf + vd->vd_aux; j = 0; while (buf2 + sizeof(Elf_Verdaux) <= end && j < vd->vd_cnt) { vda = (Elf_Verdaux *) (uintptr_t) buf2; name = get_string(re, s->link, vda->vda_name); if (j == 0) { if (dump) printf(" vda_name: %s\n", name); SAVE_VERSION_NAME((int)vd->vd_ndx, name, 1); } else if (dump) printf(" 0x%4.4lx parent: %s\n", (unsigned long) (buf2 - (uint8_t *)d->d_buf), name); if (vda->vda_next == 0) break; buf2 += vda->vda_next; j++; } if (vd->vd_next == 0) break; buf += vd->vd_next; } } static void dump_verneed(struct readelf *re, int dump) { struct section *s; struct symver *nv; Elf_Data *d; Elf_Verneed *vn; Elf_Vernaux *vna; uint8_t *buf, *end, *buf2; const char *name; int elferr, i, j; if ((s = re->vn_s) == NULL) return; if (re->ver == NULL) { re->ver_sz = 16; if ((re->ver = calloc(re->ver_sz, sizeof(*re->ver))) == NULL) { warn("calloc failed"); return; } re->ver[0].name = "*local*"; re->ver[1].name = "*global*"; } if (dump) printf("\nVersion needed section (%s):\n", s->name); (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size == 0) return; buf = d->d_buf; end = buf + d->d_size; while (buf + sizeof(Elf_Verneed) <= end) { vn = (Elf_Verneed *) (uintptr_t) buf; if (dump) { printf(" 0x%4.4lx", (unsigned long) (buf - (uint8_t *)d->d_buf)); printf(" vn_version: %u vn_file: %s vn_cnt: %u\n", vn->vn_version, get_string(re, s->link, vn->vn_file), vn->vn_cnt); } buf2 = buf + vn->vn_aux; j = 0; while (buf2 + sizeof(Elf_Vernaux) <= end && j < vn->vn_cnt) { vna = (Elf32_Vernaux *) (uintptr_t) buf2; if (dump) printf(" 0x%4.4lx", (unsigned long) (buf2 - (uint8_t *)d->d_buf)); name = get_string(re, s->link, vna->vna_name); if (dump) printf(" vna_name: %s vna_flags: %u" " vna_other: %u\n", name, vna->vna_flags, vna->vna_other); SAVE_VERSION_NAME((int)vna->vna_other, name, 0); if (vna->vna_next == 0) break; buf2 += vna->vna_next; j++; } if (vn->vn_next == 0) break; buf += vn->vn_next; } } static void dump_versym(struct readelf *re) { int i; if (re->vs_s == NULL || re->ver == NULL || re->vs == NULL) return; printf("\nVersion symbol section (%s):\n", re->vs_s->name); for (i = 0; i < re->vs_sz; i++) { if ((i & 3) == 0) { if (i > 0) putchar('\n'); printf(" %03x:", i); } if (re->vs[i] & 0x8000) printf(" %3xh %-12s ", re->vs[i] & 0x7fff, re->ver[re->vs[i] & 0x7fff].name); else printf(" %3x %-12s ", re->vs[i], re->ver[re->vs[i]].name); } putchar('\n'); } static void dump_ver(struct readelf *re) { if (re->vs_s && re->ver && re->vs) dump_versym(re); if (re->vd_s) dump_verdef(re, 1); if (re->vn_s) dump_verneed(re, 1); } static void search_ver(struct readelf *re) { struct section *s; Elf_Data *d; int elferr, i; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type == SHT_SUNW_versym) re->vs_s = s; if (s->type == SHT_SUNW_verneed) re->vn_s = s; if (s->type == SHT_SUNW_verdef) re->vd_s = s; } if (re->vd_s) dump_verdef(re, 0); if (re->vn_s) dump_verneed(re, 0); if (re->vs_s && re->ver != NULL) { (void) elf_errno(); if ((d = elf_getdata(re->vs_s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size == 0) return; re->vs = d->d_buf; re->vs_sz = d->d_size / sizeof(Elf32_Half); } } #undef Elf_Verdef #undef Elf_Verdaux #undef Elf_Verneed #undef Elf_Vernaux #undef SAVE_VERSION_NAME /* * Elf32_Lib and Elf64_Lib are identical. */ #define Elf_Lib Elf32_Lib static void dump_liblist(struct readelf *re) { struct section *s; struct tm *t; time_t ti; char tbuf[20]; Elf_Data *d; Elf_Lib *lib; int i, j, k, elferr, first; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type != SHT_GNU_LIBLIST) continue; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } if (d->d_size <= 0) continue; lib = d->d_buf; printf("\nLibrary list section '%s' ", s->name); printf("contains %ju entries:\n", s->sz / s->entsize); printf("%12s%24s%18s%10s%6s\n", "Library", "Time Stamp", "Checksum", "Version", "Flags"); for (j = 0; (uint64_t) j < s->sz / s->entsize; j++) { printf("%3d: ", j); printf("%-20.20s ", get_string(re, s->link, lib->l_name)); ti = lib->l_time_stamp; t = gmtime(&ti); snprintf(tbuf, sizeof(tbuf), "%04d-%02d-%02dT%02d:%02d" ":%2d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); printf("%-19.19s ", tbuf); printf("0x%08x ", lib->l_checksum); printf("%-7d %#x", lib->l_version, lib->l_flags); if (lib->l_flags != 0) { first = 1; putchar('('); for (k = 0; l_flag[k].name != NULL; k++) { if ((l_flag[k].value & lib->l_flags) == 0) continue; if (!first) putchar(','); else first = 0; printf("%s", l_flag[k].name); } putchar(')'); } putchar('\n'); lib++; } } } #undef Elf_Lib static uint8_t * dump_unknown_tag(uint64_t tag, uint8_t *p) { uint64_t val; /* * According to ARM EABI: For tags > 32, even numbered tags have * a ULEB128 param and odd numbered ones have NUL-terminated * string param. This rule probably also applies for tags <= 32 * if the object arch is not ARM. */ printf(" Tag_unknown_%ju: ", (uintmax_t) tag); if (tag & 1) { printf("%s\n", (char *) p); p += strlen((char *) p) + 1; } else { val = _decode_uleb128(&p); printf("%ju\n", (uintmax_t) val); } return (p); } static uint8_t * dump_compatibility_tag(uint8_t *p) { uint64_t val; val = _decode_uleb128(&p); printf("flag = %ju, vendor = %s\n", val, p); p += strlen((char *) p) + 1; return (p); } static void dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe) { uint64_t tag, val; size_t i; int found, desc; (void) re; while (p < pe) { tag = _decode_uleb128(&p); found = desc = 0; for (i = 0; i < sizeof(aeabi_tags) / sizeof(aeabi_tags[0]); i++) { if (tag == aeabi_tags[i].tag) { found = 1; printf(" %s: ", aeabi_tags[i].s_tag); if (aeabi_tags[i].get_desc) { desc = 1; val = _decode_uleb128(&p); printf("%s\n", aeabi_tags[i].get_desc(val)); } break; } if (tag < aeabi_tags[i].tag) break; } if (!found) { p = dump_unknown_tag(tag, p); continue; } if (desc) continue; switch (tag) { case 4: /* Tag_CPU_raw_name */ case 5: /* Tag_CPU_name */ case 67: /* Tag_conformance */ printf("%s\n", (char *) p); p += strlen((char *) p) + 1; break; case 32: /* Tag_compatibility */ p = dump_compatibility_tag(p); break; case 64: /* Tag_nodefaults */ /* ignored, written as 0. */ (void) _decode_uleb128(&p); printf("True\n"); break; case 65: /* Tag_also_compatible_with */ val = _decode_uleb128(&p); /* Must be Tag_CPU_arch */ if (val != 6) { printf("unknown\n"); break; } val = _decode_uleb128(&p); printf("%s\n", aeabi_cpu_arch(val)); /* Skip NUL terminator. */ p++; break; default: putchar('\n'); break; } } } #ifndef Tag_GNU_MIPS_ABI_FP #define Tag_GNU_MIPS_ABI_FP 4 #endif static void dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe) { uint64_t tag, val; (void) re; while (p < pe) { tag = _decode_uleb128(&p); switch (tag) { case Tag_GNU_MIPS_ABI_FP: val = _decode_uleb128(&p); printf(" Tag_GNU_MIPS_ABI_FP: %s\n", mips_abi_fp(val)); break; case 32: /* Tag_compatibility */ p = dump_compatibility_tag(p); break; default: p = dump_unknown_tag(tag, p); break; } } } #ifndef Tag_GNU_Power_ABI_FP #define Tag_GNU_Power_ABI_FP 4 #endif #ifndef Tag_GNU_Power_ABI_Vector #define Tag_GNU_Power_ABI_Vector 8 #endif static void dump_ppc_attributes(uint8_t *p, uint8_t *pe) { uint64_t tag, val; while (p < pe) { tag = _decode_uleb128(&p); switch (tag) { case Tag_GNU_Power_ABI_FP: val = _decode_uleb128(&p); printf(" Tag_GNU_Power_ABI_FP: %s\n", ppc_abi_fp(val)); break; case Tag_GNU_Power_ABI_Vector: val = _decode_uleb128(&p); printf(" Tag_GNU_Power_ABI_Vector: %s\n", ppc_abi_vector(val)); break; case 32: /* Tag_compatibility */ p = dump_compatibility_tag(p); break; default: p = dump_unknown_tag(tag, p); break; } } } static void dump_attributes(struct readelf *re) { struct section *s; Elf_Data *d; uint8_t *p, *sp; size_t len, seclen, nlen, sublen; uint64_t val; int tag, i, elferr; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type != SHT_GNU_ATTRIBUTES && (re->ehdr.e_machine != EM_ARM || s->type != SHT_LOPROC + 3)) continue; (void) elf_errno(); if ((d = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_rawdata failed: %s", elf_errmsg(elferr)); continue; } if (d->d_size <= 0) continue; p = d->d_buf; if (*p != 'A') { printf("Unknown Attribute Section Format: %c\n", (char) *p); continue; } len = d->d_size - 1; p++; while (len > 0) { seclen = re->dw_decode(&p, 4); if (seclen > len) { warnx("invalid attribute section length"); break; } len -= seclen; printf("Attribute Section: %s\n", (char *) p); nlen = strlen((char *) p) + 1; p += nlen; seclen -= nlen + 4; while (seclen > 0) { sp = p; tag = *p++; sublen = re->dw_decode(&p, 4); if (sublen > seclen) { warnx("invalid attribute sub-section" " length"); break; } seclen -= sublen; printf("%s", top_tag(tag)); if (tag == 2 || tag == 3) { putchar(':'); for (;;) { val = _decode_uleb128(&p); if (val == 0) break; printf(" %ju", (uintmax_t) val); } } putchar('\n'); if (re->ehdr.e_machine == EM_ARM && s->type == SHT_LOPROC + 3) dump_arm_attributes(re, p, sp + sublen); else if (re->ehdr.e_machine == EM_MIPS || re->ehdr.e_machine == EM_MIPS_RS3_LE) dump_mips_attributes(re, p, sp + sublen); else if (re->ehdr.e_machine == EM_PPC) dump_ppc_attributes(p, sp + sublen); p = sp + sublen; } } } } static void dump_mips_specific_info(struct readelf *re) { struct section *s; int i, options_found; options_found = 0; s = NULL; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && (!strcmp(s->name, ".MIPS.options") || (s->type == SHT_MIPS_OPTIONS))) { dump_mips_options(re, s); options_found = 1; } } /* * According to SGI mips64 spec, .reginfo should be ignored if * .MIPS.options section is present. */ if (!options_found) { for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && (!strcmp(s->name, ".reginfo") || (s->type == SHT_MIPS_REGINFO))) dump_mips_reginfo(re, s); } } } static void dump_mips_reginfo(struct readelf *re, struct section *s) { Elf_Data *d; int elferr; (void) elf_errno(); if ((d = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_rawdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size <= 0) return; printf("\nSection '%s' contains %ju entries:\n", s->name, s->sz / s->entsize); dump_mips_odk_reginfo(re, d->d_buf, d->d_size); } static void dump_mips_options(struct readelf *re, struct section *s) { Elf_Data *d; uint32_t info; uint16_t sndx; uint8_t *p, *pe; uint8_t kind, size; int elferr; (void) elf_errno(); if ((d = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_rawdata failed: %s", elf_errmsg(elferr)); return; } if (d->d_size == 0) return; printf("\nSection %s contains:\n", s->name); p = d->d_buf; pe = p + d->d_size; while (p < pe) { kind = re->dw_decode(&p, 1); size = re->dw_decode(&p, 1); sndx = re->dw_decode(&p, 2); info = re->dw_decode(&p, 4); switch (kind) { case ODK_REGINFO: dump_mips_odk_reginfo(re, p, size - 8); break; case ODK_EXCEPTIONS: printf(" EXCEPTIONS FPU_MIN: %#x\n", info & OEX_FPU_MIN); printf("%11.11s FPU_MAX: %#x\n", "", info & OEX_FPU_MAX); dump_mips_option_flags("", mips_exceptions_option, info); break; case ODK_PAD: printf(" %-10.10s section: %ju\n", "OPAD", (uintmax_t) sndx); dump_mips_option_flags("", mips_pad_option, info); break; case ODK_HWPATCH: dump_mips_option_flags("HWPATCH", mips_hwpatch_option, info); break; case ODK_HWAND: dump_mips_option_flags("HWAND", mips_hwa_option, info); break; case ODK_HWOR: dump_mips_option_flags("HWOR", mips_hwo_option, info); break; case ODK_FILL: printf(" %-10.10s %#jx\n", "FILL", (uintmax_t) info); break; case ODK_TAGS: printf(" %-10.10s\n", "TAGS"); break; case ODK_GP_GROUP: printf(" %-10.10s GP group number: %#x\n", "GP_GROUP", info & 0xFFFF); if (info & 0x10000) printf(" %-10.10s GP group is " "self-contained\n", ""); break; case ODK_IDENT: printf(" %-10.10s default GP group number: %#x\n", "IDENT", info & 0xFFFF); if (info & 0x10000) printf(" %-10.10s default GP group is " "self-contained\n", ""); break; case ODK_PAGESIZE: printf(" %-10.10s\n", "PAGESIZE"); break; default: break; } p += size - 8; } } static void dump_mips_option_flags(const char *name, struct mips_option *opt, uint64_t info) { int first; first = 1; for (; opt->desc != NULL; opt++) { if (info & opt->flag) { printf(" %-10.10s %s\n", first ? name : "", opt->desc); first = 0; } } } static void dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz) { uint32_t ri_gprmask; uint32_t ri_cprmask[4]; uint64_t ri_gp_value; uint8_t *pe; int i; pe = p + sz; while (p < pe) { ri_gprmask = re->dw_decode(&p, 4); /* Skip ri_pad padding field for mips64. */ if (re->ec == ELFCLASS64) re->dw_decode(&p, 4); for (i = 0; i < 4; i++) ri_cprmask[i] = re->dw_decode(&p, 4); if (re->ec == ELFCLASS32) ri_gp_value = re->dw_decode(&p, 4); else ri_gp_value = re->dw_decode(&p, 8); printf(" %s ", option_kind(ODK_REGINFO)); printf("ri_gprmask: 0x%08jx\n", (uintmax_t) ri_gprmask); for (i = 0; i < 4; i++) printf("%11.11s ri_cprmask[%d]: 0x%08jx\n", "", i, (uintmax_t) ri_cprmask[i]); printf("%12.12s", ""); printf("ri_gp_value: %#jx\n", (uintmax_t) ri_gp_value); } } static void dump_arch_specific_info(struct readelf *re) { dump_liblist(re); dump_attributes(re); switch (re->ehdr.e_machine) { case EM_MIPS: case EM_MIPS_RS3_LE: dump_mips_specific_info(re); default: break; } } +static const char * +dwarf_regname(struct readelf *re, unsigned int num) +{ + static char rx[32]; + const char *rn; + + if ((rn = dwarf_reg(re->ehdr.e_machine, num)) != NULL) + return (rn); + + snprintf(rx, sizeof(rx), "r%u", num); + + return (rx); +} + static void dump_dwarf_line(struct readelf *re) { struct section *s; Dwarf_Die die; Dwarf_Error de; Dwarf_Half tag, version, pointer_size; Dwarf_Unsigned offset, endoff, length, hdrlen, dirndx, mtime, fsize; Dwarf_Small minlen, defstmt, lrange, opbase, oplen; Elf_Data *d; char *pn; uint64_t address, file, line, column, isa, opsize, udelta; int64_t sdelta; uint8_t *p, *pe; int8_t lbase; - int is_stmt, basic_block, end_sequence; - int prologue_end, epilogue_begin; - int i, dwarf_size, elferr, ret; + int i, is_stmt, dwarf_size, elferr, ret; printf("\nDump of debug contents of section .debug_line:\n"); s = NULL; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && !strcmp(s->name, ".debug_line")) break; } if ((size_t) i >= re->shnum) return; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(-1)); return; } if (d->d_size <= 0) return; while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { die = NULL; while (dwarf_siblingof(re->dbg, die, &die, &de) == DW_DLV_OK) { if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); return; } /* XXX: What about DW_TAG_partial_unit? */ if (tag == DW_TAG_compile_unit) break; } if (die == NULL) { warnx("could not find DW_TAG_compile_unit die"); return; } if (dwarf_attrval_unsigned(die, DW_AT_stmt_list, &offset, &de) != DW_DLV_OK) continue; length = re->dw_read(d, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = re->dw_read(d, &offset, 8); } else dwarf_size = 4; if (length > d->d_size - offset) { warnx("invalid .dwarf_line section"); continue; } endoff = offset + length; version = re->dw_read(d, &offset, 2); hdrlen = re->dw_read(d, &offset, dwarf_size); minlen = re->dw_read(d, &offset, 1); defstmt = re->dw_read(d, &offset, 1); lbase = re->dw_read(d, &offset, 1); lrange = re->dw_read(d, &offset, 1); opbase = re->dw_read(d, &offset, 1); printf("\n"); printf(" Length:\t\t\t%ju\n", (uintmax_t) length); printf(" DWARF version:\t\t%u\n", version); printf(" Prologue Length:\t\t%ju\n", (uintmax_t) hdrlen); printf(" Minimum Instruction Length:\t%u\n", minlen); printf(" Initial value of 'is_stmt':\t%u\n", defstmt); printf(" Line Base:\t\t\t%d\n", lbase); printf(" Line Range:\t\t\t%u\n", lrange); printf(" Opcode Base:\t\t\t%u\n", opbase); (void) dwarf_get_address_size(re->dbg, &pointer_size, &de); printf(" (Pointer size:\t\t%u)\n", pointer_size); printf("\n"); printf(" Opcodes:\n"); for (i = 1; i < opbase; i++) { oplen = re->dw_read(d, &offset, 1); printf(" Opcode %d has %u args\n", i, oplen); } printf("\n"); printf(" The Directory Table:\n"); p = (uint8_t *) d->d_buf + offset; while (*p != '\0') { printf(" %s\n", (char *) p); p += strlen((char *) p) + 1; } p++; printf("\n"); printf(" The File Name Table:\n"); printf(" Entry\tDir\tTime\tSize\tName\n"); i = 0; while (*p != '\0') { i++; pn = (char *) p; p += strlen(pn) + 1; dirndx = _decode_uleb128(&p); mtime = _decode_uleb128(&p); fsize = _decode_uleb128(&p); printf(" %d\t%ju\t%ju\t%ju\t%s\n", i, (uintmax_t) dirndx, (uintmax_t) mtime, (uintmax_t) fsize, pn); } #define RESET_REGISTERS \ do { \ address = 0; \ file = 1; \ line = 1; \ column = 0; \ is_stmt = defstmt; \ - basic_block = 0; \ - end_sequence = 0; \ - prologue_end = 0; \ - epilogue_begin = 0; \ } while(0) #define LINE(x) (lbase + (((x) - opbase) % lrange)) #define ADDRESS(x) ((((x) - opbase) / lrange) * minlen) p++; pe = (uint8_t *) d->d_buf + endoff; printf("\n"); printf(" Line Number Statements:\n"); RESET_REGISTERS; while (p < pe) { if (*p == 0) { /* * Extended Opcodes. */ p++; opsize = _decode_uleb128(&p); printf(" Extended opcode %u: ", *p); switch (*p) { case DW_LNE_end_sequence: p++; - end_sequence = 1; RESET_REGISTERS; printf("End of Sequence\n"); break; case DW_LNE_set_address: p++; address = re->dw_decode(&p, pointer_size); printf("set Address to %#jx\n", (uintmax_t) address); break; case DW_LNE_define_file: p++; pn = (char *) p; p += strlen(pn) + 1; dirndx = _decode_uleb128(&p); mtime = _decode_uleb128(&p); fsize = _decode_uleb128(&p); printf("define new file: %s\n", pn); break; default: /* Unrecognized extened opcodes. */ p += opsize; printf("unknown opcode\n"); } } else if (*p > 0 && *p < opbase) { /* * Standard Opcodes. */ switch(*p++) { case DW_LNS_copy: - basic_block = 0; - prologue_end = 0; - epilogue_begin = 0; printf(" Copy\n"); break; case DW_LNS_advance_pc: udelta = _decode_uleb128(&p) * minlen; address += udelta; printf(" Advance PC by %ju to %#jx\n", (uintmax_t) udelta, (uintmax_t) address); break; case DW_LNS_advance_line: sdelta = _decode_sleb128(&p); line += sdelta; printf(" Advance Line by %jd to %ju\n", (intmax_t) sdelta, (uintmax_t) line); break; case DW_LNS_set_file: file = _decode_uleb128(&p); printf(" Set File to %ju\n", (uintmax_t) file); break; case DW_LNS_set_column: column = _decode_uleb128(&p); printf(" Set Column to %ju\n", (uintmax_t) column); break; case DW_LNS_negate_stmt: is_stmt = !is_stmt; printf(" Set is_stmt to %d\n", is_stmt); break; case DW_LNS_set_basic_block: - basic_block = 1; printf(" Set basic block flag\n"); break; case DW_LNS_const_add_pc: address += ADDRESS(255); printf(" Advance PC by constant %ju" " to %#jx\n", (uintmax_t) ADDRESS(255), (uintmax_t) address); break; case DW_LNS_fixed_advance_pc: udelta = re->dw_decode(&p, 2); address += udelta; printf(" Advance PC by fixed value " "%ju to %#jx\n", (uintmax_t) udelta, (uintmax_t) address); break; case DW_LNS_set_prologue_end: - prologue_end = 1; printf(" Set prologue end flag\n"); break; case DW_LNS_set_epilogue_begin: - epilogue_begin = 1; printf(" Set epilogue begin flag\n"); break; case DW_LNS_set_isa: isa = _decode_uleb128(&p); printf(" Set isa to %ju\n", isa); break; default: /* Unrecognized extended opcodes. */ printf(" Unknown extended opcode %u\n", *(p - 1)); break; } } else { /* * Special Opcodes. */ line += LINE(*p); address += ADDRESS(*p); - basic_block = 0; - prologue_end = 0; - epilogue_begin = 0; printf(" Special opcode %u: advance Address " "by %ju to %#jx and Line by %jd to %ju\n", *p - opbase, (uintmax_t) ADDRESS(*p), (uintmax_t) address, (intmax_t) LINE(*p), (uintmax_t) line); p++; } } } if (ret == DW_DLV_ERROR) warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de)); #undef RESET_REGISTERS #undef LINE #undef ADDRESS } static void dump_dwarf_line_decoded(struct readelf *re) { Dwarf_Die die; Dwarf_Line *linebuf, ln; Dwarf_Addr lineaddr; Dwarf_Signed linecount, srccount; Dwarf_Unsigned lineno, fn; Dwarf_Error de; const char *dir, *file; char **srcfiles; int i, ret; printf("Decoded dump of debug contents of section .debug_line:\n\n"); while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { if (dwarf_siblingof(re->dbg, NULL, &die, &de) != DW_DLV_OK) continue; if (dwarf_attrval_string(die, DW_AT_name, &file, &de) != DW_DLV_OK) file = NULL; if (dwarf_attrval_string(die, DW_AT_comp_dir, &dir, &de) != DW_DLV_OK) dir = NULL; printf("CU: "); if (dir && file) printf("%s/", dir); if (file) printf("%s", file); putchar('\n'); printf("%-37s %11s %s\n", "Filename", "Line Number", "Starting Address"); if (dwarf_srclines(die, &linebuf, &linecount, &de) != DW_DLV_OK) continue; if (dwarf_srcfiles(die, &srcfiles, &srccount, &de) != DW_DLV_OK) continue; for (i = 0; i < linecount; i++) { ln = linebuf[i]; if (dwarf_line_srcfileno(ln, &fn, &de) != DW_DLV_OK) continue; if (dwarf_lineno(ln, &lineno, &de) != DW_DLV_OK) continue; if (dwarf_lineaddr(ln, &lineaddr, &de) != DW_DLV_OK) continue; printf("%-37s %11ju %#18jx\n", basename(srcfiles[fn - 1]), (uintmax_t) lineno, (uintmax_t) lineaddr); } putchar('\n'); } } static void dump_dwarf_die(struct readelf *re, Dwarf_Die die, int level) { Dwarf_Attribute *attr_list; Dwarf_Die ret_die; - Dwarf_Off dieoff, cuoff, culen; - Dwarf_Unsigned ate, v_udata; + Dwarf_Off dieoff, cuoff, culen, attroff; + Dwarf_Unsigned ate, lang, v_udata, v_sig; Dwarf_Signed attr_count, v_sdata; Dwarf_Off v_off; Dwarf_Addr v_addr; Dwarf_Half tag, attr, form; Dwarf_Block *v_block; - Dwarf_Bool v_bool; + Dwarf_Bool v_bool, is_info; + Dwarf_Sig8 v_sig8; Dwarf_Error de; - const char *tag_str, *attr_str, *ate_str; + Dwarf_Ptr v_expr; + const char *tag_str, *attr_str, *ate_str, *lang_str; + char unk_tag[32], unk_attr[32]; char *v_str; - uint8_t *b; + uint8_t *b, *p; int i, j, abc, ret; if (dwarf_dieoffset(die, &dieoff, &de) != DW_DLV_OK) { warnx("dwarf_dieoffset failed: %s", dwarf_errmsg(de)); goto cont_search; } - printf("<%d><%jx>: ", level, (uintmax_t) dieoff); + printf(" <%d><%jx>: ", level, (uintmax_t) dieoff); if (dwarf_die_CU_offset_range(die, &cuoff, &culen, &de) != DW_DLV_OK) { warnx("dwarf_die_CU_offset_range failed: %s", dwarf_errmsg(de)); cuoff = 0; } abc = dwarf_die_abbrev_code(die); if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); goto cont_search; } if (dwarf_get_TAG_name(tag, &tag_str) != DW_DLV_OK) { - warnx("dwarf_get_TAG_name failed"); - goto cont_search; + snprintf(unk_tag, sizeof(unk_tag), "[Unknown Tag: %#x]", tag); + tag_str = unk_tag; } printf("Abbrev Number: %d (%s)\n", abc, tag_str); if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) != DW_DLV_OK) { if (ret == DW_DLV_ERROR) warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de)); goto cont_search; } for (i = 0; i < attr_count; i++) { if (dwarf_whatform(attr_list[i], &form, &de) != DW_DLV_OK) { warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) { warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_get_AT_name(attr, &attr_str) != DW_DLV_OK) { - warnx("dwarf_get_AT_name failed"); - continue; + snprintf(unk_attr, sizeof(unk_attr), + "[Unknown AT: %#x]", attr); + attr_str = unk_attr; + } + if (dwarf_attroffset(attr_list[i], &attroff, &de) != + DW_DLV_OK) { + warnx("dwarf_attroffset failed: %s", dwarf_errmsg(de)); + attroff = 0; } - printf(" %-18s: ", attr_str); + printf(" <%jx> %-18s: ", (uintmax_t) attroff, attr_str); switch (form) { case DW_FORM_ref_addr: + case DW_FORM_sec_offset: if (dwarf_global_formref(attr_list[i], &v_off, &de) != DW_DLV_OK) { warnx("dwarf_global_formref failed: %s", dwarf_errmsg(de)); continue; } - printf("<%jx>", (uintmax_t) v_off); + if (form == DW_FORM_ref_addr) + printf("<0x%jx>", (uintmax_t) v_off); + else + printf("0x%jx", (uintmax_t) v_off); break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: if (dwarf_formref(attr_list[i], &v_off, &de) != DW_DLV_OK) { warnx("dwarf_formref failed: %s", dwarf_errmsg(de)); continue; } v_off += cuoff; - printf("<%jx>", (uintmax_t) v_off); + printf("<0x%jx>", (uintmax_t) v_off); break; case DW_FORM_addr: if (dwarf_formaddr(attr_list[i], &v_addr, &de) != DW_DLV_OK) { warnx("dwarf_formaddr failed: %s", dwarf_errmsg(de)); continue; } printf("%#jx", (uintmax_t) v_addr); break; case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_udata: if (dwarf_formudata(attr_list[i], &v_udata, &de) != DW_DLV_OK) { warnx("dwarf_formudata failed: %s", dwarf_errmsg(de)); continue; } - printf("%ju", (uintmax_t) v_udata); + if (attr == DW_AT_high_pc) + printf("0x%jx", (uintmax_t) v_udata); + else + printf("%ju", (uintmax_t) v_udata); break; case DW_FORM_sdata: if (dwarf_formsdata(attr_list[i], &v_sdata, &de) != DW_DLV_OK) { warnx("dwarf_formudata failed: %s", dwarf_errmsg(de)); continue; } printf("%jd", (intmax_t) v_sdata); break; case DW_FORM_flag: if (dwarf_formflag(attr_list[i], &v_bool, &de) != DW_DLV_OK) { warnx("dwarf_formflag failed: %s", dwarf_errmsg(de)); continue; } printf("%jd", (intmax_t) v_bool); break; + case DW_FORM_flag_present: + putchar('1'); + break; + case DW_FORM_string: case DW_FORM_strp: if (dwarf_formstring(attr_list[i], &v_str, &de) != DW_DLV_OK) { warnx("dwarf_formstring failed: %s", dwarf_errmsg(de)); continue; } if (form == DW_FORM_string) printf("%s", v_str); else printf("(indirect string) %s", v_str); break; case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: if (dwarf_formblock(attr_list[i], &v_block, &de) != DW_DLV_OK) { warnx("dwarf_formblock failed: %s", dwarf_errmsg(de)); continue; } - printf("%ju byte block:", v_block->bl_len); + printf("%ju byte block:", (uintmax_t) v_block->bl_len); b = v_block->bl_data; for (j = 0; (Dwarf_Unsigned) j < v_block->bl_len; j++) printf(" %x", b[j]); + printf("\t("); + dump_dwarf_block(re, v_block->bl_data, v_block->bl_len); + putchar(')'); + break; + + case DW_FORM_exprloc: + if (dwarf_formexprloc(attr_list[i], &v_udata, &v_expr, + &de) != DW_DLV_OK) { + warnx("dwarf_formexprloc failed: %s", + dwarf_errmsg(de)); + continue; + } + printf("%ju byte block:", (uintmax_t) v_udata); + b = v_expr; + for (j = 0; (Dwarf_Unsigned) j < v_udata; j++) + printf(" %x", b[j]); + printf("\t("); + dump_dwarf_block(re, v_expr, v_udata); + putchar(')'); break; + + case DW_FORM_ref_sig8: + if (dwarf_formsig8(attr_list[i], &v_sig8, &de) != + DW_DLV_OK) { + warnx("dwarf_formsig8 failed: %s", + dwarf_errmsg(de)); + continue; + } + p = (uint8_t *)(uintptr_t) &v_sig8.signature[0]; + v_sig = re->dw_decode(&p, 8); + printf("signature: 0x%jx", (uintmax_t) v_sig); } switch (attr) { case DW_AT_encoding: if (dwarf_attrval_unsigned(die, attr, &ate, &de) != DW_DLV_OK) break; if (dwarf_get_ATE_name(ate, &ate_str) != DW_DLV_OK) - break; + ate_str = "DW_ATE_UNKNOWN"; printf("\t(%s)", &ate_str[strlen("DW_ATE_")]); break; + + case DW_AT_language: + if (dwarf_attrval_unsigned(die, attr, &lang, &de) != + DW_DLV_OK) + break; + if (dwarf_get_LANG_name(lang, &lang_str) != DW_DLV_OK) + break; + printf("\t(%s)", &lang_str[strlen("DW_LANG_")]); + break; + + case DW_AT_location: + case DW_AT_string_length: + case DW_AT_return_addr: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + switch (form) { + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_sec_offset: + printf("\t(location list)"); + break; + default: + break; + } + default: break; } putchar('\n'); } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) dump_dwarf_die(re, ret_die, level + 1); /* Search sibling. */ - ret = dwarf_siblingof(re->dbg, die, &ret_die, &de); + is_info = dwarf_get_die_infotypes_flag(die); + ret = dwarf_siblingof_b(re->dbg, die, &ret_die, is_info, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) dump_dwarf_die(re, ret_die, level); dwarf_dealloc(re->dbg, die, DW_DLA_DIE); } static void -dump_dwarf_info(struct readelf *re) +set_cu_context(struct readelf *re, Dwarf_Half psize, Dwarf_Half osize, + Dwarf_Half ver) +{ + + re->cu_psize = psize; + re->cu_osize = osize; + re->cu_ver = ver; +} + +static void +dump_dwarf_info(struct readelf *re, Dwarf_Bool is_info) { struct section *s; Dwarf_Die die; Dwarf_Error de; - Dwarf_Half tag, version, pointer_size; + Dwarf_Half tag, version, pointer_size, off_size; Dwarf_Off cu_offset, cu_length; Dwarf_Off aboff; - Elf_Data *d; - int i, elferr, ret; + Dwarf_Unsigned typeoff; + Dwarf_Sig8 sig8; + Dwarf_Unsigned sig; + uint8_t *p; + const char *sn; + int i, ret; - printf("\nDump of debug contents of section .debug_info:\n"); + sn = is_info ? ".debug_info" : ".debug_types"; s = NULL; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; - if (s->name != NULL && !strcmp(s->name, ".debug_info")) + if (s->name != NULL && !strcmp(s->name, sn)) break; } if ((size_t) i >= re->shnum) return; - (void) elf_errno(); - if ((d = elf_getdata(s->scn, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - warnx("elf_getdata failed: %s", elf_errmsg(-1)); - return; - } - if (d->d_size <= 0) - return; + do { + printf("\nDump of debug contents of section %s:\n", sn); + + while ((ret = dwarf_next_cu_header_c(re->dbg, is_info, NULL, + &version, &aboff, &pointer_size, &off_size, NULL, &sig8, + &typeoff, NULL, &de)) == DW_DLV_OK) { + set_cu_context(re, pointer_size, off_size, version); + die = NULL; + while (dwarf_siblingof_b(re->dbg, die, &die, is_info, + &de) == DW_DLV_OK) { + if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { + warnx("dwarf_tag failed: %s", + dwarf_errmsg(de)); + continue; + } + /* XXX: What about DW_TAG_partial_unit? */ + if ((is_info && tag == DW_TAG_compile_unit) || + (!is_info && tag == DW_TAG_type_unit)) + break; + } + if (die == NULL && is_info) { + warnx("could not find DW_TAG_compile_unit " + "die"); + continue; + } else if (die == NULL && !is_info) { + warnx("could not find DW_TAG_type_unit die"); + continue; + } - while ((ret = dwarf_next_cu_header(re->dbg, NULL, &version, &aboff, - &pointer_size, NULL, &de)) == DW_DLV_OK) { - die = NULL; - while (dwarf_siblingof(re->dbg, die, &die, &de) == DW_DLV_OK) { - if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { - warnx("dwarf_tag failed: %s", + if (dwarf_die_CU_offset_range(die, &cu_offset, + &cu_length, &de) != DW_DLV_OK) { + warnx("dwarf_die_CU_offset failed: %s", dwarf_errmsg(de)); - return; + continue; } - /* XXX: What about DW_TAG_partial_unit? */ - if (tag == DW_TAG_compile_unit) - break; - } - if (die == NULL) { - warnx("could not find DW_TAG_compile_unit die"); - return; - } - if (dwarf_die_CU_offset_range(die, &cu_offset, &cu_length, - &de) != DW_DLV_OK) { - warnx("dwarf_die_CU_offset failed: %s", - dwarf_errmsg(de)); - continue; - } + cu_length -= off_size == 4 ? 4 : 12; - printf(" Compilation Unit @ %jd:\n", (intmax_t) cu_offset); - printf(" Length:\t\t%jd\n", (intmax_t) cu_length); - printf(" Version:\t\t%u\n", version); - printf(" Abbrev Offset:\t%ju\n", (uintmax_t) aboff); - printf(" Pointer Size:\t%u\n", pointer_size); + sig = 0; + if (!is_info) { + p = (uint8_t *)(uintptr_t) &sig8.signature[0]; + sig = re->dw_decode(&p, 8); + } - dump_dwarf_die(re, die, 0); - } - if (ret == DW_DLV_ERROR) - warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de)); + printf("\n Type Unit @ offset 0x%jx:\n", + (uintmax_t) cu_offset); + printf(" Length:\t\t%#jx (%d-bit)\n", + (uintmax_t) cu_length, off_size == 4 ? 32 : 64); + printf(" Version:\t\t%u\n", version); + printf(" Abbrev Offset:\t0x%jx\n", + (uintmax_t) aboff); + printf(" Pointer Size:\t%u\n", pointer_size); + if (!is_info) { + printf(" Signature:\t\t0x%016jx\n", + (uintmax_t) sig); + printf(" Type Offset:\t0x%jx\n", + (uintmax_t) typeoff); + } + + dump_dwarf_die(re, die, 0); + } + if (ret == DW_DLV_ERROR) + warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de)); + if (is_info) + break; + } while (dwarf_next_types_section(re->dbg, &de) == DW_DLV_OK); } static void dump_dwarf_abbrev(struct readelf *re) { Dwarf_Abbrev ab; Dwarf_Off aboff, atoff; Dwarf_Unsigned length, attr_count; Dwarf_Signed flag, form; Dwarf_Half tag, attr; Dwarf_Error de; const char *tag_str, *attr_str, *form_str; + char unk_tag[32], unk_attr[32], unk_form[32]; int i, j, ret; printf("\nContents of section .debug_abbrev:\n\n"); while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, &aboff, NULL, NULL, &de)) == DW_DLV_OK) { printf(" Number TAG\n"); i = 0; while ((ret = dwarf_get_abbrev(re->dbg, aboff, &ab, &length, &attr_count, &de)) == DW_DLV_OK) { if (length == 1) { dwarf_dealloc(re->dbg, ab, DW_DLA_ABBREV); break; } aboff += length; printf("%4d", ++i); if (dwarf_get_abbrev_tag(ab, &tag, &de) != DW_DLV_OK) { warnx("dwarf_get_abbrev_tag failed: %s", dwarf_errmsg(de)); goto next_abbrev; } if (dwarf_get_TAG_name(tag, &tag_str) != DW_DLV_OK) { - warnx("dwarf_get_TAG_name failed"); - goto next_abbrev; + snprintf(unk_tag, sizeof(unk_tag), + "[Unknown Tag: %#x]", tag); + tag_str = unk_tag; } if (dwarf_get_abbrev_children_flag(ab, &flag, &de) != DW_DLV_OK) { warnx("dwarf_get_abbrev_children_flag failed:" " %s", dwarf_errmsg(de)); goto next_abbrev; } printf(" %s %s\n", tag_str, flag ? "[has children]" : "[no children]"); for (j = 0; (Dwarf_Unsigned) j < attr_count; j++) { if (dwarf_get_abbrev_entry(ab, (Dwarf_Signed) j, &attr, &form, &atoff, &de) != DW_DLV_OK) { warnx("dwarf_get_abbrev_entry failed:" " %s", dwarf_errmsg(de)); continue; } if (dwarf_get_AT_name(attr, &attr_str) != DW_DLV_OK) { - warnx("dwarf_get_AT_name failed"); - continue; + snprintf(unk_attr, sizeof(unk_attr), + "[Unknown AT: %#x]", attr); + attr_str = unk_attr; } if (dwarf_get_FORM_name(form, &form_str) != DW_DLV_OK) { - warnx("dwarf_get_FORM_name failed"); - continue; + snprintf(unk_form, sizeof(unk_form), + "[Unknown Form: %#x]", + (Dwarf_Half) form); + form_str = unk_form; } printf(" %-18s %s\n", attr_str, form_str); } next_abbrev: dwarf_dealloc(re->dbg, ab, DW_DLA_ABBREV); } if (ret != DW_DLV_OK) warnx("dwarf_get_abbrev: %s", dwarf_errmsg(de)); } if (ret == DW_DLV_ERROR) warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de)); } static void dump_dwarf_pubnames(struct readelf *re) { struct section *s; Dwarf_Off die_off; Dwarf_Unsigned offset, length, nt_cu_offset, nt_cu_length; Dwarf_Signed cnt; Dwarf_Global *globs; Dwarf_Half nt_version; Dwarf_Error de; Elf_Data *d; char *glob_name; int i, dwarf_size, elferr; printf("\nContents of the .debug_pubnames section:\n"); s = NULL; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && !strcmp(s->name, ".debug_pubnames")) break; } if ((size_t) i >= re->shnum) return; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(-1)); return; } if (d->d_size <= 0) return; /* Read in .debug_pubnames section table header. */ offset = 0; length = re->dw_read(d, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = re->dw_read(d, &offset, 8); } else dwarf_size = 4; if (length > d->d_size - offset) { warnx("invalid .dwarf_pubnames section"); return; } nt_version = re->dw_read(d, &offset, 2); nt_cu_offset = re->dw_read(d, &offset, dwarf_size); nt_cu_length = re->dw_read(d, &offset, dwarf_size); printf(" Length:\t\t\t\t%ju\n", (uintmax_t) length); printf(" Version:\t\t\t\t%u\n", nt_version); printf(" Offset into .debug_info section:\t%ju\n", (uintmax_t) nt_cu_offset); printf(" Size of area in .debug_info section:\t%ju\n", (uintmax_t) nt_cu_length); if (dwarf_get_globals(re->dbg, &globs, &cnt, &de) != DW_DLV_OK) { warnx("dwarf_get_globals failed: %s", dwarf_errmsg(de)); return; } printf("\n Offset Name\n"); for (i = 0; i < cnt; i++) { if (dwarf_globname(globs[i], &glob_name, &de) != DW_DLV_OK) { warnx("dwarf_globname failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_global_die_offset(globs[i], &die_off, &de) != DW_DLV_OK) { warnx("dwarf_global_die_offset failed: %s", dwarf_errmsg(de)); continue; } printf(" %-11ju %s\n", (uintmax_t) die_off, glob_name); } } static void dump_dwarf_aranges(struct readelf *re) { struct section *s; Dwarf_Arange *aranges; Dwarf_Addr start; Dwarf_Unsigned offset, length, as_cu_offset; Dwarf_Off die_off; Dwarf_Signed cnt; Dwarf_Half as_version, as_addrsz, as_segsz; Dwarf_Error de; Elf_Data *d; int i, dwarf_size, elferr; printf("\nContents of section .debug_aranges:\n"); s = NULL; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && !strcmp(s->name, ".debug_aranges")) break; } if ((size_t) i >= re->shnum) return; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(-1)); return; } if (d->d_size <= 0) return; /* Read in the .debug_aranges section table header. */ offset = 0; length = re->dw_read(d, &offset, 4); if (length == 0xffffffff) { dwarf_size = 8; length = re->dw_read(d, &offset, 8); } else dwarf_size = 4; if (length > d->d_size - offset) { warnx("invalid .dwarf_aranges section"); return; } as_version = re->dw_read(d, &offset, 2); as_cu_offset = re->dw_read(d, &offset, dwarf_size); as_addrsz = re->dw_read(d, &offset, 1); as_segsz = re->dw_read(d, &offset, 1); printf(" Length:\t\t\t%ju\n", (uintmax_t) length); printf(" Version:\t\t\t%u\n", as_version); printf(" Offset into .debug_info:\t%ju\n", (uintmax_t) as_cu_offset); printf(" Pointer Size:\t\t\t%u\n", as_addrsz); printf(" Segment Size:\t\t\t%u\n", as_segsz); if (dwarf_get_aranges(re->dbg, &aranges, &cnt, &de) != DW_DLV_OK) { warnx("dwarf_get_aranges failed: %s", dwarf_errmsg(de)); return; } printf("\n Address Length\n"); for (i = 0; i < cnt; i++) { if (dwarf_get_arange_info(aranges[i], &start, &length, &die_off, &de) != DW_DLV_OK) { warnx("dwarf_get_arange_info failed: %s", dwarf_errmsg(de)); continue; } printf(" %08jx %ju\n", (uintmax_t) start, (uintmax_t) length); } } static void dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die, Dwarf_Addr base) { Dwarf_Attribute *attr_list; Dwarf_Ranges *ranges; Dwarf_Die ret_die; Dwarf_Error de; Dwarf_Addr base0; Dwarf_Half attr; Dwarf_Signed attr_count, cnt; Dwarf_Unsigned off, bytecnt; int i, j, ret; if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) != DW_DLV_OK) { if (ret == DW_DLV_ERROR) warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de)); goto cont_search; } for (i = 0; i < attr_count; i++) { if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) { warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de)); continue; } if (attr != DW_AT_ranges) continue; if (dwarf_formudata(attr_list[i], &off, &de) != DW_DLV_OK) { warnx("dwarf_formudata failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_get_ranges(re->dbg, (Dwarf_Off) off, &ranges, &cnt, &bytecnt, &de) != DW_DLV_OK) continue; base0 = base; for (j = 0; j < cnt; j++) { printf(" %08jx ", (uintmax_t) off); if (ranges[j].dwr_type == DW_RANGES_END) { printf("%s\n", ""); continue; } else if (ranges[j].dwr_type == DW_RANGES_ADDRESS_SELECTION) { base0 = ranges[j].dwr_addr2; continue; } if (re->ec == ELFCLASS32) printf("%08jx %08jx\n", ranges[j].dwr_addr1 + base0, ranges[j].dwr_addr2 + base0); else printf("%016jx %016jx\n", ranges[j].dwr_addr1 + base0, ranges[j].dwr_addr2 + base0); } } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) dump_dwarf_ranges_foreach(re, ret_die, base); /* Search sibling. */ ret = dwarf_siblingof(re->dbg, die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) dump_dwarf_ranges_foreach(re, ret_die, base); } static void dump_dwarf_ranges(struct readelf *re) { Dwarf_Ranges *ranges; Dwarf_Die die; Dwarf_Signed cnt; Dwarf_Unsigned bytecnt; Dwarf_Half tag; Dwarf_Error de; Dwarf_Unsigned lowpc; int ret; if (dwarf_get_ranges(re->dbg, 0, &ranges, &cnt, &bytecnt, &de) != DW_DLV_OK) return; printf("Contents of the .debug_ranges section:\n\n"); if (re->ec == ELFCLASS32) printf(" %-8s %-8s %s\n", "Offset", "Begin", "End"); else printf(" %-8s %-16s %s\n", "Offset", "Begin", "End"); while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { die = NULL; if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK) continue; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); continue; } /* XXX: What about DW_TAG_partial_unit? */ lowpc = 0; if (tag == DW_TAG_compile_unit) { if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lowpc, &de) != DW_DLV_OK) lowpc = 0; } dump_dwarf_ranges_foreach(re, die, (Dwarf_Addr) lowpc); } putchar('\n'); } static void dump_dwarf_macinfo(struct readelf *re) { Dwarf_Unsigned offset; Dwarf_Signed cnt; Dwarf_Macro_Details *md; Dwarf_Error de; const char *mi_str; + char unk_mi[32]; int i; #define _MAX_MACINFO_ENTRY 65535 printf("\nContents of section .debug_macinfo:\n\n"); offset = 0; while (dwarf_get_macro_details(re->dbg, offset, _MAX_MACINFO_ENTRY, &cnt, &md, &de) == DW_DLV_OK) { for (i = 0; i < cnt; i++) { offset = md[i].dmd_offset + 1; if (md[i].dmd_type == 0) break; if (dwarf_get_MACINFO_name(md[i].dmd_type, &mi_str) != DW_DLV_OK) { - warnx("dwarf_get_MACINFO_name failed: %s", - dwarf_errmsg(de)); - continue; + snprintf(unk_mi, sizeof(unk_mi), + "[Unknown MACINFO: %#x]", md[i].dmd_type); + mi_str = unk_mi; } printf(" %s", mi_str); switch (md[i].dmd_type) { case DW_MACINFO_define: case DW_MACINFO_undef: printf(" - lineno : %jd macro : %s\n", (intmax_t) md[i].dmd_lineno, md[i].dmd_macro); break; case DW_MACINFO_start_file: printf(" - lineno : %jd filenum : %jd\n", (intmax_t) md[i].dmd_lineno, (intmax_t) md[i].dmd_fileindex); break; default: putchar('\n'); break; } } } #undef _MAX_MACINFO_ENTRY } static void -dump_dwarf_frame_inst(Dwarf_Cie cie, uint8_t *insts, Dwarf_Unsigned len, - Dwarf_Unsigned caf, Dwarf_Signed daf, Dwarf_Addr pc, Dwarf_Debug dbg) +dump_dwarf_frame_inst(struct readelf *re, Dwarf_Cie cie, uint8_t *insts, + Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, Dwarf_Addr pc, + Dwarf_Debug dbg) { Dwarf_Frame_Op *oplist; Dwarf_Signed opcnt, delta; Dwarf_Small op; Dwarf_Error de; const char *op_str; + char unk_op[32]; int i; if (dwarf_expand_frame_instructions(cie, insts, len, &oplist, &opcnt, &de) != DW_DLV_OK) { warnx("dwarf_expand_frame_instructions failed: %s", dwarf_errmsg(de)); return; } for (i = 0; i < opcnt; i++) { if (oplist[i].fp_base_op != 0) op = oplist[i].fp_base_op << 6; else op = oplist[i].fp_extended_op; if (dwarf_get_CFA_name(op, &op_str) != DW_DLV_OK) { - warnx("dwarf_get_CFA_name failed: %s", - dwarf_errmsg(de)); - continue; + snprintf(unk_op, sizeof(unk_op), "[Unknown CFA: %#x]", + op); + op_str = unk_op; } printf(" %s", op_str); switch (op) { case DW_CFA_advance_loc: delta = oplist[i].fp_offset * caf; pc += delta; printf(": %ju to %08jx", (uintmax_t) delta, (uintmax_t) pc); break; case DW_CFA_offset: case DW_CFA_offset_extended: case DW_CFA_offset_extended_sf: delta = oplist[i].fp_offset * daf; - printf(": r%u at cfa%+jd", oplist[i].fp_register, + printf(": r%u (%s) at cfa%+jd", oplist[i].fp_register, + dwarf_regname(re, oplist[i].fp_register), (intmax_t) delta); break; case DW_CFA_restore: - printf(": r%u", oplist[i].fp_register); + printf(": r%u (%s)", oplist[i].fp_register, + dwarf_regname(re, oplist[i].fp_register)); break; case DW_CFA_set_loc: pc = oplist[i].fp_offset; printf(": to %08jx", (uintmax_t) pc); break; case DW_CFA_advance_loc1: case DW_CFA_advance_loc2: case DW_CFA_advance_loc4: pc += oplist[i].fp_offset; printf(": %jd to %08jx", (intmax_t) oplist[i].fp_offset, (uintmax_t) pc); break; case DW_CFA_def_cfa: - printf(": r%u ofs %ju", oplist[i].fp_register, + printf(": r%u (%s) ofs %ju", oplist[i].fp_register, + dwarf_regname(re, oplist[i].fp_register), (uintmax_t) oplist[i].fp_offset); break; case DW_CFA_def_cfa_sf: - printf(": r%u ofs %jd", oplist[i].fp_register, + printf(": r%u (%s) ofs %jd", oplist[i].fp_register, + dwarf_regname(re, oplist[i].fp_register), (intmax_t) (oplist[i].fp_offset * daf)); break; case DW_CFA_def_cfa_register: - printf(": r%u", oplist[i].fp_register); + printf(": r%u (%s)", oplist[i].fp_register, + dwarf_regname(re, oplist[i].fp_register)); break; case DW_CFA_def_cfa_offset: printf(": %ju", (uintmax_t) oplist[i].fp_offset); break; case DW_CFA_def_cfa_offset_sf: printf(": %jd", (intmax_t) (oplist[i].fp_offset * daf)); break; default: break; } putchar('\n'); } dwarf_dealloc(dbg, oplist, DW_DLA_FRAME_BLOCK); } static char * -get_regoff_str(Dwarf_Half reg, Dwarf_Addr off) +get_regoff_str(struct readelf *re, Dwarf_Half reg, Dwarf_Addr off) { static char rs[16]; if (reg == DW_FRAME_UNDEFINED_VAL || reg == DW_FRAME_REG_INITIAL_VALUE) snprintf(rs, sizeof(rs), "%c", 'u'); else if (reg == DW_FRAME_CFA_COL) snprintf(rs, sizeof(rs), "c%+jd", (intmax_t) off); else - snprintf(rs, sizeof(rs), "r%u%+jd", reg, (intmax_t) off); + snprintf(rs, sizeof(rs), "%s%+jd", dwarf_regname(re, reg), + (intmax_t) off); return (rs); } static int -dump_dwarf_frame_regtable(Dwarf_Fde fde, Dwarf_Addr pc, Dwarf_Unsigned func_len, - Dwarf_Half cie_ra) +dump_dwarf_frame_regtable(struct readelf *re, Dwarf_Fde fde, Dwarf_Addr pc, + Dwarf_Unsigned func_len, Dwarf_Half cie_ra) { Dwarf_Regtable rt; Dwarf_Addr row_pc, end_pc, pre_pc, cur_pc; Dwarf_Error de; - char rn[16]; char *vec; int i; #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7)) #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7))) #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7))) #define RT(x) rt.rules[(x)] vec = calloc((DW_REG_TABLE_SIZE + 7) / 8, 1); if (vec == NULL) err(EXIT_FAILURE, "calloc failed"); pre_pc = ~((Dwarf_Addr) 0); cur_pc = pc; end_pc = pc + func_len; for (; cur_pc < end_pc; cur_pc++) { if (dwarf_get_fde_info_for_all_regs(fde, cur_pc, &rt, &row_pc, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_info_for_all_regs failed: %s\n", dwarf_errmsg(de)); return (-1); } if (row_pc == pre_pc) continue; pre_pc = row_pc; for (i = 1; i < DW_REG_TABLE_SIZE; i++) { if (rt.rules[i].dw_regnum != DW_FRAME_REG_INITIAL_VALUE) BIT_SET(vec, i); } } printf(" LOC CFA "); for (i = 1; i < DW_REG_TABLE_SIZE; i++) { if (BIT_ISSET(vec, i)) { if ((Dwarf_Half) i == cie_ra) printf("ra "); - else { - snprintf(rn, sizeof(rn), "r%d", i); - printf("%-5s", rn); - } + else + printf("%-5s", + dwarf_regname(re, (unsigned int) i)); } } putchar('\n'); pre_pc = ~((Dwarf_Addr) 0); cur_pc = pc; end_pc = pc + func_len; for (; cur_pc < end_pc; cur_pc++) { if (dwarf_get_fde_info_for_all_regs(fde, cur_pc, &rt, &row_pc, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_info_for_all_regs failed: %s\n", dwarf_errmsg(de)); return (-1); } if (row_pc == pre_pc) continue; pre_pc = row_pc; printf("%08jx ", (uintmax_t) row_pc); - printf("%-8s ", get_regoff_str(RT(0).dw_regnum, + printf("%-8s ", get_regoff_str(re, RT(0).dw_regnum, RT(0).dw_offset)); for (i = 1; i < DW_REG_TABLE_SIZE; i++) { if (BIT_ISSET(vec, i)) { - printf("%-5s", get_regoff_str(RT(i).dw_regnum, - RT(i).dw_offset)); + printf("%-5s", get_regoff_str(re, + RT(i).dw_regnum, RT(i).dw_offset)); } } putchar('\n'); } free(vec); return (0); #undef BIT_SET #undef BIT_CLR #undef BIT_ISSET #undef RT } static void dump_dwarf_frame_section(struct readelf *re, struct section *s, int alt) { Dwarf_Cie *cie_list, cie, pre_cie; Dwarf_Fde *fde_list, fde; Dwarf_Off cie_offset, fde_offset; Dwarf_Unsigned cie_length, fde_instlen; Dwarf_Unsigned cie_caf, cie_daf, cie_instlen, func_len, fde_length; Dwarf_Signed cie_count, fde_count, cie_index; Dwarf_Addr low_pc; Dwarf_Half cie_ra; Dwarf_Small cie_version; Dwarf_Ptr fde_addr, fde_inst, cie_inst; char *cie_aug, c; int i, eh_frame; Dwarf_Error de; printf("\nThe section %s contains:\n\n", s->name); if (!strcmp(s->name, ".debug_frame")) { eh_frame = 0; if (dwarf_get_fde_list(re->dbg, &cie_list, &cie_count, &fde_list, &fde_count, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_list failed: %s", dwarf_errmsg(de)); return; } } else if (!strcmp(s->name, ".eh_frame")) { eh_frame = 1; if (dwarf_get_fde_list_eh(re->dbg, &cie_list, &cie_count, &fde_list, &fde_count, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_list_eh failed: %s", dwarf_errmsg(de)); return; } } else return; pre_cie = NULL; for (i = 0; i < fde_count; i++) { if (dwarf_get_fde_n(fde_list, i, &fde, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_n failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_get_cie_of_fde(fde, &cie, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_n failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_get_fde_range(fde, &low_pc, &func_len, &fde_addr, &fde_length, &cie_offset, &cie_index, &fde_offset, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_range failed: %s", dwarf_errmsg(de)); continue; } if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_instlen, &de) != DW_DLV_OK) { warnx("dwarf_get_fde_instr_bytes failed: %s", dwarf_errmsg(de)); continue; } if (pre_cie == NULL || cie != pre_cie) { pre_cie = cie; if (dwarf_get_cie_info(cie, &cie_length, &cie_version, &cie_aug, &cie_caf, &cie_daf, &cie_ra, &cie_inst, &cie_instlen, &de) != DW_DLV_OK) { warnx("dwarf_get_cie_info failed: %s", dwarf_errmsg(de)); continue; } printf("%08jx %08jx %8.8jx CIE", (uintmax_t) cie_offset, (uintmax_t) cie_length, (uintmax_t) (eh_frame ? 0 : ~0U)); if (!alt) { putchar('\n'); printf(" Version:\t\t\t%u\n", cie_version); printf(" Augmentation:\t\t\t\""); while ((c = *cie_aug++) != '\0') putchar(c); printf("\"\n"); printf(" Code alignment factor:\t%ju\n", (uintmax_t) cie_caf); printf(" Data alignment factor:\t%jd\n", (intmax_t) cie_daf); printf(" Return address column:\t%ju\n", (uintmax_t) cie_ra); putchar('\n'); - dump_dwarf_frame_inst(cie, cie_inst, + dump_dwarf_frame_inst(re, cie, cie_inst, cie_instlen, cie_caf, cie_daf, 0, re->dbg); putchar('\n'); } else { printf(" \""); while ((c = *cie_aug++) != '\0') putchar(c); putchar('"'); printf(" cf=%ju df=%jd ra=%ju\n", (uintmax_t) cie_caf, (uintmax_t) cie_daf, (uintmax_t) cie_ra); - dump_dwarf_frame_regtable(fde, low_pc, 1, + dump_dwarf_frame_regtable(re, fde, low_pc, 1, cie_ra); putchar('\n'); } } printf("%08jx %08jx %08jx FDE cie=%08jx pc=%08jx..%08jx\n", (uintmax_t) fde_offset, (uintmax_t) fde_length, (uintmax_t) cie_offset, (uintmax_t) (eh_frame ? fde_offset + 4 - cie_offset : cie_offset), (uintmax_t) low_pc, (uintmax_t) (low_pc + func_len)); if (!alt) - dump_dwarf_frame_inst(cie, fde_inst, fde_instlen, + dump_dwarf_frame_inst(re, cie, fde_inst, fde_instlen, cie_caf, cie_daf, low_pc, re->dbg); else - dump_dwarf_frame_regtable(fde, low_pc, func_len, + dump_dwarf_frame_regtable(re, fde, low_pc, func_len, cie_ra); putchar('\n'); } } static void dump_dwarf_frame(struct readelf *re, int alt) { struct section *s; int i; (void) dwarf_set_frame_cfa_value(re->dbg, DW_FRAME_CFA_COL); for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && (!strcmp(s->name, ".debug_frame") || !strcmp(s->name, ".eh_frame"))) dump_dwarf_frame_section(re, s, alt); } } static void dump_dwarf_str(struct readelf *re) { struct section *s; Elf_Data *d; unsigned char *p; int elferr, end, i, j; printf("\nContents of section .debug_str:\n"); s = NULL; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->name != NULL && !strcmp(s->name, ".debug_str")) break; } if ((size_t) i >= re->shnum) return; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(-1)); return; } if (d->d_size <= 0) return; for (i = 0, p = d->d_buf; (size_t) i < d->d_size; i += 16) { printf(" 0x%08x", (unsigned int) i); if ((size_t) i + 16 > d->d_size) end = d->d_size; else end = i + 16; for (j = i; j < i + 16; j++) { if ((j - i) % 4 == 0) putchar(' '); if (j >= end) { printf(" "); continue; } printf("%02x", (uint8_t) p[j]); } putchar(' '); for (j = i; j < end; j++) { if (isprint(p[j])) putchar(p[j]); else if (p[j] == 0) putchar('.'); else putchar(' '); } putchar('\n'); } } struct loc_at { Dwarf_Attribute la_at; Dwarf_Unsigned la_off; Dwarf_Unsigned la_lowpc; + Dwarf_Half la_cu_psize; + Dwarf_Half la_cu_osize; + Dwarf_Half la_cu_ver; TAILQ_ENTRY(loc_at) la_next; }; static TAILQ_HEAD(, loc_at) lalist = TAILQ_HEAD_INITIALIZER(lalist); static void search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc) { Dwarf_Attribute *attr_list; Dwarf_Die ret_die; Dwarf_Unsigned off; + Dwarf_Off ref; Dwarf_Signed attr_count; Dwarf_Half attr, form; + Dwarf_Bool is_info; Dwarf_Error de; struct loc_at *la, *nla; int i, ret; + is_info = dwarf_get_die_infotypes_flag(die); + if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) != DW_DLV_OK) { if (ret == DW_DLV_ERROR) warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de)); goto cont_search; } for (i = 0; i < attr_count; i++) { if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) { warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de)); continue; } if (attr != DW_AT_location && attr != DW_AT_string_length && attr != DW_AT_return_addr && attr != DW_AT_data_member_location && attr != DW_AT_frame_base && attr != DW_AT_segment && attr != DW_AT_static_link && attr != DW_AT_use_location && attr != DW_AT_vtable_elem_location) continue; if (dwarf_whatform(attr_list[i], &form, &de) != DW_DLV_OK) { warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); continue; } - if (form != DW_FORM_data4 && form != DW_FORM_data8) - continue; - if (dwarf_formudata(attr_list[i], &off, &de) != DW_DLV_OK) { - warnx("dwarf_formudata failed: %s", dwarf_errmsg(de)); + if (form == DW_FORM_data4 || form == DW_FORM_data8) { + if (dwarf_formudata(attr_list[i], &off, &de) != + DW_DLV_OK) { + warnx("dwarf_formudata failed: %s", + dwarf_errmsg(de)); + continue; + } + } else if (form == DW_FORM_sec_offset) { + if (dwarf_global_formref(attr_list[i], &ref, &de) != + DW_DLV_OK) { + warnx("dwarf_global_formref failed: %s", + dwarf_errmsg(de)); + continue; + } + off = ref; + } else continue; - } + TAILQ_FOREACH(la, &lalist, la_next) { if (off == la->la_off) break; if (off < la->la_off) { if ((nla = malloc(sizeof(*nla))) == NULL) err(EXIT_FAILURE, "malloc failed"); nla->la_at = attr_list[i]; nla->la_off = off; nla->la_lowpc = lowpc; + nla->la_cu_psize = re->cu_psize; + nla->la_cu_osize = re->cu_osize; + nla->la_cu_ver = re->cu_ver; TAILQ_INSERT_BEFORE(la, nla, la_next); break; } } if (la == NULL) { if ((nla = malloc(sizeof(*nla))) == NULL) err(EXIT_FAILURE, "malloc failed"); nla->la_at = attr_list[i]; nla->la_off = off; nla->la_lowpc = lowpc; + nla->la_cu_psize = re->cu_psize; + nla->la_cu_osize = re->cu_osize; + nla->la_cu_ver = re->cu_ver; TAILQ_INSERT_TAIL(&lalist, nla, la_next); } } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_loclist_at(re, ret_die, lowpc); /* Search sibling. */ - ret = dwarf_siblingof(re->dbg, die, &ret_die, &de); + ret = dwarf_siblingof_b(re->dbg, die, &ret_die, is_info, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_loclist_at(re, ret_die, lowpc); } +static void +dump_dwarf_loc(struct readelf *re, Dwarf_Loc *lr) +{ + const char *op_str; + char unk_op[32]; + uint8_t *b, n; + int i; + + if (dwarf_get_OP_name(lr->lr_atom, &op_str) != + DW_DLV_OK) { + snprintf(unk_op, sizeof(unk_op), + "[Unknown OP: %#x]", lr->lr_atom); + op_str = unk_op; + } + + printf("%s", op_str); + + switch (lr->lr_atom) { + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + printf(" (%s)", dwarf_regname(re, lr->lr_atom - DW_OP_reg0)); + break; + + case DW_OP_deref: + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + case DW_OP_dup: + case DW_OP_drop: + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + case DW_OP_nop: + case DW_OP_push_object_address: + case DW_OP_form_tls_address: + case DW_OP_call_frame_cfa: + case DW_OP_stack_value: + case DW_OP_GNU_push_tls_address: + case DW_OP_GNU_uninit: + break; + + case DW_OP_const1u: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + case DW_OP_const2u: + case DW_OP_bra: + case DW_OP_skip: + case DW_OP_const4u: + case DW_OP_const8u: + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + printf(": %ju", (uintmax_t) + lr->lr_number); + break; + + case DW_OP_const1s: + case DW_OP_const2s: + case DW_OP_const4s: + case DW_OP_const8s: + case DW_OP_consts: + printf(": %jd", (intmax_t) + lr->lr_number); + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + printf(" (%s): %jd", + dwarf_regname(re, lr->lr_atom - DW_OP_breg0), + (intmax_t) lr->lr_number); + break; + + case DW_OP_fbreg: + printf(": %jd", (intmax_t) + lr->lr_number); + break; + + case DW_OP_bregx: + printf(": %ju (%s) %jd", + (uintmax_t) lr->lr_number, + dwarf_regname(re, (unsigned int) lr->lr_number), + (intmax_t) lr->lr_number2); + break; + + case DW_OP_addr: + case DW_OP_GNU_encoded_addr: + printf(": %#jx", (uintmax_t) + lr->lr_number); + break; + + case DW_OP_GNU_implicit_pointer: + printf(": <0x%jx> %jd", (uintmax_t) lr->lr_number, + (intmax_t) lr->lr_number2); + break; + + case DW_OP_implicit_value: + printf(": %ju byte block:", (uintmax_t) lr->lr_number); + b = (uint8_t *)(uintptr_t) lr->lr_number2; + for (i = 0; (Dwarf_Unsigned) i < lr->lr_number; i++) + printf(" %x", b[i]); + break; + + case DW_OP_GNU_entry_value: + printf(": ("); + dump_dwarf_block(re, (uint8_t *)(uintptr_t) lr->lr_number2, + lr->lr_number); + putchar(')'); + break; + + case DW_OP_GNU_const_type: + printf(": <0x%jx> ", (uintmax_t) lr->lr_number); + b = (uint8_t *)(uintptr_t) lr->lr_number2; + n = *b; + for (i = 1; (uint8_t) i < n; i++) + printf(" %x", b[i]); + break; + + case DW_OP_GNU_regval_type: + printf(": %ju (%s) <0x%jx>", (uintmax_t) lr->lr_number, + dwarf_regname(re, (unsigned int) lr->lr_number), + (uintmax_t) lr->lr_number2); + break; + + case DW_OP_GNU_convert: + case DW_OP_GNU_deref_type: + case DW_OP_GNU_parameter_ref: + case DW_OP_GNU_reinterpret: + printf(": <0x%jx>", (uintmax_t) lr->lr_number); + break; + + default: + break; + } +} + +static void +dump_dwarf_block(struct readelf *re, uint8_t *b, Dwarf_Unsigned len) +{ + Dwarf_Locdesc *llbuf; + Dwarf_Signed lcnt; + Dwarf_Error de; + int i; + + if (dwarf_loclist_from_expr_b(re->dbg, b, len, re->cu_psize, + re->cu_osize, re->cu_ver, &llbuf, &lcnt, &de) != DW_DLV_OK) { + warnx("dwarf_loclist_form_expr_b: %s", dwarf_errmsg(de)); + return; + } + + for (i = 0; (Dwarf_Half) i < llbuf->ld_cents; i++) { + dump_dwarf_loc(re, &llbuf->ld_s[i]); + if (i < llbuf->ld_cents - 1) + printf("; "); + } + + dwarf_dealloc(re->dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(re->dbg, llbuf, DW_DLA_LOCDESC); +} + static void dump_dwarf_loclist(struct readelf *re) { Dwarf_Die die; Dwarf_Locdesc **llbuf; Dwarf_Unsigned lowpc; Dwarf_Signed lcnt; - Dwarf_Half tag; + Dwarf_Half tag, version, pointer_size, off_size; Dwarf_Error de; - Dwarf_Loc *lr; struct loc_at *la; - const char *op_str; int i, j, ret; printf("\nContents of section .debug_loc:\n"); - while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL, - NULL, &de)) == DW_DLV_OK) { + /* Search .debug_info section. */ + while ((ret = dwarf_next_cu_header_b(re->dbg, NULL, &version, NULL, + &pointer_size, &off_size, NULL, NULL, &de)) == DW_DLV_OK) { + set_cu_context(re, pointer_size, off_size, version); die = NULL; if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK) continue; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); continue; } /* XXX: What about DW_TAG_partial_unit? */ lowpc = 0; if (tag == DW_TAG_compile_unit) { - if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lowpc, - &de) != DW_DLV_OK) + if (dwarf_attrval_unsigned(die, DW_AT_low_pc, + &lowpc, &de) != DW_DLV_OK) lowpc = 0; } /* Search attributes for reference to .debug_loc section. */ search_loclist_at(re, die, lowpc); } if (ret == DW_DLV_ERROR) warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de)); + /* Search .debug_types section. */ + do { + while ((ret = dwarf_next_cu_header_c(re->dbg, 0, NULL, + &version, NULL, &pointer_size, &off_size, NULL, NULL, + NULL, NULL, &de)) == DW_DLV_OK) { + set_cu_context(re, pointer_size, off_size, version); + die = NULL; + if (dwarf_siblingof(re->dbg, die, &die, &de) != + DW_DLV_OK) + continue; + if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { + warnx("dwarf_tag failed: %s", + dwarf_errmsg(de)); + continue; + } + + lowpc = 0; + if (tag == DW_TAG_type_unit) { + if (dwarf_attrval_unsigned(die, DW_AT_low_pc, + &lowpc, &de) != DW_DLV_OK) + lowpc = 0; + } + + /* + * Search attributes for reference to .debug_loc + * section. + */ + search_loclist_at(re, die, lowpc); + } + if (ret == DW_DLV_ERROR) + warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de)); + } while (dwarf_next_types_section(re->dbg, &de) == DW_DLV_OK); + if (TAILQ_EMPTY(&lalist)) return; printf(" Offset Begin End Expression\n"); TAILQ_FOREACH(la, &lalist, la_next) { if (dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de) != DW_DLV_OK) { warnx("dwarf_loclist_n failed: %s", dwarf_errmsg(de)); continue; } + set_cu_context(re, la->la_cu_psize, la->la_cu_osize, + la->la_cu_ver); for (i = 0; i < lcnt; i++) { printf(" %8.8jx ", la->la_off); if (llbuf[i]->ld_lopc == 0 && llbuf[i]->ld_hipc == 0) { printf("\n"); continue; } /* TODO: handle base selection entry. */ printf("%8.8jx %8.8jx ", (uintmax_t) (la->la_lowpc + llbuf[i]->ld_lopc), (uintmax_t) (la->la_lowpc + llbuf[i]->ld_hipc)); putchar('('); for (j = 0; (Dwarf_Half) j < llbuf[i]->ld_cents; j++) { - lr = &llbuf[i]->ld_s[j]; - if (dwarf_get_OP_name(lr->lr_atom, &op_str) != - DW_DLV_OK) { - warnx("dwarf_get_OP_name failed: %s", - dwarf_errmsg(de)); - continue; - } - - printf("%s", op_str); - - switch (lr->lr_atom) { - /* Operations with no operands. */ - case DW_OP_deref: - case DW_OP_reg0: - case DW_OP_reg1: - case DW_OP_reg2: - case DW_OP_reg3: - case DW_OP_reg4: - case DW_OP_reg5: - case DW_OP_reg6: - case DW_OP_reg7: - case DW_OP_reg8: - case DW_OP_reg9: - case DW_OP_reg10: - case DW_OP_reg11: - case DW_OP_reg12: - case DW_OP_reg13: - case DW_OP_reg14: - case DW_OP_reg15: - case DW_OP_reg16: - case DW_OP_reg17: - case DW_OP_reg18: - case DW_OP_reg19: - case DW_OP_reg20: - case DW_OP_reg21: - case DW_OP_reg22: - case DW_OP_reg23: - case DW_OP_reg24: - case DW_OP_reg25: - case DW_OP_reg26: - case DW_OP_reg27: - case DW_OP_reg28: - case DW_OP_reg29: - case DW_OP_reg30: - case DW_OP_reg31: - case DW_OP_lit0: - case DW_OP_lit1: - case DW_OP_lit2: - case DW_OP_lit3: - case DW_OP_lit4: - case DW_OP_lit5: - case DW_OP_lit6: - case DW_OP_lit7: - case DW_OP_lit8: - case DW_OP_lit9: - case DW_OP_lit10: - case DW_OP_lit11: - case DW_OP_lit12: - case DW_OP_lit13: - case DW_OP_lit14: - case DW_OP_lit15: - case DW_OP_lit16: - case DW_OP_lit17: - case DW_OP_lit18: - case DW_OP_lit19: - case DW_OP_lit20: - case DW_OP_lit21: - case DW_OP_lit22: - case DW_OP_lit23: - case DW_OP_lit24: - case DW_OP_lit25: - case DW_OP_lit26: - case DW_OP_lit27: - case DW_OP_lit28: - case DW_OP_lit29: - case DW_OP_lit30: - case DW_OP_lit31: - case DW_OP_dup: - case DW_OP_drop: - case DW_OP_over: - case DW_OP_swap: - case DW_OP_rot: - case DW_OP_xderef: - case DW_OP_abs: - case DW_OP_and: - case DW_OP_div: - case DW_OP_minus: - case DW_OP_mod: - case DW_OP_mul: - case DW_OP_neg: - case DW_OP_not: - case DW_OP_or: - case DW_OP_plus: - case DW_OP_shl: - case DW_OP_shr: - case DW_OP_shra: - case DW_OP_xor: - case DW_OP_eq: - case DW_OP_ge: - case DW_OP_gt: - case DW_OP_le: - case DW_OP_lt: - case DW_OP_ne: - case DW_OP_nop: - break; - - case DW_OP_const1u: - case DW_OP_const1s: - case DW_OP_pick: - case DW_OP_deref_size: - case DW_OP_xderef_size: - case DW_OP_const2u: - case DW_OP_const2s: - case DW_OP_bra: - case DW_OP_skip: - case DW_OP_const4u: - case DW_OP_const4s: - case DW_OP_const8u: - case DW_OP_const8s: - case DW_OP_constu: - case DW_OP_plus_uconst: - case DW_OP_regx: - case DW_OP_piece: - printf(": %ju", (uintmax_t) - lr->lr_number); - break; - - case DW_OP_consts: - case DW_OP_breg0: - case DW_OP_breg1: - case DW_OP_breg2: - case DW_OP_breg3: - case DW_OP_breg4: - case DW_OP_breg5: - case DW_OP_breg6: - case DW_OP_breg7: - case DW_OP_breg8: - case DW_OP_breg9: - case DW_OP_breg10: - case DW_OP_breg11: - case DW_OP_breg12: - case DW_OP_breg13: - case DW_OP_breg14: - case DW_OP_breg15: - case DW_OP_breg16: - case DW_OP_breg17: - case DW_OP_breg18: - case DW_OP_breg19: - case DW_OP_breg20: - case DW_OP_breg21: - case DW_OP_breg22: - case DW_OP_breg23: - case DW_OP_breg24: - case DW_OP_breg25: - case DW_OP_breg26: - case DW_OP_breg27: - case DW_OP_breg28: - case DW_OP_breg29: - case DW_OP_breg30: - case DW_OP_breg31: - case DW_OP_fbreg: - printf(": %jd", (intmax_t) - lr->lr_number); - break; - - case DW_OP_bregx: - printf(": %ju %jd", - (uintmax_t) lr->lr_number, - (intmax_t) lr->lr_number2); - break; - - case DW_OP_addr: - printf(": %#jx", (uintmax_t) - lr->lr_number); - break; - } + dump_dwarf_loc(re, &llbuf[i]->ld_s[j]); if (j < llbuf[i]->ld_cents - 1) - printf(", "); + printf("; "); } putchar(')'); if (llbuf[i]->ld_lopc == llbuf[i]->ld_hipc) printf(" (start == end)"); putchar('\n'); } + for (i = 0; i < lcnt; i++) { + dwarf_dealloc(re->dbg, llbuf[i]->ld_s, + DW_DLA_LOC_BLOCK); + dwarf_dealloc(re->dbg, llbuf[i], DW_DLA_LOCDESC); + } + dwarf_dealloc(re->dbg, llbuf, DW_DLA_LIST); } } /* * Retrieve a string using string table section index and the string offset. */ static const char* get_string(struct readelf *re, int strtab, size_t off) { const char *name; if ((name = elf_strptr(re->elf, strtab, off)) == NULL) return (""); return (name); } /* * Retrieve the name of a symbol using the section index of the symbol * table and the index of the symbol within that table. */ static const char * get_symbol_name(struct readelf *re, int symtab, int i) { struct section *s; const char *name; GElf_Sym sym; Elf_Data *data; int elferr; s = &re->sl[symtab]; if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM) return (""); (void) elf_errno(); if ((data = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return (""); } if (gelf_getsym(data, i, &sym) != &sym) return (""); /* Return section name for STT_SECTION symbol. */ if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && re->sl[sym.st_shndx].name != NULL) return (re->sl[sym.st_shndx].name); if ((name = elf_strptr(re->elf, s->link, sym.st_name)) == NULL) return (""); return (name); } static uint64_t get_symbol_value(struct readelf *re, int symtab, int i) { struct section *s; GElf_Sym sym; Elf_Data *data; int elferr; s = &re->sl[symtab]; if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM) return (0); (void) elf_errno(); if ((data = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return (0); } if (gelf_getsym(data, i, &sym) != &sym) return (0); return (sym.st_value); } static void hex_dump(struct readelf *re) { struct section *s; Elf_Data *d; uint8_t *buf; size_t sz, nbytes; uint64_t addr; int elferr, i, j; for (i = 1; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (find_dumpop(re, (size_t) i, s->name, HEX_DUMP, -1) == NULL) continue; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } if (d->d_size <= 0 || d->d_buf == NULL) { printf("\nSection '%s' has no data to dump.\n", s->name); continue; } buf = d->d_buf; sz = d->d_size; addr = s->addr; printf("\nHex dump of section '%s':\n", s->name); while (sz > 0) { printf(" 0x%8.8jx ", (uintmax_t)addr); nbytes = sz > 16? 16 : sz; for (j = 0; j < 16; j++) { if ((size_t)j < nbytes) printf("%2.2x", buf[j]); else printf(" "); if ((j & 3) == 3) printf(" "); } for (j = 0; (size_t)j < nbytes; j++) { if (isprint(buf[j])) printf("%c", buf[j]); else printf("."); } printf("\n"); buf += nbytes; addr += nbytes; sz -= nbytes; } } } static void str_dump(struct readelf *re) { struct section *s; Elf_Data *d; unsigned char *start, *end, *buf_end; unsigned int len; int i, j, elferr, found; for (i = 1; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (find_dumpop(re, (size_t) i, s->name, STR_DUMP, -1) == NULL) continue; (void) elf_errno(); if ((d = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } if (d->d_size <= 0 || d->d_buf == NULL) { printf("\nSection '%s' has no data to dump.\n", s->name); continue; } buf_end = (unsigned char *) d->d_buf + d->d_size; start = (unsigned char *) d->d_buf; found = 0; printf("\nString dump of section '%s':\n", s->name); for (;;) { while (start < buf_end && !isprint(*start)) start++; if (start >= buf_end) break; end = start + 1; while (end < buf_end && isprint(*end)) end++; printf(" [%6lx] ", (long) (start - (unsigned char *) d->d_buf)); len = end - start; for (j = 0; (unsigned int) j < len; j++) putchar(start[j]); putchar('\n'); found = 1; if (end >= buf_end) break; start = end + 1; } if (!found) printf(" No strings found in this section."); putchar('\n'); } } static void load_sections(struct readelf *re) { struct section *s; const char *name; Elf_Scn *scn; GElf_Shdr sh; size_t shstrndx, ndx; int elferr; /* Allocate storage for internal section list. */ if (!elf_getshnum(re->elf, &re->shnum)) { warnx("elf_getshnum failed: %s", elf_errmsg(-1)); return; } if (re->sl != NULL) free(re->sl); if ((re->sl = calloc(re->shnum, sizeof(*re->sl))) == NULL) err(EXIT_FAILURE, "calloc failed"); /* Get the index of .shstrtab section. */ if (!elf_getshstrndx(re->elf, &shstrndx)) { warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); return; } if ((scn = elf_getscn(re->elf, 0)) == NULL) { warnx("elf_getscn failed: %s", elf_errmsg(-1)); return; } (void) elf_errno(); do { if (gelf_getshdr(scn, &sh) == NULL) { warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); (void) elf_errno(); continue; } if ((name = elf_strptr(re->elf, shstrndx, sh.sh_name)) == NULL) { (void) elf_errno(); name = "ERROR"; } if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) { if ((elferr = elf_errno()) != 0) warnx("elf_ndxscn failed: %s", elf_errmsg(elferr)); continue; } if (ndx >= re->shnum) { warnx("section index of '%s' out of range", name); continue; } s = &re->sl[ndx]; s->name = name; s->scn = scn; s->off = sh.sh_offset; s->sz = sh.sh_size; s->entsize = sh.sh_entsize; s->align = sh.sh_addralign; s->type = sh.sh_type; s->flags = sh.sh_flags; s->addr = sh.sh_addr; s->link = sh.sh_link; s->info = sh.sh_info; } while ((scn = elf_nextscn(re->elf, scn)) != NULL); elferr = elf_errno(); if (elferr != 0) warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); } static void unload_sections(struct readelf *re) { if (re->sl != NULL) { free(re->sl); re->sl = NULL; } re->shnum = 0; re->vd_s = NULL; re->vn_s = NULL; re->vs_s = NULL; re->vs = NULL; re->vs_sz = 0; if (re->ver != NULL) { free(re->ver); re->ver = NULL; re->ver_sz = 0; } } static void dump_elf(struct readelf *re) { /* Fetch ELF header. No need to continue if it fails. */ if (gelf_getehdr(re->elf, &re->ehdr) == NULL) { warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); return; } if ((re->ec = gelf_getclass(re->elf)) == ELFCLASSNONE) { warnx("gelf_getclass failed: %s", elf_errmsg(-1)); return; } if (re->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) { re->dw_read = _read_msb; re->dw_decode = _decode_msb; } else { re->dw_read = _read_lsb; re->dw_decode = _decode_lsb; } if (re->options & ~RE_H) load_sections(re); if ((re->options & RE_VV) || (re->options & RE_S)) search_ver(re); if (re->options & RE_H) dump_ehdr(re); if (re->options & RE_L) dump_phdr(re); if (re->options & RE_SS) dump_shdr(re); if (re->options & RE_D) dump_dynamic(re); if (re->options & RE_R) dump_reloc(re); if (re->options & RE_S) dump_symtabs(re); if (re->options & RE_N) dump_notes(re); if (re->options & RE_II) dump_hash(re); if (re->options & RE_X) hex_dump(re); if (re->options & RE_P) str_dump(re); if (re->options & RE_VV) dump_ver(re); if (re->options & RE_AA) dump_arch_specific_info(re); if (re->options & RE_W) dump_dwarf(re); if (re->options & ~RE_H) unload_sections(re); } static void dump_dwarf(struct readelf *re) { int error; Dwarf_Error de; if (dwarf_elf_init(re->elf, DW_DLC_READ, NULL, NULL, &re->dbg, &de)) { if ((error = dwarf_errno(de)) != DW_DLE_DEBUG_INFO_NULL) errx(EXIT_FAILURE, "dwarf_elf_init failed: %s", dwarf_errmsg(de)); return; } if (re->dop & DW_A) dump_dwarf_abbrev(re); if (re->dop & DW_L) dump_dwarf_line(re); if (re->dop & DW_LL) dump_dwarf_line_decoded(re); - if (re->dop & DW_I) - dump_dwarf_info(re); + if (re->dop & DW_I) { + dump_dwarf_info(re, 0); + dump_dwarf_info(re, 1); + } if (re->dop & DW_P) dump_dwarf_pubnames(re); if (re->dop & DW_R) dump_dwarf_aranges(re); if (re->dop & DW_RR) dump_dwarf_ranges(re); if (re->dop & DW_M) dump_dwarf_macinfo(re); if (re->dop & DW_F) dump_dwarf_frame(re, 0); else if (re->dop & DW_FF) dump_dwarf_frame(re, 1); if (re->dop & DW_S) dump_dwarf_str(re); if (re->dop & DW_O) dump_dwarf_loclist(re); dwarf_finish(re->dbg, &de); } static void dump_ar(struct readelf *re, int fd) { Elf_Arsym *arsym; Elf_Arhdr *arhdr; Elf_Cmd cmd; Elf *e; size_t sz; off_t off; int i; re->ar = re->elf; if (re->options & RE_C) { if ((arsym = elf_getarsym(re->ar, &sz)) == NULL) { warnx("elf_getarsym() failed: %s", elf_errmsg(-1)); goto process_members; } printf("Index of archive %s: (%ju entries)\n", re->filename, (uintmax_t) sz - 1); off = 0; for (i = 0; (size_t) i < sz; i++) { if (arsym[i].as_name == NULL) break; if (arsym[i].as_off != off) { off = arsym[i].as_off; if (elf_rand(re->ar, off) != off) { warnx("elf_rand() failed: %s", elf_errmsg(-1)); continue; } if ((e = elf_begin(fd, ELF_C_READ, re->ar)) == NULL) { warnx("elf_begin() failed: %s", elf_errmsg(-1)); continue; } if ((arhdr = elf_getarhdr(e)) == NULL) { warnx("elf_getarhdr() failed: %s", elf_errmsg(-1)); elf_end(e); continue; } printf("Binary %s(%s) contains:\n", re->filename, arhdr->ar_name); } printf("\t%s\n", arsym[i].as_name); } if (elf_rand(re->ar, SARMAG) != SARMAG) { warnx("elf_rand() failed: %s", elf_errmsg(-1)); return; } } process_members: if ((re->options & ~RE_C) == 0) return; cmd = ELF_C_READ; while ((re->elf = elf_begin(fd, cmd, re->ar)) != NULL) { if ((arhdr = elf_getarhdr(re->elf)) == NULL) { warnx("elf_getarhdr() failed: %s", elf_errmsg(-1)); goto next_member; } if (strcmp(arhdr->ar_name, "/") == 0 || strcmp(arhdr->ar_name, "//") == 0 || strcmp(arhdr->ar_name, "__.SYMDEF") == 0) goto next_member; printf("\nFile: %s(%s)\n", re->filename, arhdr->ar_name); dump_elf(re); next_member: cmd = elf_next(re->elf); elf_end(re->elf); } re->elf = re->ar; } static void dump_object(struct readelf *re) { int fd; if ((fd = open(re->filename, O_RDONLY)) == -1) { warn("open %s failed", re->filename); return; } if ((re->flags & DISPLAY_FILENAME) != 0) printf("\nFile: %s\n", re->filename); if ((re->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warnx("elf_begin() failed: %s", elf_errmsg(-1)); return; } switch (elf_kind(re->elf)) { case ELF_K_NONE: warnx("Not an ELF file."); return; case ELF_K_ELF: dump_elf(re); break; case ELF_K_AR: dump_ar(re, fd); break; default: warnx("Internal: libelf returned unknown elf kind."); return; } elf_end(re->elf); } static void add_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t) { struct dumpop *d; if ((d = find_dumpop(re, si, sn, -1, t)) == NULL) { if ((d = calloc(1, sizeof(*d))) == NULL) err(EXIT_FAILURE, "calloc failed"); if (t == DUMP_BY_INDEX) d->u.si = si; else d->u.sn = sn; d->type = t; d->op = op; STAILQ_INSERT_TAIL(&re->v_dumpop, d, dumpop_list); } else d->op |= op; } static struct dumpop * find_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t) { struct dumpop *d; STAILQ_FOREACH(d, &re->v_dumpop, dumpop_list) { if ((op == -1 || op & d->op) && (t == -1 || (unsigned) t == d->type)) { if ((d->type == DUMP_BY_INDEX && d->u.si == si) || (d->type == DUMP_BY_NAME && !strcmp(d->u.sn, sn))) return (d); } } return (NULL); } static struct { const char *ln; char sn; int value; } dwarf_op[] = { {"rawline", 'l', DW_L}, {"decodedline", 'L', DW_LL}, {"info", 'i', DW_I}, {"abbrev", 'a', DW_A}, {"pubnames", 'p', DW_P}, {"aranges", 'r', DW_R}, {"ranges", 'r', DW_R}, {"Ranges", 'R', DW_RR}, {"macro", 'm', DW_M}, {"frames", 'f', DW_F}, - {"", 'F', DW_FF}, + {"frames-interp", 'F', DW_FF}, {"str", 's', DW_S}, {"loc", 'o', DW_O}, {NULL, 0, 0} }; static void parse_dwarf_op_short(struct readelf *re, const char *op) { int i; if (op == NULL) { re->dop |= DW_DEFAULT_OPTIONS; return; } for (; *op != '\0'; op++) { for (i = 0; dwarf_op[i].ln != NULL; i++) { if (dwarf_op[i].sn == *op) { re->dop |= dwarf_op[i].value; break; } } } } static void parse_dwarf_op_long(struct readelf *re, const char *op) { char *p, *token, *bp; int i; if (op == NULL) { re->dop |= DW_DEFAULT_OPTIONS; return; } if ((p = strdup(op)) == NULL) err(EXIT_FAILURE, "strdup failed"); bp = p; while ((token = strsep(&p, ",")) != NULL) { for (i = 0; dwarf_op[i].ln != NULL; i++) { if (!strcmp(token, dwarf_op[i].ln)) { re->dop |= dwarf_op[i].value; break; } } } free(bp); } static uint64_t _read_lsb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read) { uint64_t ret; uint8_t *src; src = (uint8_t *) d->d_buf + *offsetp; ret = 0; switch (bytes_to_read) { case 8: ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40; ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56; case 4: ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24; case 2: ret |= ((uint64_t) src[1]) << 8; case 1: ret |= src[0]; break; default: return (0); } *offsetp += bytes_to_read; return (ret); } static uint64_t _read_msb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read) { uint64_t ret; uint8_t *src; src = (uint8_t *) d->d_buf + *offsetp; switch (bytes_to_read) { case 1: ret = src[0]; break; case 2: ret = src[1] | ((uint64_t) src[0]) << 8; break; case 4: ret = src[3] | ((uint64_t) src[2]) << 8; ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24; break; case 8: ret = src[7] | ((uint64_t) src[6]) << 8; ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24; ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40; ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56; break; default: return (0); } *offsetp += bytes_to_read; return (ret); } static uint64_t _decode_lsb(uint8_t **data, int bytes_to_read) { uint64_t ret; uint8_t *src; src = *data; ret = 0; switch (bytes_to_read) { case 8: ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40; ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56; case 4: ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24; case 2: ret |= ((uint64_t) src[1]) << 8; case 1: ret |= src[0]; break; default: return (0); } *data += bytes_to_read; return (ret); } static uint64_t _decode_msb(uint8_t **data, int bytes_to_read) { uint64_t ret; uint8_t *src; src = *data; ret = 0; switch (bytes_to_read) { case 1: ret = src[0]; break; case 2: ret = src[1] | ((uint64_t) src[0]) << 8; break; case 4: ret = src[3] | ((uint64_t) src[2]) << 8; ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24; break; case 8: ret = src[7] | ((uint64_t) src[6]) << 8; ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24; ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40; ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56; break; default: return (0); break; } *data += bytes_to_read; return (ret); } static int64_t _decode_sleb128(uint8_t **dp) { int64_t ret = 0; uint8_t b; int shift = 0; uint8_t *src = *dp; do { b = *src++; ret |= ((b & 0x7f) << shift); shift += 7; } while ((b & 0x80) != 0); if (shift < 32 && (b & 0x40) != 0) ret |= (-1 << shift); *dp = src; return (ret); } static uint64_t _decode_uleb128(uint8_t **dp) { uint64_t ret = 0; uint8_t b; int shift = 0; uint8_t *src = *dp; do { b = *src++; ret |= ((b & 0x7f) << shift); shift += 7; } while ((b & 0x80) != 0); *dp = src; return (ret); } static void readelf_version(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } #define USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Display information about ELF objects and ar(1) archives.\n\n\ Options:\n\ -a | --all Equivalent to specifying options '-dhIlrsASV'.\n\ -c | --archive-index Print the archive symbol table for archives.\n\ -d | --dynamic Print the contents of SHT_DYNAMIC sections.\n\ -e | --headers Print all headers in the object.\n\ -g | --section-groups (accepted, but ignored)\n\ -h | --file-header Print the file header for the object.\n\ -l | --program-headers Print the PHDR table for the object.\n\ -n | --notes Print the contents of SHT_NOTE sections.\n\ -p INDEX | --string-dump=INDEX\n\ Print the contents of section at index INDEX.\n\ -r | --relocs Print relocation information.\n\ -s | --syms | --symbols Print symbol tables.\n\ -t | --section-details Print additional information about sections.\n\ -v | --version Print a version identifier and exit.\n\ -x INDEX | --hex-dump=INDEX\n\ Display contents of a section as hexadecimal.\n\ -A | --arch-specific (accepted, but ignored)\n\ -D | --use-dynamic Print the symbol table specified by the DT_SYMTAB\n\ entry in the \".dynamic\" section.\n\ -H | --help Print a help message.\n\ -I | --histogram Print information on bucket list lengths for \n\ hash sections.\n\ -N | --full-section-name (accepted, but ignored)\n\ -S | --sections | --section-headers\n\ Print information about section headers.\n\ -V | --version-info Print symbol versoning information.\n\ -W | --wide Print information without wrapping long lines.\n" static void readelf_usage(void) { fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } int main(int argc, char **argv) { struct readelf *re, re_storage; unsigned long si; int opt, i; char *ep; re = &re_storage; memset(re, 0, sizeof(*re)); STAILQ_INIT(&re->v_dumpop); while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:", longopts, NULL)) != -1) { switch(opt) { case '?': readelf_usage(); break; case 'A': re->options |= RE_AA; break; case 'a': re->options |= RE_AA | RE_D | RE_H | RE_II | RE_L | RE_R | RE_SS | RE_S | RE_VV; break; case 'c': re->options |= RE_C; break; case 'D': re->options |= RE_DD; break; case 'd': re->options |= RE_D; break; case 'e': re->options |= RE_H | RE_L | RE_SS; break; case 'g': re->options |= RE_G; break; case 'H': readelf_usage(); break; case 'h': re->options |= RE_H; break; case 'I': re->options |= RE_II; break; case 'i': /* Not implemented yet. */ break; case 'l': re->options |= RE_L; break; case 'N': re->options |= RE_NN; break; case 'n': re->options |= RE_N; break; case 'p': re->options |= RE_P; si = strtoul(optarg, &ep, 10); if (*ep == '\0') add_dumpop(re, (size_t) si, NULL, STR_DUMP, DUMP_BY_INDEX); else add_dumpop(re, 0, optarg, STR_DUMP, DUMP_BY_NAME); break; case 'r': re->options |= RE_R; break; case 'S': re->options |= RE_SS; break; case 's': re->options |= RE_S; break; case 't': re->options |= RE_T; break; case 'u': re->options |= RE_U; break; case 'V': re->options |= RE_VV; break; case 'v': readelf_version(); break; case 'W': re->options |= RE_WW; break; case 'w': re->options |= RE_W; parse_dwarf_op_short(re, optarg); break; case 'x': re->options |= RE_X; si = strtoul(optarg, &ep, 10); if (*ep == '\0') add_dumpop(re, (size_t) si, NULL, HEX_DUMP, DUMP_BY_INDEX); else add_dumpop(re, 0, optarg, HEX_DUMP, DUMP_BY_NAME); break; case OPTION_DEBUG_DUMP: re->options |= RE_W; parse_dwarf_op_long(re, optarg); } } argv += optind; argc -= optind; if (argc == 0 || re->options == 0) readelf_usage(); if (argc > 1) re->flags |= DISPLAY_FILENAME; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); for (i = 0; i < argc; i++) if (argv[i] != NULL) { re->filename = argv[i]; dump_object(re); } exit(EXIT_SUCCESS); } diff --git a/strings/strings.c b/strings/strings.c index c936d5c5374f..5964f64f19d5 100644 --- a/strings/strings.c +++ b/strings/strings.c @@ -1,454 +1,454 @@ /*- * Copyright (c) 2007 S.Sam Arun Raj * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: strings.c 2351 2011-12-19 11:20:37Z jkoshy $"); +ELFTC_VCSID("$Id: strings.c 3124 2014-12-21 05:46:28Z kaiwang27 $"); enum return_code { RETURN_OK, RETURN_NOINPUT, RETURN_SOFTWARE }; enum radix_style { RADIX_DECIMAL, RADIX_HEX, RADIX_OCTAL }; enum encoding_style { ENCODING_7BIT, ENCODING_8BIT, ENCODING_16BIT_BIG, ENCODING_16BIT_LITTLE, ENCODING_32BIT_BIG, ENCODING_32BIT_LITTLE }; #define PRINTABLE(c) \ ((c) >= 0 && (c) <= 255 && \ ((c) == '\t' || isprint((c)) || \ (encoding == ENCODING_8BIT && (c) > 127))) -int encoding_size, entire_file, min_len, show_filename, show_loc; -enum encoding_style encoding; -enum radix_style radix; +static int encoding_size, entire_file, min_len, show_filename, show_loc; +static enum encoding_style encoding; +static enum radix_style radix; static struct option strings_longopts[] = { { "all", no_argument, NULL, 'a'}, { "bytes", required_argument, NULL, 'n'}, { "encoding", required_argument, NULL, 'e'}, { "help", no_argument, NULL, 'h'}, { "print-file-name", no_argument, NULL, 'f'}, { "radix", required_argument, NULL, 't'}, { "version", no_argument, NULL, 'v'}, { NULL, 0, NULL, 0 } }; long getcharacter(void); int handle_file(const char *); int handle_elf(const char *, int); int handle_binary(const char *, int); int find_strings(const char *, off_t, off_t); void show_version(void); void usage(void); /* * strings(1) extracts text(contiguous printable characters) * from elf and binary files. */ int main(int argc, char **argv) { int ch, rc; rc = RETURN_OK; min_len = 0; encoding_size = 1; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); while ((ch = getopt_long(argc, argv, "1234567890ae:fhn:ot:Vv", strings_longopts, NULL)) != -1) switch((char)ch) { case 'a': entire_file = 1; break; case 'e': if (*optarg == 's') { encoding = ENCODING_7BIT; } else if (*optarg == 'S') { encoding = ENCODING_8BIT; } else if (*optarg == 'b') { encoding = ENCODING_16BIT_BIG; encoding_size = 2; } else if (*optarg == 'B') { encoding = ENCODING_32BIT_BIG; encoding_size = 4; } else if (*optarg == 'l') { encoding = ENCODING_16BIT_LITTLE; encoding_size = 2; } else if (*optarg == 'L') { encoding = ENCODING_32BIT_LITTLE; encoding_size = 4; } else usage(); /* NOTREACHED */ break; case 'f': show_filename = 1; break; case 'n': min_len = (int)strtoimax(optarg, (char**)NULL, 10); break; case 'o': show_loc = 1; radix = RADIX_OCTAL; break; case 't': show_loc = 1; if (*optarg == 'd') radix = RADIX_DECIMAL; else if (*optarg == 'o') radix = RADIX_OCTAL; else if (*optarg == 'x') radix = RADIX_HEX; else usage(); /* NOTREACHED */ break; case 'v': case 'V': show_version(); /* NOTREACHED */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': min_len *= 10; min_len += ch - '0'; break; case 'h': case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if (!min_len) min_len = 4; if (!*argv) rc = handle_file("{standard input}"); else while (*argv) { rc = handle_file(*argv); argv++; } return (rc); } int handle_file(const char *name) { int fd, rt; if (name == NULL) return (RETURN_NOINPUT); if (strcmp("{standard input}", name) != 0) { if (freopen(name, "rb", stdin) == NULL) { warnx("'%s': %s", name, strerror(errno)); return (RETURN_NOINPUT); } } else { return (find_strings(name, (off_t)0, (off_t)0)); } fd = fileno(stdin); if (fd < 0) return (RETURN_NOINPUT); rt = handle_elf(name, fd); return (rt); } /* * Files not understood by handle_elf, will be passed off here and will * treated as a binary file. This would include text file, core dumps ... */ int handle_binary(const char *name, int fd) { struct stat buf; memset(&buf, 0, sizeof(struct stat)); (void) lseek(fd, (off_t)0, SEEK_SET); if (!fstat(fd, &buf)) return (find_strings(name, (off_t)0, buf.st_size)); return (RETURN_SOFTWARE); } /* * Will analyse a file to see if it ELF, other files including ar(1), * core dumps are passed off and treated as flat binary files. Unlike * GNU size in FreeBSD this routine will not treat ELF object from * different archs as flat binary files(has to overridden using -a). */ int handle_elf(const char *name, int fd) { GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf *elf; Elf_Scn *scn; int rc; rc = RETURN_OK; /* If entire file is choosen, treat it as a binary file */ if (entire_file) return (handle_binary(name, fd)); (void) lseek(fd, (off_t)0, SEEK_SET); elf = elf_begin(fd, ELF_C_READ, NULL); if (elf_kind(elf) != ELF_K_ELF) { (void) elf_end(elf); return (handle_binary(name, fd)); } if (gelf_getehdr(elf, &elfhdr) == NULL) { (void) elf_end(elf); warnx("%s: ELF file could not be processed", name); return (RETURN_SOFTWARE); } if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { (void) elf_end(elf); return (handle_binary(name, fd)); } else { scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) == NULL) continue; if (shdr.sh_type != SHT_NOBITS && (shdr.sh_flags & SHF_ALLOC) != 0) { rc = find_strings(name, shdr.sh_offset, shdr.sh_size); } } } (void) elf_end(elf); return (rc); } /* * Retrieves a character from input stream based on the encoding * type requested. */ long getcharacter(void) { long rt; int i; char buf[4], c; rt = EOF; for(i = 0; i < encoding_size; i++) { c = getc(stdin); if (feof(stdin)) return (EOF); buf[i] = c; } switch(encoding) { case ENCODING_7BIT: case ENCODING_8BIT: rt = buf[0]; break; case ENCODING_16BIT_BIG: rt = (buf[0] << 8) | buf[1]; break; case ENCODING_16BIT_LITTLE: rt = buf[0] | (buf[1] << 8); break; case ENCODING_32BIT_BIG: rt = ((long) buf[0] << 24) | ((long) buf[1] << 16) | ((long) buf[2] << 8) | buf[3]; break; case ENCODING_32BIT_LITTLE: rt = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) | ((long) buf[3] << 24); break; } return (rt); } /* * Input stream stdin is read until the end of file is reached or until * the section size is reached in case of ELF files. Contiguous * characters of >= min_size(default 4) will be displayed. */ int find_strings(const char *name, off_t offset, off_t size) { off_t cur_off, start_off; char *obuf; long c; int i; if ((obuf = (char*)calloc(1, min_len + 1)) == NULL) { (void) fprintf(stderr, "Unable to allocate memory: %s\n", strerror(errno)); return (RETURN_SOFTWARE); } (void) fseeko(stdin, offset, SEEK_SET); cur_off = offset; start_off = 0; while(1) { if ((offset + size) && (cur_off >= offset + size)) break; start_off = cur_off; memset(obuf, 0, min_len+1); for(i = 0; i < min_len; i++) { c = getcharacter(); if (c == EOF && feof(stdin)) goto _exit1; if (PRINTABLE(c)) { obuf[i] = c; obuf[i+1] = 0; cur_off += encoding_size; } else { if (encoding == ENCODING_8BIT && (uint8_t)c > 127) { obuf[i] = c; obuf[i+1] = 0; cur_off += encoding_size; continue; } cur_off += encoding_size; break; } } if (i >= min_len && ((cur_off <= offset + size) || !(offset + size))) { if (show_filename) printf ("%s: ", name); if (show_loc) { switch(radix) { case RADIX_DECIMAL: (void) printf("%7ju ", (uintmax_t)start_off); break; case RADIX_HEX: (void) printf("%7jx ", (uintmax_t)start_off); break; case RADIX_OCTAL: (void) printf("%7jo ", (uintmax_t)start_off); break; } } printf("%s", obuf); while(1) { if ((offset + size) && (cur_off >= offset + size)) break; c = getcharacter(); cur_off += encoding_size; if (encoding == ENCODING_8BIT && (uint8_t)c > 127) { putchar(c); continue; } if (!PRINTABLE(c) || c == EOF) break; putchar(c); } putchar('\n'); } } _exit1: free(obuf); return (RETURN_OK); } #define USAGE_MESSAGE "\ Usage: %s [options] [file...]\n\ Print contiguous sequences of printable characters.\n\n\ Options:\n\ -a | --all Scan the entire file for strings.\n\ -e ENC | --encoding=ENC Select the character encoding to use.\n\ -f | --print-file-name Print the file name before each string.\n\ -h | --help Print a help message and exit.\n\ -n N | --bytes=N | -N Print sequences with 'N' or more characters.\n\ -o Print offsets in octal.\n\ -t R | --radix=R Print offsets using the radix named by 'R'.\n\ -v | --version Print a version identifier and exit.\n" void usage(void) { (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } void show_version(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } diff --git a/test/ar/Makefile b/test/ar/Makefile index a62db09d9320..d767a3934430 100644 --- a/test/ar/Makefile +++ b/test/ar/Makefile @@ -1,20 +1,20 @@ -# $Id: Makefile 2141 2011-11-10 15:03:40Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ TOP= ../.. AR= ${TOP}/ar/ar TEST_LOG= test.log .MAIN: all .PHONY: clobber execute test execute test: ${AR} /bin/sh run.sh clobber: clean rm -f ${TEST_LOG} SUBDIR= plugin -.include +.include "${TOP}/mk/elftoolchain.subdir.mk" diff --git a/test/ar/plugin/Makefile b/test/ar/plugin/Makefile index 58e00fd1b2de..36e33a35687c 100644 --- a/test/ar/plugin/Makefile +++ b/test/ar/plugin/Makefile @@ -1,15 +1,15 @@ -# $Id: Makefile 2080 2011-10-27 04:23:24Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ PLUGINS= ardiff teraser all: ${PLUGINS} ${PLUGINS}: .for plugin in ${.TARGET} ${MAKE} -f Makefile.${plugin} .endfor -clean depend: +clean cleandepend depend: .for plugin in ${PLUGINS} ${MAKE} -f Makefile.${plugin} ${.TARGET} .endfor diff --git a/test/ar/plugin/Makefile.ardiff b/test/ar/plugin/Makefile.ardiff index 1558cfe6065c..ec702c2ae585 100644 --- a/test/ar/plugin/Makefile.ardiff +++ b/test/ar/plugin/Makefile.ardiff @@ -1,16 +1,14 @@ -# $Id: Makefile.ardiff 2096 2011-11-01 04:42:04Z jkoshy $ +# $Id: Makefile.ardiff 3120 2014-12-21 05:45:51Z kaiwang27 $ TOP= ../../.. -.include "${TOP}/mk/elftoolchain.os.mk" - PROG= ardiff NOMAN= noman WARNS?= 6 DPADD= ${LIBARCHIVE} LDADD= -larchive .include "${TOP}/mk/elftoolchain.prog.mk" diff --git a/test/ar/plugin/ardiff.c b/test/ar/plugin/ardiff.c index e54f6a9f6cdc..907d1ea80da9 100644 --- a/test/ar/plugin/ardiff.c +++ b/test/ar/plugin/ardiff.c @@ -1,254 +1,253 @@ /* Selectively compare two ar archives. * Usage: * ardiff [-ni] [-t name] ar1 ar2 * Options: * -c compare member content. (This implies -s) * -n compare member name. * -i compare member mtime. * -l compare archive length (member count). * -s compare member size. * -t specify the test name. * * By default, it compares nothing and consider the test "not ok" * iff it encounters errors while reading archive. * - * $Id: ardiff.c 2142 2011-11-10 15:29:59Z jkoshy $ + * $Id: ardiff.c 3102 2014-10-29 21:09:01Z jkoshy $ */ #include #include #include #include #include #include #include #include #define COUNTER "/tmp/bsdar-test-total" #define PASSED "/tmp/bsdar-test-passed" static void usage(void); static void filediff(const char *tc, const char *msg, const char *e); static void filesame(const char *tc); static void incct(const char *pathname); int main(int argc, char **argv) { struct archive *a1; struct archive *a2; struct archive_entry *e1; struct archive_entry *e2; const char *tc; char *buf1; char *buf2; char checkcont; char checklen; char checkname; char checksize; char checktime; char a1end; ssize_t size1; ssize_t size2; char opt; int r; /* * Parse command line options. */ checkcont = 0; checklen = 0; checkname = 0; checksize = 0; checktime = 0; tc = NULL; while ((opt = getopt(argc, argv, "cilnst:")) != -1) { switch(opt) { case 'c': checkcont = 1; break; case 'i': checktime = 1; break; case 'l': checklen = 1; break; case 'n': checkname = 1; break; case 's': checksize = 1; case 't': tc = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 2) usage(); /* Open file 1 */ a1 = archive_read_new(); - archive_read_support_compression_none(a1); archive_read_support_format_ar(a1); - if (archive_read_open_file(a1, argv[0], + if (archive_read_open_filename(a1, argv[0], 1024*10)) { warnx("%s", archive_error_string(a1)); filediff(tc, "archive open failed", NULL); } /* Open file 2 */ a2 = archive_read_new(); - archive_read_support_compression_none(a2); archive_read_support_format_ar(a2); - if (archive_read_open_file(a2, argv[1], + if (archive_read_open_filename(a2, argv[1], 1024*10)) { warnx("%s", archive_error_string(a2)); filediff(tc, "archive open failed", NULL); } /* Main loop */ a1end = 0; size1 = 0; size2 = 0; for (;;) { /* * Read header from each archive, compare length. */ r = archive_read_next_header(a1, &e1); if (r == ARCHIVE_EOF) a1end = 1; if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || r == ARCHIVE_FATAL) { warnx("%s", archive_error_string(a1)); filediff(tc, "archive data error", NULL); } r = archive_read_next_header(a2, &e2); if (r == ARCHIVE_EOF) { if (a1end > 0) break; else { if (checklen) filediff(tc, "length differ", NULL); break; } } if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || r == ARCHIVE_FATAL) { warnx("%s", archive_error_string(a2)); filediff(tc, "archive data error", NULL); } if (a1end > 0) { if (checklen) filediff(tc, "length differ", NULL); break; } /* * Check member name if required. */ if (checkname) { if (strcmp(archive_entry_pathname(e1), archive_entry_pathname(e2)) != 0) filediff(tc, "member name differ", archive_entry_pathname(e1)); } /* * Compare time if required. */ if (checktime) { if (archive_entry_mtime(e1) != archive_entry_mtime(e2)) filediff(tc, "member mtime differ", archive_entry_pathname(e1)); } /* * Compare member size if required. */ if (checksize || checkcont) { size1 = archive_entry_size(e1); size2 = archive_entry_size(e2); if (size1 != size2) filediff(tc, "member size differ", archive_entry_pathname(e1)); } /* * Compare member content if required. */ if (checkcont) { if ((buf1 = malloc(size1)) == NULL) filediff(tc, "not enough memory", NULL); if ((buf2 = malloc(size2)) == NULL) filediff(tc, "not enough memory", NULL); if (archive_read_data(a1, buf1, size1) != size1) filediff(tc, "archive_read_data failed", archive_entry_pathname(e1)); if (archive_read_data(a2, buf2, size2) != size2) filediff(tc, "archive_read_data failed", archive_entry_pathname(e1)); if (memcmp(buf1, buf2, size1) != 0) filediff(tc, "member content differ", archive_entry_pathname(e1)); free(buf1); free(buf2); } /* Proceed to next header. */ } /* Passed! */ filesame(tc); exit(EXIT_SUCCESS); } static void filediff(const char *tc, const char *msg, const char *e) { if (e != NULL) fprintf(stdout, "%s - archive diff not ok (%s (entry: %s))\n", tc, msg, e); else fprintf(stdout, "%s - archive diff not ok (%s)\n", tc, msg); incct(COUNTER); exit(EXIT_SUCCESS); } static void filesame(const char *tc) { fprintf(stdout, "%s - archive diff ok\n", tc); incct(COUNTER); incct(PASSED); } static void incct(const char *pathname) { FILE *fp; - char buf[10], *_buf; + char buf[10]; if ((fp = fopen(pathname, "r")) != NULL) { - _buf = fgets(buf, 10, fp); + if (fgets(buf, 10, fp) != buf) + perror("fgets"); snprintf(buf, 10, "%d\n", atoi(buf) + 1); fclose(fp); } if ((fp = fopen(pathname, "w")) != NULL) { fputs(buf, fp); fclose(fp); } } static void usage(void) { fprintf(stderr, "usage: ardiff archive1 archive2\n"); exit(EXIT_FAILURE); } diff --git a/test/ar/plugin/teraser.c b/test/ar/plugin/teraser.c index 59d587f7f048..d16752e7cefb 100644 --- a/test/ar/plugin/teraser.c +++ b/test/ar/plugin/teraser.c @@ -1,145 +1,147 @@ /* 1. Erase archive symbol table's timestamp from ar archives, * make it easy to `diff'. (option -e) * 2. Check the sanity of timestamp. (option -c) * - * $Id: teraser.c 2142 2011-11-10 15:29:59Z jkoshy $ + * $Id: teraser.c 3102 2014-10-29 21:09:01Z jkoshy $ */ #include #include #include #include #include #include #include #include #define TSPOS 24 /* position of timestamp */ #define TSLEN 10 /* length of timstamp string */ #define TDELAY 3 /* max delay allowed */ #define COUNTER "/tmp/bsdar-test-total" #define PASSED "/tmp/bsdar-test-passed" static void usage(void); int main(int argc, char **argv) { char opt; char checktime; char erasetime; - char buf[TSLEN + 1], *_buf; + char buf[TSLEN + 1]; char *tc; int fd; int ts; int now; FILE *ct, *ps; checktime = 0; erasetime = 0; tc = NULL; while ((opt = getopt(argc, argv, "cet:")) != -1) { switch(opt) { case 'c': checktime = 1; break; case 'e': erasetime = 1; break; case 't': tc = optarg; break; default: usage(); } } argv += optind; if (*argv == NULL) usage(); for (; *argv != NULL; argv++) { if (checktime) { if ((fd = open(*argv, O_RDONLY)) == -1) { fprintf(stderr, "open %s failed(%s), skipping time check...\n,", *argv, strerror(errno)); goto ctend; } if ((lseek(fd, TSPOS, SEEK_SET)) == -1) { fprintf(stderr, "lseek %s failed(%s), skipping...\n,", *argv, strerror(errno)); goto ctend; } if ((read(fd, buf, TSLEN)) != TSLEN) { fprintf(stderr, "read %s failed(%s), skipping...\n,", *argv, strerror(errno)); goto ctend; } buf[TSLEN] = '\0'; ts = atoi(buf); now = time(NULL); if (ts <= now && ts >= now - TDELAY) { fprintf(stderr, "%s - timestamp ok\n", tc); if ((ps = fopen(PASSED, "r")) != NULL) { - _buf = fgets(buf, TSLEN, ps); + if (fgets(buf, TSLEN, ps) != buf) + perror("fgets"); snprintf(buf, TSLEN, "%d\n", atoi(buf) + 1); fclose(ps); } if ((ps = fopen(PASSED, "w")) != NULL) { fputs(buf, ps); fclose(ps); } } else { fprintf(stderr, "%s - timestamp not ok\n", tc); } if ((ct = fopen(COUNTER, "r")) != NULL) { - _buf = fgets(buf, TSLEN, ct); + if (fgets(buf, TSLEN, ct) != buf) + perror("fgets"); snprintf(buf, TSLEN, "%d\n", atoi(buf) + 1); fclose(ct); } if ((ct = fopen(COUNTER, "w")) != NULL) { fputs(buf, ct); fclose(ct); } ctend: close(fd); } if (erasetime) { if ((fd = open(*argv, O_RDWR)) == -1) { fprintf(stderr, "open %s failed(%s), skipping time check...\n,", *argv, strerror(errno)); goto etend; } if ((lseek(fd, TSPOS, SEEK_SET)) == -1) { fprintf(stderr, "lseek %s failed(%s), skipping...,", *argv, strerror(errno)); goto etend; } memset(buf, 32, TSLEN); if ((write(fd, buf, TSLEN)) != TSLEN) fprintf(stderr, "read %s failed(%s), skipping...\n,", *argv, strerror(errno)); etend: close(fd); } } exit(EXIT_SUCCESS); } static void usage(void) { fprintf(stderr, "usage: teraser [-ce] [-t name] archive ...\n"); exit(EXIT_FAILURE); } diff --git a/test/elfcopy/Makefile b/test/elfcopy/Makefile index f1302f133979..5114a68e7b2f 100644 --- a/test/elfcopy/Makefile +++ b/test/elfcopy/Makefile @@ -1,21 +1,21 @@ -# $Id: Makefile 2141 2011-11-10 15:03:40Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ TOP= ../.. ELFCOPY= ${TOP}/elfcopy/elfcopy TEST_LOG= test.log .MAIN: all .PHONY: clobber execute test execute test: ${ELFCOPY} /bin/sh run.sh clobber: clean rm -f ${TEST_LOG} SUBDIR= plugin -.include +.include "${TOP}/mk/elftoolchain.subdir.mk" diff --git a/test/elfcopy/plugin/Makefile b/test/elfcopy/plugin/Makefile index a72fbfe7d371..36e33a35687c 100644 --- a/test/elfcopy/plugin/Makefile +++ b/test/elfcopy/plugin/Makefile @@ -1,15 +1,15 @@ -# $Id: Makefile 2082 2011-10-27 04:38:32Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ PLUGINS= ardiff teraser all: ${PLUGINS} ${PLUGINS}: .for plugin in ${.TARGET} ${MAKE} -f Makefile.${plugin} .endfor -clean depend: +clean cleandepend depend: .for plugin in ${PLUGINS} ${MAKE} -f Makefile.${plugin} ${.TARGET} .endfor diff --git a/test/elfcopy/plugin/Makefile.ardiff b/test/elfcopy/plugin/Makefile.ardiff index 7f371a7a975c..a7baa0a0292b 100644 --- a/test/elfcopy/plugin/Makefile.ardiff +++ b/test/elfcopy/plugin/Makefile.ardiff @@ -1,16 +1,14 @@ -# $Id: Makefile.ardiff 2096 2011-11-01 04:42:04Z jkoshy $ +# $Id: Makefile.ardiff 3121 2014-12-21 05:46:01Z kaiwang27 $ TOP= ../../.. -.include "${TOP}/mk/elftoolchain.os.mk" - PROG= ardiff NOMAN= WARNS?= 6 DPADD= ${LIBARCHIVE} LDADD= -larchive .include "${TOP}/mk/elftoolchain.prog.mk" diff --git a/test/elfcopy/plugin/ardiff.c b/test/elfcopy/plugin/ardiff.c index e54f6a9f6cdc..907d1ea80da9 100644 --- a/test/elfcopy/plugin/ardiff.c +++ b/test/elfcopy/plugin/ardiff.c @@ -1,254 +1,253 @@ /* Selectively compare two ar archives. * Usage: * ardiff [-ni] [-t name] ar1 ar2 * Options: * -c compare member content. (This implies -s) * -n compare member name. * -i compare member mtime. * -l compare archive length (member count). * -s compare member size. * -t specify the test name. * * By default, it compares nothing and consider the test "not ok" * iff it encounters errors while reading archive. * - * $Id: ardiff.c 2142 2011-11-10 15:29:59Z jkoshy $ + * $Id: ardiff.c 3102 2014-10-29 21:09:01Z jkoshy $ */ #include #include #include #include #include #include #include #include #define COUNTER "/tmp/bsdar-test-total" #define PASSED "/tmp/bsdar-test-passed" static void usage(void); static void filediff(const char *tc, const char *msg, const char *e); static void filesame(const char *tc); static void incct(const char *pathname); int main(int argc, char **argv) { struct archive *a1; struct archive *a2; struct archive_entry *e1; struct archive_entry *e2; const char *tc; char *buf1; char *buf2; char checkcont; char checklen; char checkname; char checksize; char checktime; char a1end; ssize_t size1; ssize_t size2; char opt; int r; /* * Parse command line options. */ checkcont = 0; checklen = 0; checkname = 0; checksize = 0; checktime = 0; tc = NULL; while ((opt = getopt(argc, argv, "cilnst:")) != -1) { switch(opt) { case 'c': checkcont = 1; break; case 'i': checktime = 1; break; case 'l': checklen = 1; break; case 'n': checkname = 1; break; case 's': checksize = 1; case 't': tc = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 2) usage(); /* Open file 1 */ a1 = archive_read_new(); - archive_read_support_compression_none(a1); archive_read_support_format_ar(a1); - if (archive_read_open_file(a1, argv[0], + if (archive_read_open_filename(a1, argv[0], 1024*10)) { warnx("%s", archive_error_string(a1)); filediff(tc, "archive open failed", NULL); } /* Open file 2 */ a2 = archive_read_new(); - archive_read_support_compression_none(a2); archive_read_support_format_ar(a2); - if (archive_read_open_file(a2, argv[1], + if (archive_read_open_filename(a2, argv[1], 1024*10)) { warnx("%s", archive_error_string(a2)); filediff(tc, "archive open failed", NULL); } /* Main loop */ a1end = 0; size1 = 0; size2 = 0; for (;;) { /* * Read header from each archive, compare length. */ r = archive_read_next_header(a1, &e1); if (r == ARCHIVE_EOF) a1end = 1; if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || r == ARCHIVE_FATAL) { warnx("%s", archive_error_string(a1)); filediff(tc, "archive data error", NULL); } r = archive_read_next_header(a2, &e2); if (r == ARCHIVE_EOF) { if (a1end > 0) break; else { if (checklen) filediff(tc, "length differ", NULL); break; } } if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || r == ARCHIVE_FATAL) { warnx("%s", archive_error_string(a2)); filediff(tc, "archive data error", NULL); } if (a1end > 0) { if (checklen) filediff(tc, "length differ", NULL); break; } /* * Check member name if required. */ if (checkname) { if (strcmp(archive_entry_pathname(e1), archive_entry_pathname(e2)) != 0) filediff(tc, "member name differ", archive_entry_pathname(e1)); } /* * Compare time if required. */ if (checktime) { if (archive_entry_mtime(e1) != archive_entry_mtime(e2)) filediff(tc, "member mtime differ", archive_entry_pathname(e1)); } /* * Compare member size if required. */ if (checksize || checkcont) { size1 = archive_entry_size(e1); size2 = archive_entry_size(e2); if (size1 != size2) filediff(tc, "member size differ", archive_entry_pathname(e1)); } /* * Compare member content if required. */ if (checkcont) { if ((buf1 = malloc(size1)) == NULL) filediff(tc, "not enough memory", NULL); if ((buf2 = malloc(size2)) == NULL) filediff(tc, "not enough memory", NULL); if (archive_read_data(a1, buf1, size1) != size1) filediff(tc, "archive_read_data failed", archive_entry_pathname(e1)); if (archive_read_data(a2, buf2, size2) != size2) filediff(tc, "archive_read_data failed", archive_entry_pathname(e1)); if (memcmp(buf1, buf2, size1) != 0) filediff(tc, "member content differ", archive_entry_pathname(e1)); free(buf1); free(buf2); } /* Proceed to next header. */ } /* Passed! */ filesame(tc); exit(EXIT_SUCCESS); } static void filediff(const char *tc, const char *msg, const char *e) { if (e != NULL) fprintf(stdout, "%s - archive diff not ok (%s (entry: %s))\n", tc, msg, e); else fprintf(stdout, "%s - archive diff not ok (%s)\n", tc, msg); incct(COUNTER); exit(EXIT_SUCCESS); } static void filesame(const char *tc) { fprintf(stdout, "%s - archive diff ok\n", tc); incct(COUNTER); incct(PASSED); } static void incct(const char *pathname) { FILE *fp; - char buf[10], *_buf; + char buf[10]; if ((fp = fopen(pathname, "r")) != NULL) { - _buf = fgets(buf, 10, fp); + if (fgets(buf, 10, fp) != buf) + perror("fgets"); snprintf(buf, 10, "%d\n", atoi(buf) + 1); fclose(fp); } if ((fp = fopen(pathname, "w")) != NULL) { fputs(buf, fp); fclose(fp); } } static void usage(void) { fprintf(stderr, "usage: ardiff archive1 archive2\n"); exit(EXIT_FAILURE); } diff --git a/test/elfcopy/plugin/teraser.c b/test/elfcopy/plugin/teraser.c index 59d587f7f048..0deb7cc90630 100644 --- a/test/elfcopy/plugin/teraser.c +++ b/test/elfcopy/plugin/teraser.c @@ -1,145 +1,147 @@ /* 1. Erase archive symbol table's timestamp from ar archives, * make it easy to `diff'. (option -e) * 2. Check the sanity of timestamp. (option -c) * - * $Id: teraser.c 2142 2011-11-10 15:29:59Z jkoshy $ + * $Id: teraser.c 3102 2014-10-29 21:09:01Z jkoshy $ */ #include #include #include #include #include #include #include #include #define TSPOS 24 /* position of timestamp */ #define TSLEN 10 /* length of timstamp string */ #define TDELAY 3 /* max delay allowed */ #define COUNTER "/tmp/bsdar-test-total" #define PASSED "/tmp/bsdar-test-passed" static void usage(void); int main(int argc, char **argv) { char opt; char checktime; char erasetime; - char buf[TSLEN + 1], *_buf; + char buf[TSLEN + 1]; char *tc; int fd; int ts; int now; FILE *ct, *ps; checktime = 0; erasetime = 0; tc = NULL; while ((opt = getopt(argc, argv, "cet:")) != -1) { switch(opt) { case 'c': checktime = 1; break; case 'e': erasetime = 1; break; case 't': tc = optarg; break; default: usage(); } } argv += optind; if (*argv == NULL) usage(); for (; *argv != NULL; argv++) { if (checktime) { if ((fd = open(*argv, O_RDONLY)) == -1) { fprintf(stderr, "open %s failed(%s), skipping time check...\n,", *argv, strerror(errno)); goto ctend; } if ((lseek(fd, TSPOS, SEEK_SET)) == -1) { fprintf(stderr, "lseek %s failed(%s), skipping...\n,", *argv, strerror(errno)); goto ctend; } if ((read(fd, buf, TSLEN)) != TSLEN) { fprintf(stderr, "read %s failed(%s), skipping...\n,", *argv, strerror(errno)); goto ctend; } buf[TSLEN] = '\0'; ts = atoi(buf); now = time(NULL); if (ts <= now && ts >= now - TDELAY) { fprintf(stderr, "%s - timestamp ok\n", tc); if ((ps = fopen(PASSED, "r")) != NULL) { - _buf = fgets(buf, TSLEN, ps); + if (fgets(buf, TSLEN, ps) != buf) + perror("fgets"); snprintf(buf, TSLEN, "%d\n", atoi(buf) + 1); fclose(ps); } if ((ps = fopen(PASSED, "w")) != NULL) { fputs(buf, ps); fclose(ps); } } else { fprintf(stderr, "%s - timestamp not ok\n", tc); } if ((ct = fopen(COUNTER, "r")) != NULL) { - _buf = fgets(buf, TSLEN, ct); + if (fgets(buf, TSLEN, ct) != NULL) + perror("fgets"); snprintf(buf, TSLEN, "%d\n", atoi(buf) + 1); fclose(ct); } if ((ct = fopen(COUNTER, "w")) != NULL) { fputs(buf, ct); fclose(ct); } ctend: close(fd); } if (erasetime) { if ((fd = open(*argv, O_RDWR)) == -1) { fprintf(stderr, "open %s failed(%s), skipping time check...\n,", *argv, strerror(errno)); goto etend; } if ((lseek(fd, TSPOS, SEEK_SET)) == -1) { fprintf(stderr, "lseek %s failed(%s), skipping...,", *argv, strerror(errno)); goto etend; } memset(buf, 32, TSLEN); if ((write(fd, buf, TSLEN)) != TSLEN) fprintf(stderr, "read %s failed(%s), skipping...\n,", *argv, strerror(errno)); etend: close(fd); } } exit(EXIT_SUCCESS); } static void usage(void) { fprintf(stderr, "usage: teraser [-ce] [-t name] archive ...\n"); exit(EXIT_FAILURE); } diff --git a/test/elfcopy/tc/strip-empty-1/in/strip-empty-1.in.shar b/test/elfcopy/tc/strip-empty-1/in/strip-empty-1.in.shar new file mode 100644 index 000000000000..6ff3cf214cc2 --- /dev/null +++ b/test/elfcopy/tc/strip-empty-1/in/strip-empty-1.in.shar @@ -0,0 +1,32 @@ +# This is a shell archive. Save it in a file, remove anything before +# this line, and then unpack it by entering "sh file". Note, it may +# create directories; files and directories will be owned by you and +# have default permissions. +# +# This archive contains: +# +# empty.o.uu +# +echo x - empty.o.uu +sed 's/^X//' >empty.o.uu << '446fa33c5b702a1d1fbfe3ec7a501a1a' +Xbegin 644 empty.o +XM?T5,1@(!`0D```````````$`/@`!`````````````````````````'`````` +XM`````````$```````$``!P`$```Nempty.o.uu << '446fa33c5b702a1d1fbfe3ec7a501a1a' +Xbegin 644 empty.o +XM?T5,1@(!`0D```````````$`/@`!`````````````````````````%`````` +XM`````````$```````$```@`!```N +.include "${TOP}/mk/elftoolchain.tetbase.mk" diff --git a/test/libdwarf/ts/Makefile b/test/libdwarf/ts/Makefile index 84d6e2404b14..05ddf91e16d4 100644 --- a/test/libdwarf/ts/Makefile +++ b/test/libdwarf/ts/Makefile @@ -1,25 +1,27 @@ # -# $Id: Makefile 2084 2011-10-27 04:48:12Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ # +TOP= ../../.. + SUBDIR+= dwarf_init SUBDIR+= dwarf_next_cu_header SUBDIR+= dwarf_get_address_size SUBDIR+= dwarf_siblingof SUBDIR+= dwarf_child SUBDIR+= dwarf_die_query SUBDIR+= dwarf_die_offset SUBDIR+= dwarf_die_convenience SUBDIR+= dwarf_attr SUBDIR+= dwarf_attrlist SUBDIR+= dwarf_form SUBDIR+= dwarf_loclist SUBDIR+= dwarf_lineno SUBDIR+= dwarf_frame SUBDIR+= dwarf_arange SUBDIR+= dwarf_abbrev SUBDIR+= dwarf_pubnames SUBDIR+= dwarf_macinfo SUBDIR+= dwarf_ranges -.include +.include "${TOP}/mk/elftoolchain.subdir.mk" diff --git a/test/libdwarf/ts/Makefile.tset b/test/libdwarf/ts/Makefile.tset index af0f82a10dbc..6546de89d2cf 100644 --- a/test/libdwarf/ts/Makefile.tset +++ b/test/libdwarf/ts/Makefile.tset @@ -1,56 +1,56 @@ -# $Id: Makefile.tset 2198 2011-11-23 16:13:45Z jkoshy $ - -.include "${TOP}/mk/elftoolchain.os.mk" +# $Id: Makefile.tset 3122 2014-12-21 05:46:10Z kaiwang27 $ # libdwarf test suite uses libdwarf in /usr/local (i.e. SGI libdwarf), # if TCGEN is defined. .if defined(TCGEN) DWARF_INC?= /usr/local/include DWARF_LIBS?= /usr/local/lib CFLAGS+= -DTCGEN -I${DWARF_INC} LDADD+= -L${DWARF_LIBS} .endif LDADD+= -ldwarf DPADD+= ${LIBELF} LDADD+= -lelf +# Test cases do not have manual pages. +NOMAN= noman + +.include "${TOP}/mk/elftoolchain.os.mk" + # Determine the location of the XML handling library. .if ${OS_HOST} == FreeBSD LDADD+= -lbsdxml .else .if ${OS_HOST} == DragonFly || ${OS_HOST} == NetBSD CFLAGS+= -I/usr/pkg/include LDADD+= -L/usr/pkg/lib .endif LDADD+= -lexpat .endif .if !defined(TCGEN) TS_SRCS+= ${.OBJDIR}/ic_count.c ${.OBJDIR}/ic_count.c: ${TS_ROOT}/bin/count-ic ${.OBJDIR} CLEANFILES+= ${.OBJDIR}/ic_count.c .endif .for f in ${TS_DATA} CLEANFILES+= ${f}.xml .endfor # Copy test objects(binaries) to the build directory. .for f in ${TS_DATA} .if !exists(${f:R}) ${f}: ${TS_OBJROOT}/common/object/${f}.gz cp ${.ALLSRC} ${.TARGET}.gz gunzip ${.TARGET}.gz .endif .endfor # NetBSD turns on -Wstrict-prototypes for WARNS>0; however # TET 3.8's headers do not compile with -Wstrict-prototypes. .if ${OS_HOST} != NetBSD WARNS?= 2 .endif - -# Test cases do not have manual pages. -NOMAN= noman diff --git a/test/libdwarf/ts/README b/test/libdwarf/ts/README index b163c50a7ccd..0a041dcbd604 100644 --- a/test/libdwarf/ts/README +++ b/test/libdwarf/ts/README @@ -1,34 +1,46 @@ -: $Id: README 2084 2011-10-27 04:48:12Z jkoshy $ +: $Id: README 3072 2014-06-23 03:08:44Z kaiwang27 $ Libdwarf test suite use XML files to describe test case, invocable component and test purpose. Each test case can have several XML files, and each XML file corresponds to exact one invocable component. For example, test case dwarf_get_address_size contains following XML file: 4 Element 'ic' defines invocable component, in libdwarf test suite, one invocable component can be invoked on only one test object (dt32-g1 in this case). Element 'tp' defines a test purpose. A 'ic' can have multiple 'tp' (only one in this case). Element 'vc' defines a "variable check", which means verify varible's value against constant. In this example, test purpose tp_dwarf_get_address_size will verify that variable addr_size has value 4. When a test case is compiled nomarlly, during test case startup, the test driver will parse the XML files and report to TET how many IC and TP this test case have. When each TP is executed, test driver will verify variable values according to the list of VC defined in that TP. When a test case is compiled with 'make TCGEN=yes', it will instead link with SGI libdwarf and genearte XML files during TP execution. These generated XML files can then be used directly to test this libdwarf implementation. + +For example, to generate XML files for test case dwarf_next_cu_header: + +% cd /path/to/elftoolchain/test/libdwarf/ +# unsetenv TET_ROOT +% make clean && make TCGEN=yes +% cd ts/dwarf_next_cu_header +% setenv TET_ROOT /path/to/elftoolchain/test/tet +% env ICLIST=dt32-g1:dt64-g1:ec32-g1:ec64-g1:ld_symver.o-64-g1 ./tc_dwarf_next_cu_header + +(ICLIST defines a list of test objects on which the test case +generates. One gzipped XML file is generated for each test object.) diff --git a/test/libdwarf/ts/common/die_traverse2.c b/test/libdwarf/ts/common/die_traverse2.c new file mode 100644 index 000000000000..059ca13cb1c0 --- /dev/null +++ b/test/libdwarf/ts/common/die_traverse2.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2010,2014 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: die_traverse2.c 3076 2014-06-23 23:54:01Z kaiwang27 $ + */ + +#include +#include +#include + +#include "driver.h" + +static int die_cnt; + +/* + * DIE traverse function shared by test cases. (another version with + * .debug_types support) + */ + +static void +_die_traverse_recursive2(Dwarf_Debug dbg, Dwarf_Die die, + Dwarf_Bool is_info, void (*die_callback)(Dwarf_Die die)) +{ + Dwarf_Die die0; + Dwarf_Off offset; + Dwarf_Half tag; + Dwarf_Error de; + const char *tagname; + int r; + + assert(dbg != NULL && die != NULL && die_callback != NULL); + + if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { + tet_printf("dwarf_tag failed: %s\n", dwarf_errmsg(de)); + result = TET_FAIL; + } + tagname = NULL; + if (dwarf_get_TAG_name(tag, &tagname) != DW_DLV_OK) { + tet_infoline("dwarf_get_TAG_name failed"); + result = TET_FAIL; + } + offset = 0; + if (dwarf_dieoffset(die, &offset, &de) != DW_DLV_OK) { + tet_printf("dwarf_dieoffset failed: %s\n", dwarf_errmsg(de)); + result = TET_FAIL; + } + tet_printf("DIE #%d (%s) [%#x]\n", die_cnt++, tagname, offset); + + die_callback(die); + + /* Search children. */ + r = dwarf_child(die, &die0, &de); + if (r == DW_DLV_ERROR) + tet_printf("%s: dwarf_child failed: %s", __func__, + dwarf_errmsg(de)); + else if (r == DW_DLV_OK) + _die_traverse_recursive2(dbg, die0, is_info, die_callback); + + /* Search sibling. */ + r = dwarf_siblingof_b(dbg, die, &die0, is_info, &de); + if (r == DW_DLV_ERROR) + tet_printf("%s: dwarf_siblingof failed: %s", __func__, + dwarf_errmsg(de)); + else if (r == DW_DLV_OK) + _die_traverse_recursive2(dbg, die0, is_info, die_callback); +} + +static void +_die_traverse2(Dwarf_Debug dbg, Dwarf_Bool is_info, + void (*die_callback)(Dwarf_Die die)) +{ + Dwarf_Die die; + Dwarf_Error de; + Dwarf_Unsigned cu_next_offset; + + assert(dbg != NULL && die_callback != NULL); + + die_cnt = 0; + + if (is_info) { + TS_DWARF_CU_FOREACH2(dbg, 1, cu_next_offset, de) { + if (dwarf_siblingof_b(dbg, NULL, &die, 1, &de) != + DW_DLV_OK) + break; + _die_traverse_recursive2(dbg, die, 1, die_callback); + } + } else { + do { + TS_DWARF_CU_FOREACH2(dbg, 0, cu_next_offset, de) { + if (dwarf_siblingof_b(dbg, NULL, &die, 0, + &de) != DW_DLV_OK) + break; + _die_traverse_recursive2(dbg, die, 0, + die_callback); + } + } while (dwarf_next_types_section(dbg, &de) == DW_DLV_OK); + } +} diff --git a/test/libdwarf/ts/common/driver.h b/test/libdwarf/ts/common/driver.h index 7d84a017e386..580683ffd17e 100644 --- a/test/libdwarf/ts/common/driver.h +++ b/test/libdwarf/ts/common/driver.h @@ -1,172 +1,179 @@ /*- * Copyright (c) 2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: driver.h 2084 2011-10-27 04:48:12Z jkoshy $ + * $Id: driver.h 3074 2014-06-23 03:08:53Z kaiwang27 $ */ #ifndef _DRIVER_H_ #define _DRIVER_H_ struct dwarf_tp { const char *tp_name; void (*tp_func)(void); }; #define TS_DWARF_INIT(D,FD,DE) do { \ (D) = NULL; \ if (((FD) = open(_cur_file, O_RDONLY)) < 0) { \ tet_printf("open %s failed; %s", _cur_file, \ strerror(errno)); \ result = TET_FAIL; \ goto done; \ } \ if (dwarf_init((FD), DW_DLC_READ, NULL, NULL, &(D), &(DE)) != \ DW_DLV_OK) { \ tet_printf("dwarf_init failed: %s", dwarf_errmsg((DE)));\ result = TET_FAIL; \ goto done; \ } \ } while (0) #define TS_DWARF_FINISH(D,DE) do { \ if (dwarf_finish((D), &(DE)) != DW_DLV_OK) { \ tet_printf("dwarf_finish failed: %s", \ dwarf_errmsg((DE))); \ result = TET_FAIL; \ } \ } while (0) #define TS_DWARF_CU_FOREACH(D,N,DE) \ while (dwarf_next_cu_header((D), NULL, NULL, NULL, NULL, &(N), \ &(DE)) == DW_DLV_OK) -#define TS_DWARF_DIE_TRAVERSE(D, CB) \ +#define TS_DWARF_CU_FOREACH2(D,I,N,DE) \ + while (dwarf_next_cu_header_c((D), (I), NULL, NULL, NULL, NULL, \ + NULL, NULL, NULL, NULL, &(N), &(DE)) == DW_DLV_OK) + +#define TS_DWARF_DIE_TRAVERSE(D,CB) \ _die_traverse((D), (CB)) +#define TS_DWARF_DIE_TRAVERSE2(D,I,CB) \ + _die_traverse2((D), (I), (CB)) + #ifndef TCGEN #define _TS_CHECK_VAR(X,S) do { \ struct _drv_vc *_next_vc; \ int skip = 0; \ if (strcmp(_cur_vc->var, S)) { \ tet_printf("VC var(%s) does not match %s, possibly" \ " caused by the skip of previous VCs, try finding" \ " the next var with maching name", _cur_vc->var, \ S); \ _next_vc = _cur_vc; \ do { \ _next_vc = STAILQ_NEXT(_next_vc, next); \ skip++; \ if (!strcmp(_next_vc->var, S)) \ break; \ } while (_next_vc != NULL); \ if (_next_vc != NULL) { \ tet_printf("skipped %d VC(s)\n", skip); \ _cur_vc = _next_vc; \ } \ } \ } while (0) #define TS_CHECK_INT(X) do { \ assert(_cur_vc != NULL); \ _TS_CHECK_VAR(X,#X); \ if (X != _cur_vc->v.i64) { \ tet_printf("assertion %s(%jd) == %jd failed", \ _cur_vc->var, (intmax_t) (X), \ (intmax_t) _cur_vc->v.i64); \ result = TET_FAIL; \ } \ _cur_vc = STAILQ_NEXT(_cur_vc, next); \ } while (0) #define TS_CHECK_UINT(X) do { \ assert(_cur_vc != NULL); \ _TS_CHECK_VAR(X,#X); \ if (X != _cur_vc->v.u64) { \ tet_printf("assertion %s(%ju) == %ju failed", \ _cur_vc->var, (uintmax_t) (X), \ (uintmax_t) _cur_vc->v.u64); \ result = TET_FAIL; \ } \ _cur_vc = STAILQ_NEXT(_cur_vc, next); \ } while (0) #define TS_CHECK_STRING(X) do { \ assert(_cur_vc != NULL); \ _TS_CHECK_VAR(X,#X); \ if (strcmp(X, _cur_vc->v.str)) { \ tet_printf("assertion %s('%s') == '%s' failed", \ _cur_vc->var, (X), _cur_vc->v.str); \ result = TET_FAIL; \ } \ _cur_vc = STAILQ_NEXT(_cur_vc, next); \ } while (0) #define TS_CHECK_BLOCK(B,S) do { \ assert(_cur_vc != NULL); \ _TS_CHECK_VAR(B,#B); \ if ((S) != _cur_vc->v.b.len || \ memcmp((B), _cur_vc->v.b.data, _cur_vc->v.b.len)) { \ tet_printf("assertion block %s failed\n", _cur_vc->var);\ result = TET_FAIL; \ } \ _cur_vc = STAILQ_NEXT(_cur_vc, next); \ } while (0) #define TS_RESULT(X) tet_result(X) #else /* !TCGEN */ #define TS_CHECK_INT(X) do { \ fprintf(_cur_fp, " %jd\n", #X, \ (intmax_t) (X)); \ } while (0) #define TS_CHECK_UINT(X) do { \ fprintf(_cur_fp, " %ju\n", #X, \ (uintmax_t)(X)); \ } while (0) #define TS_CHECK_STRING(X) do { \ fprintf(_cur_fp, " %s\n", #X, \ driver_string_encode(X)); \ } while (0) #define TS_CHECK_BLOCK(B,S) do { \ char *code; \ int codesize; \ size_t wsize; \ fprintf(_cur_fp, " ", #B); \ driver_base64_encode((char *) (B), (S), &code, &codesize); \ wsize = fwrite(code, 1, (size_t) codesize, _cur_fp); \ assert(wsize == (size_t) codesize); \ fprintf(_cur_fp, "\n"); \ free(code); \ } while (0) #define TS_RESULT(X) #endif /* !TCGEN */ #endif /* !_DRIVER_H_ */ diff --git a/test/libdwarf/ts/common/object/ld_symver.o-64-g1.gz b/test/libdwarf/ts/common/object/ld_symver.o-64-g1.gz new file mode 100644 index 000000000000..5fd90579c811 Binary files /dev/null and b/test/libdwarf/ts/common/object/ld_symver.o-64-g1.gz differ diff --git a/test/libdwarf/ts/dwarf_attrlist/Makefile b/test/libdwarf/ts/dwarf_attrlist/Makefile index 29cc2480527b..beaf7e4bb415 100644 --- a/test/libdwarf/ts/dwarf_attrlist/Makefile +++ b/test/libdwarf/ts/dwarf_attrlist/Makefile @@ -1,8 +1,8 @@ -# $Id: Makefile 2084 2011-10-27 04:48:12Z jkoshy $ +# $Id: Makefile 3083 2014-09-02 22:08:01Z kaiwang27 $ TOP= ../../../.. TS_SRCS= dwarf_attrlist.c -TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 +TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 ld_symver.o-64-g1 .include "${TOP}/mk/elftoolchain.tet.mk" diff --git a/test/libdwarf/ts/dwarf_attrlist/dt32-g1.xml.gz b/test/libdwarf/ts/dwarf_attrlist/dt32-g1.xml.gz index 9757123b7b2c..78629601d102 100644 Binary files a/test/libdwarf/ts/dwarf_attrlist/dt32-g1.xml.gz and b/test/libdwarf/ts/dwarf_attrlist/dt32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_attrlist/dt64-g1.xml.gz b/test/libdwarf/ts/dwarf_attrlist/dt64-g1.xml.gz index e4cf1c592c6d..8b69a054fa4d 100644 Binary files a/test/libdwarf/ts/dwarf_attrlist/dt64-g1.xml.gz and b/test/libdwarf/ts/dwarf_attrlist/dt64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_attrlist/dwarf_attrlist.c b/test/libdwarf/ts/dwarf_attrlist/dwarf_attrlist.c index fa6818ec1dcc..e8f29edc9366 100644 --- a/test/libdwarf/ts/dwarf_attrlist/dwarf_attrlist.c +++ b/test/libdwarf/ts/dwarf_attrlist/dwarf_attrlist.c @@ -1,129 +1,130 @@ /*- * Copyright (c) 2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dwarf_attrlist.c 2084 2011-10-27 04:48:12Z jkoshy $ + * $Id: dwarf_attrlist.c 3083 2014-09-02 22:08:01Z kaiwang27 $ */ #include #include #include #include #include #include #include "driver.h" #include "tet_api.h" /* * Test case for dwarf_attrlist and dwarf_whatattr etc. */ static void tp_dwarf_attrlist(void); static void tp_dwarf_attrlist_sanity(void); static struct dwarf_tp dwarf_tp_array[] = { {"tp_dwarf_attrlist", tp_dwarf_attrlist}, {"tp_dwarf_attrlist_sanity", tp_dwarf_attrlist_sanity}, {NULL, NULL}, }; static int result = TET_UNRESOLVED; #include "driver.c" -#include "die_traverse.c" +#include "die_traverse2.c" static void _dwarf_attrlist(Dwarf_Die die) { Dwarf_Attribute *attrlist; Dwarf_Signed attrcount; Dwarf_Half attr; Dwarf_Error de; int i, r; r = dwarf_attrlist(die, &attrlist, &attrcount, &de); TS_CHECK_INT(r); if (r == DW_DLV_ERROR) { tet_printf("dwarf_attrlist failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; return; } else if (r == DW_DLV_NO_ENTRY) return; TS_CHECK_INT(attrcount); for (i = 0; i < attrcount; i++) { if (dwarf_whatattr(attrlist[i], &attr, &de) != DW_DLV_OK) { tet_printf("dwarf_whatattr failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_UINT(attr); } } static void tp_dwarf_attrlist(void) { Dwarf_Debug dbg; Dwarf_Error de; int fd; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); - TS_DWARF_DIE_TRAVERSE(dbg, _dwarf_attrlist); + TS_DWARF_DIE_TRAVERSE2(dbg, 1, _dwarf_attrlist); + TS_DWARF_DIE_TRAVERSE2(dbg, 0, _dwarf_attrlist); if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } static void tp_dwarf_attrlist_sanity(void) { Dwarf_Debug dbg; Dwarf_Attribute *attrlist; Dwarf_Signed attrcount; Dwarf_Error de; int fd; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); if (dwarf_attrlist(NULL, &attrlist, &attrcount, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_attrlist didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } diff --git a/test/libdwarf/ts/dwarf_attrlist/ec32-g1.xml.gz b/test/libdwarf/ts/dwarf_attrlist/ec32-g1.xml.gz index 3408f55c6e59..f2a53356cc7c 100644 Binary files a/test/libdwarf/ts/dwarf_attrlist/ec32-g1.xml.gz and b/test/libdwarf/ts/dwarf_attrlist/ec32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_attrlist/ec64-g1.xml.gz b/test/libdwarf/ts/dwarf_attrlist/ec64-g1.xml.gz index 13581a27d24c..19faaf701f76 100644 Binary files a/test/libdwarf/ts/dwarf_attrlist/ec64-g1.xml.gz and b/test/libdwarf/ts/dwarf_attrlist/ec64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_attrlist/ld_symver.o-64-g1.xml.gz b/test/libdwarf/ts/dwarf_attrlist/ld_symver.o-64-g1.xml.gz new file mode 100644 index 000000000000..b78ab0abd9b2 Binary files /dev/null and b/test/libdwarf/ts/dwarf_attrlist/ld_symver.o-64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_die_query/Makefile b/test/libdwarf/ts/dwarf_die_query/Makefile index efcf1bc97c4e..0f99aa3e1bbf 100644 --- a/test/libdwarf/ts/dwarf_die_query/Makefile +++ b/test/libdwarf/ts/dwarf_die_query/Makefile @@ -1,8 +1,8 @@ -# $Id: Makefile 2084 2011-10-27 04:48:12Z jkoshy $ +# $Id: Makefile 3075 2014-06-23 03:08:57Z kaiwang27 $ TOP= ../../../.. TS_SRCS= dwarf_die_query.c -TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 dto64-g1 +TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 dto64-g1 ld_symver.o-64-g1 .include "${TOP}/mk/elftoolchain.tet.mk" diff --git a/test/libdwarf/ts/dwarf_die_query/dt32-g1.xml.gz b/test/libdwarf/ts/dwarf_die_query/dt32-g1.xml.gz index 2cda689a7945..1fc085142117 100644 Binary files a/test/libdwarf/ts/dwarf_die_query/dt32-g1.xml.gz and b/test/libdwarf/ts/dwarf_die_query/dt32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_die_query/dt64-g1.xml.gz b/test/libdwarf/ts/dwarf_die_query/dt64-g1.xml.gz index 211645acbf43..6a1a6fd54759 100644 Binary files a/test/libdwarf/ts/dwarf_die_query/dt64-g1.xml.gz and b/test/libdwarf/ts/dwarf_die_query/dt64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_die_query/dto64-g1.xml.gz b/test/libdwarf/ts/dwarf_die_query/dto64-g1.xml.gz index 7b2d38d04585..2cd4ea5a2ff7 100644 Binary files a/test/libdwarf/ts/dwarf_die_query/dto64-g1.xml.gz and b/test/libdwarf/ts/dwarf_die_query/dto64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_die_query/dwarf_die_query.c b/test/libdwarf/ts/dwarf_die_query/dwarf_die_query.c index 45b9c44d1abe..5c99fc230497 100644 --- a/test/libdwarf/ts/dwarf_die_query/dwarf_die_query.c +++ b/test/libdwarf/ts/dwarf_die_query/dwarf_die_query.c @@ -1,154 +1,178 @@ /*- * Copyright (c) 2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dwarf_die_query.c 2084 2011-10-27 04:48:12Z jkoshy $ + * $Id: dwarf_die_query.c 3075 2014-06-23 03:08:57Z kaiwang27 $ */ #include #include #include #include #include #include #include "driver.h" #include "tet_api.h" /* * Test case for DIE query functions: dwarf_tag, dwarf_die_abbrev_code, * dwarf_diename and dwarf_dieoffset. */ static void tp_dwarf_die_query(void); +static void tp_dwarf_die_query_types(void); static void tp_dwarf_die_query_sanity(void); static struct dwarf_tp dwarf_tp_array[] = { {"tp_dwarf_die_query", tp_dwarf_die_query}, + {"tp_dwarf_die_query_types", tp_dwarf_die_query_types}, {"tp_dwarf_die_query_sanity", tp_dwarf_die_query_sanity}, {NULL, NULL}, }; static int result = TET_UNRESOLVED; #include "driver.c" #include "die_traverse.c" +#include "die_traverse2.c" static void _dwarf_die_query(Dwarf_Die die) { Dwarf_Half tag; Dwarf_Error de; char *die_name; int abbrev_code, dwarf_diename_ret; /* Check DIE abbreviation code. */ abbrev_code = dwarf_die_abbrev_code(die); TS_CHECK_INT(abbrev_code); /* Check DIE tag. */ if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { tet_printf("dwarf_tag failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_UINT(tag); /* Check DIE name. */ dwarf_diename_ret = dwarf_diename(die, &die_name, &de); TS_CHECK_INT(dwarf_diename_ret); if (dwarf_diename_ret == DW_DLV_ERROR) { tet_printf("dwarf_diename failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; } else if (dwarf_diename_ret == DW_DLV_OK) TS_CHECK_STRING(die_name); } static void tp_dwarf_die_query(void) { Dwarf_Debug dbg; Dwarf_Error de; int fd; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); TS_DWARF_DIE_TRAVERSE(dbg, _dwarf_die_query); if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } +static void +tp_dwarf_die_query_types(void) +{ + Dwarf_Debug dbg; + Dwarf_Error de; + int fd; + + result = TET_UNRESOLVED; + + TS_DWARF_INIT(dbg, fd, de); + + TS_DWARF_DIE_TRAVERSE2(dbg, 0, _dwarf_die_query); + + if (result == TET_UNRESOLVED) + result = TET_PASS; + +done: + TS_DWARF_FINISH(dbg, de); + TS_RESULT(result); +} + static void tp_dwarf_die_query_sanity(void) { Dwarf_Debug dbg; Dwarf_Die die; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned cu_next_offset; char *die_name; int fd; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); TS_DWARF_CU_FOREACH(dbg, cu_next_offset, de) { if (dwarf_siblingof(dbg, NULL, &die, &de) == DW_DLV_ERROR) { tet_printf("dwarf_siblingof failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; goto done; } if (dwarf_tag(NULL, &tag, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_tag didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { tet_printf("dwarf_tag failed: %s", dwarf_errmsg(de)); result = TET_FAIL; goto done; } TS_CHECK_UINT(tag); if (dwarf_diename(NULL, &die_name, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_diename didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } } if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } diff --git a/test/libdwarf/ts/dwarf_die_query/ec32-g1.xml.gz b/test/libdwarf/ts/dwarf_die_query/ec32-g1.xml.gz index d54847f126ea..0dde7100876f 100644 Binary files a/test/libdwarf/ts/dwarf_die_query/ec32-g1.xml.gz and b/test/libdwarf/ts/dwarf_die_query/ec32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_die_query/ec64-g1.xml.gz b/test/libdwarf/ts/dwarf_die_query/ec64-g1.xml.gz index 21559130a679..3c9890e18d00 100644 Binary files a/test/libdwarf/ts/dwarf_die_query/ec64-g1.xml.gz and b/test/libdwarf/ts/dwarf_die_query/ec64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_die_query/ld_symver.o-64-g1.xml.gz b/test/libdwarf/ts/dwarf_die_query/ld_symver.o-64-g1.xml.gz new file mode 100644 index 000000000000..c8de24e2c300 Binary files /dev/null and b/test/libdwarf/ts/dwarf_die_query/ld_symver.o-64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_form/Makefile b/test/libdwarf/ts/dwarf_form/Makefile index a64bd6f6f2ba..a1f193ada1b2 100644 --- a/test/libdwarf/ts/dwarf_form/Makefile +++ b/test/libdwarf/ts/dwarf_form/Makefile @@ -1,8 +1,8 @@ -# $Id: Makefile 2084 2011-10-27 04:48:12Z jkoshy $ +# $Id: Makefile 3084 2014-09-02 22:08:13Z kaiwang27 $ TOP= ../../../.. TS_SRCS= dwarf_form.c -TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 +TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 ld_symver.o-64-g1 .include "${TOP}/mk/elftoolchain.tet.mk" diff --git a/test/libdwarf/ts/dwarf_form/dt32-g1.xml.gz b/test/libdwarf/ts/dwarf_form/dt32-g1.xml.gz index b15226e85f10..afc398d021aa 100644 Binary files a/test/libdwarf/ts/dwarf_form/dt32-g1.xml.gz and b/test/libdwarf/ts/dwarf_form/dt32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_form/dt64-g1.xml.gz b/test/libdwarf/ts/dwarf_form/dt64-g1.xml.gz index 62b6aa268730..257b4687bd50 100644 Binary files a/test/libdwarf/ts/dwarf_form/dt64-g1.xml.gz and b/test/libdwarf/ts/dwarf_form/dt64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_form/dwarf_form.c b/test/libdwarf/ts/dwarf_form/dwarf_form.c index 8567b5a14491..5ef73d3f486b 100644 --- a/test/libdwarf/ts/dwarf_form/dwarf_form.c +++ b/test/libdwarf/ts/dwarf_form/dwarf_form.c @@ -1,270 +1,284 @@ /*- * Copyright (c) 2010 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dwarf_form.c 2084 2011-10-27 04:48:12Z jkoshy $ + * $Id: dwarf_form.c 3084 2014-09-02 22:08:13Z kaiwang27 $ */ #include #include #include #include #include #include #include "driver.h" #include "tet_api.h" /* * Test case for DWARF attribute query functions. */ static void tp_dwarf_form(void); static void tp_dwarf_form_sanity(void); static struct dwarf_tp dwarf_tp_array[] = { {"tp_dwarf_form", tp_dwarf_form}, {"tp_dwarf_form_sanity", tp_dwarf_form_sanity}, {NULL, NULL}, }; static int result = TET_UNRESOLVED; #include "driver.c" -#include "die_traverse.c" +#include "die_traverse2.c" static void _dwarf_form(Dwarf_Die die) { Dwarf_Attribute *attrlist, at; Dwarf_Signed attrcount; Dwarf_Half form, direct_form; Dwarf_Off offset; Dwarf_Addr addr; Dwarf_Bool flag, hasform; Dwarf_Unsigned uvalue; Dwarf_Signed svalue; Dwarf_Block *block; + Dwarf_Sig8 sig8; + Dwarf_Ptr ptr; Dwarf_Error de; char *str; int i, r; int r_formref, r_global_formref, r_formaddr, r_formflag; int r_formudata, r_formsdata, r_formblock, r_formstring; + int r_formsig8, r_formexprloc; r = dwarf_attrlist(die, &attrlist, &attrcount, &de); if (r == DW_DLV_ERROR) { tet_printf("dwarf_attrlist failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; return; } else if (r == DW_DLV_NO_ENTRY) return; for (i = 0; i < attrcount; i++) { at = attrlist[i]; if (dwarf_whatform(at, &form, &de) != DW_DLV_OK) { tet_printf("dwarf_whatform failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; continue; } TS_CHECK_UINT(form); if (dwarf_hasform(at, form, &hasform, &de) != DW_DLV_OK) { tet_printf("dwarf_hasform failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; } if (!hasform) { tet_infoline("dwarf_hasform contradicts with" " dwarf_whatform"); result = TET_FAIL; } if (dwarf_whatform_direct(at, &direct_form, &de) != DW_DLV_OK) { tet_printf("dwarf_whatform_direct failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_UINT(direct_form); r_formref = dwarf_formref(at, &offset, &de); TS_CHECK_INT(r_formref); if (r_formref == DW_DLV_OK) TS_CHECK_INT(offset); r_global_formref = dwarf_global_formref(at, &offset, &de); TS_CHECK_INT(r_global_formref); if (r_global_formref == DW_DLV_OK) TS_CHECK_INT(offset); r_formaddr = dwarf_formaddr(at, &addr, &de); TS_CHECK_INT(r_formaddr); if (r_formaddr == DW_DLV_OK) TS_CHECK_UINT(addr); r_formflag = dwarf_formflag(at, &flag, &de); TS_CHECK_INT(r_formflag); if (r_formflag == DW_DLV_OK) TS_CHECK_INT(flag); r_formudata = dwarf_formudata(at, &uvalue, &de); TS_CHECK_INT(r_formudata); if (r_formudata == DW_DLV_OK) TS_CHECK_UINT(uvalue); r_formsdata = dwarf_formsdata(at, &svalue, &de); TS_CHECK_INT(r_formsdata); if (r_formsdata == DW_DLV_OK) TS_CHECK_INT(svalue); r_formblock = dwarf_formblock(at, &block, &de); TS_CHECK_INT(r_formblock); if (r_formblock == DW_DLV_OK) TS_CHECK_BLOCK(block->bl_data, block->bl_len); r_formstring = dwarf_formstring(at, &str, &de); TS_CHECK_INT(r_formstring); if (r_formstring == DW_DLV_OK) TS_CHECK_STRING(str); + + r_formsig8 = dwarf_formsig8(at, &sig8, &de); + TS_CHECK_INT(r_formsig8); + if (r_formsig8 == DW_DLV_OK) + TS_CHECK_BLOCK(sig8.signature, 8); + + r_formexprloc = dwarf_formexprloc(at, &uvalue, &ptr, &de); + TS_CHECK_INT(r_formexprloc); + if (r_formexprloc == DW_DLV_OK) + TS_CHECK_BLOCK(ptr, uvalue); } } static void tp_dwarf_form(void) { Dwarf_Debug dbg; Dwarf_Error de; int fd; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); - TS_DWARF_DIE_TRAVERSE(dbg, _dwarf_form); + TS_DWARF_DIE_TRAVERSE2(dbg, 1, _dwarf_form); + TS_DWARF_DIE_TRAVERSE2(dbg, 0, _dwarf_form); if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } static void tp_dwarf_form_sanity(void) { Dwarf_Debug dbg; Dwarf_Error de; Dwarf_Half form, direct_form; Dwarf_Off offset; Dwarf_Addr addr; Dwarf_Bool flag, hasform; Dwarf_Unsigned uvalue; Dwarf_Signed svalue; Dwarf_Block *block; char *str; int fd; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); if (dwarf_whatform(NULL, &form, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_whatform didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_whatform_direct(NULL, &direct_form, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_whatform_direct didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_hasform(NULL, DW_FORM_indirect, &hasform, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_hasform didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formref(NULL, &offset, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formref didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_global_formref(NULL, &offset, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_global_formref didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formaddr(NULL, &addr, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formaddr didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formflag(NULL, &flag, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formflag didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formudata(NULL, &uvalue, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formudata didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formsdata(NULL, &svalue, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formsdata didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formblock(NULL, &block, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formblock didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (dwarf_formstring(NULL, &str, &de) != DW_DLV_ERROR) { tet_infoline("dwarf_formstring didn't return DW_DLV_ERROR" " when called with NULL arguments"); result = TET_FAIL; goto done; } if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } diff --git a/test/libdwarf/ts/dwarf_form/ec32-g1.xml.gz b/test/libdwarf/ts/dwarf_form/ec32-g1.xml.gz index 8342c21cf7e1..bf8b65ed07b4 100644 Binary files a/test/libdwarf/ts/dwarf_form/ec32-g1.xml.gz and b/test/libdwarf/ts/dwarf_form/ec32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_form/ec64-g1.xml.gz b/test/libdwarf/ts/dwarf_form/ec64-g1.xml.gz index b046c5b90237..1c964962fc4e 100644 Binary files a/test/libdwarf/ts/dwarf_form/ec64-g1.xml.gz and b/test/libdwarf/ts/dwarf_form/ec64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_form/ld_symver.o-64-g1.xml.gz b/test/libdwarf/ts/dwarf_form/ld_symver.o-64-g1.xml.gz new file mode 100644 index 000000000000..22c60db86842 Binary files /dev/null and b/test/libdwarf/ts/dwarf_form/ld_symver.o-64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_next_cu_header/Makefile b/test/libdwarf/ts/dwarf_next_cu_header/Makefile index ef798c118a56..ad29f1efa8ee 100644 --- a/test/libdwarf/ts/dwarf_next_cu_header/Makefile +++ b/test/libdwarf/ts/dwarf_next_cu_header/Makefile @@ -1,8 +1,8 @@ -# $Id: Makefile 2084 2011-10-27 04:48:12Z jkoshy $ +# $Id: Makefile 3073 2014-06-23 03:08:49Z kaiwang27 $ TOP= ../../../.. TS_SRCS= dwarf_next_cu_header.c -TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 +TS_DATA= dt32-g1 dt64-g1 ec32-g1 ec64-g1 ld_symver.o-64-g1 .include "${TOP}/mk/elftoolchain.tet.mk" diff --git a/test/libdwarf/ts/dwarf_next_cu_header/dt32-g1.xml.gz b/test/libdwarf/ts/dwarf_next_cu_header/dt32-g1.xml.gz index e9f788ca68f3..7ba737cc6e97 100644 Binary files a/test/libdwarf/ts/dwarf_next_cu_header/dt32-g1.xml.gz and b/test/libdwarf/ts/dwarf_next_cu_header/dt32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_next_cu_header/dt64-g1.xml.gz b/test/libdwarf/ts/dwarf_next_cu_header/dt64-g1.xml.gz index 60dfb4202084..93a44424c7d1 100644 Binary files a/test/libdwarf/ts/dwarf_next_cu_header/dt64-g1.xml.gz and b/test/libdwarf/ts/dwarf_next_cu_header/dt64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_next_cu_header/dwarf_next_cu_header.c b/test/libdwarf/ts/dwarf_next_cu_header/dwarf_next_cu_header.c index acfe506bb869..b5a580d49753 100644 --- a/test/libdwarf/ts/dwarf_next_cu_header/dwarf_next_cu_header.c +++ b/test/libdwarf/ts/dwarf_next_cu_header/dwarf_next_cu_header.c @@ -1,149 +1,209 @@ /*- - * Copyright (c) 2010 Kai Wang + * Copyright (c) 2010,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dwarf_next_cu_header.c 2084 2011-10-27 04:48:12Z jkoshy $ + * $Id: dwarf_next_cu_header.c 3073 2014-06-23 03:08:49Z kaiwang27 $ */ #include #include #include #include #include #include #include "driver.h" #include "tet_api.h" static void tp_dwarf_next_cu_header(void); static void tp_dwarf_next_cu_header_b(void); +static void tp_dwarf_next_cu_header_c(void); static void tp_dwarf_next_cu_header_loop(void); static struct dwarf_tp dwarf_tp_array[] = { {"tp_dwarf_next_cu_header", tp_dwarf_next_cu_header}, {"tp_dwarf_next_cu_header_b", tp_dwarf_next_cu_header_b}, + {"tp_dwarf_next_cu_header_c", tp_dwarf_next_cu_header_c}, {"tp_dwarf_next_cu_header_loop", tp_dwarf_next_cu_header_loop}, {NULL, NULL}, }; #include "driver.c" static void tp_dwarf_next_cu_header(void) { Dwarf_Debug dbg; Dwarf_Error de; Dwarf_Unsigned cu_header_length; Dwarf_Half cu_version; Dwarf_Off cu_abbrev_offset; Dwarf_Half cu_pointer_size; Dwarf_Unsigned cu_next_offset; int fd, result; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); while (dwarf_next_cu_header(dbg, &cu_header_length, &cu_version, &cu_abbrev_offset, &cu_pointer_size, &cu_next_offset, &de) == DW_DLV_OK) { TS_CHECK_UINT(cu_header_length); TS_CHECK_UINT(cu_version); TS_CHECK_INT(cu_abbrev_offset); TS_CHECK_UINT(cu_pointer_size); TS_CHECK_UINT(cu_next_offset); } if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } static void tp_dwarf_next_cu_header_b(void) { Dwarf_Debug dbg; Dwarf_Error de; Dwarf_Unsigned cu_header_length; Dwarf_Half cu_version; Dwarf_Off cu_abbrev_offset; Dwarf_Half cu_pointer_size; Dwarf_Half cu_offset_size; Dwarf_Half cu_extension_size; Dwarf_Unsigned cu_next_offset; int fd, result; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); while (dwarf_next_cu_header_b(dbg, &cu_header_length, &cu_version, - &cu_abbrev_offset, &cu_pointer_size, &cu_offset_size, - &cu_extension_size, &cu_next_offset, &de) == DW_DLV_OK) { + &cu_abbrev_offset, &cu_pointer_size, &cu_offset_size, + &cu_extension_size, &cu_next_offset, &de) == DW_DLV_OK) { TS_CHECK_UINT(cu_header_length); TS_CHECK_UINT(cu_version); TS_CHECK_INT(cu_abbrev_offset); TS_CHECK_UINT(cu_pointer_size); TS_CHECK_UINT(cu_offset_size); TS_CHECK_UINT(cu_extension_size); TS_CHECK_UINT(cu_next_offset); } if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } +static void +tp_dwarf_next_cu_header_c(void) +{ + Dwarf_Debug dbg; + Dwarf_Error de; + Dwarf_Unsigned cu_header_length; + Dwarf_Half cu_version; + Dwarf_Off cu_abbrev_offset; + Dwarf_Half cu_pointer_size; + Dwarf_Half cu_offset_size; + Dwarf_Half cu_extension_size; + Dwarf_Sig8 cu_type_sig; + Dwarf_Unsigned cu_type_offset; + Dwarf_Unsigned cu_next_offset; + int fd, result; + + result = TET_UNRESOLVED; + + TS_DWARF_INIT(dbg, fd, de); + + while (dwarf_next_cu_header_c(dbg, 1, &cu_header_length, &cu_version, + &cu_abbrev_offset, &cu_pointer_size, &cu_offset_size, + &cu_extension_size, NULL, NULL, &cu_next_offset, &de) == + DW_DLV_OK) { + TS_CHECK_UINT(cu_header_length); + TS_CHECK_UINT(cu_version); + TS_CHECK_INT(cu_abbrev_offset); + TS_CHECK_UINT(cu_pointer_size); + TS_CHECK_UINT(cu_offset_size); + TS_CHECK_UINT(cu_extension_size); + TS_CHECK_UINT(cu_next_offset); + } + + do { + while (dwarf_next_cu_header_c(dbg, 0, &cu_header_length, + &cu_version, &cu_abbrev_offset, &cu_pointer_size, + &cu_offset_size, &cu_extension_size, &cu_type_sig, + &cu_type_offset, &cu_next_offset, &de) == DW_DLV_OK) { + TS_CHECK_UINT(cu_header_length); + TS_CHECK_UINT(cu_version); + TS_CHECK_INT(cu_abbrev_offset); + TS_CHECK_UINT(cu_pointer_size); + TS_CHECK_UINT(cu_offset_size); + TS_CHECK_UINT(cu_extension_size); + TS_CHECK_BLOCK(cu_type_sig.signature, 8); + TS_CHECK_UINT(cu_type_offset); + TS_CHECK_UINT(cu_next_offset); + } + } while (dwarf_next_types_section(dbg, &de) == DW_DLV_OK); + + if (result == TET_UNRESOLVED) + result = TET_PASS; + +done: + TS_DWARF_FINISH(dbg, de); + TS_RESULT(result); +} + #define _LOOP_COUNT 50 static void tp_dwarf_next_cu_header_loop(void) { Dwarf_Debug dbg; Dwarf_Error de; int i, r, fd, result; Dwarf_Unsigned cu_next_offset; result = TET_UNRESOLVED; TS_DWARF_INIT(dbg, fd, de); for (i = 0; i < _LOOP_COUNT; i++) { tet_printf("dwarf_next_cu_header loop(%d)\n", i); r = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, &cu_next_offset, &de); TS_CHECK_INT(r); } if (result == TET_UNRESOLVED) result = TET_PASS; done: TS_DWARF_FINISH(dbg, de); TS_RESULT(result); } diff --git a/test/libdwarf/ts/dwarf_next_cu_header/ec32-g1.xml.gz b/test/libdwarf/ts/dwarf_next_cu_header/ec32-g1.xml.gz index 6efbf28a509d..c613d8ec741e 100644 Binary files a/test/libdwarf/ts/dwarf_next_cu_header/ec32-g1.xml.gz and b/test/libdwarf/ts/dwarf_next_cu_header/ec32-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_next_cu_header/ec64-g1.xml.gz b/test/libdwarf/ts/dwarf_next_cu_header/ec64-g1.xml.gz index e03947ddbac5..180062815342 100644 Binary files a/test/libdwarf/ts/dwarf_next_cu_header/ec64-g1.xml.gz and b/test/libdwarf/ts/dwarf_next_cu_header/ec64-g1.xml.gz differ diff --git a/test/libdwarf/ts/dwarf_next_cu_header/ld_symver.o-64-g1.xml.gz b/test/libdwarf/ts/dwarf_next_cu_header/ld_symver.o-64-g1.xml.gz new file mode 100644 index 000000000000..adf56ab1f756 Binary files /dev/null and b/test/libdwarf/ts/dwarf_next_cu_header/ld_symver.o-64-g1.xml.gz differ diff --git a/test/libelf/Makefile b/test/libelf/Makefile index 903221d9bafa..f7a3903e2b9e 100644 --- a/test/libelf/Makefile +++ b/test/libelf/Makefile @@ -1,36 +1,6 @@ -# $Id: Makefile 2137 2011-11-10 13:09:30Z jkoshy $ - -TOP = ../.. - -.include "${TOP}/mk/elftoolchain.tetvars.mk" - -.if !defined(TET_EXECUTE) -TET_EXECUTE= ${.OBJDIR} -.endif - -.if make(tccbuild) -TET_OPTIONS+= -b -.endif - -.if make(tccclean) -TET_OPTIONS+= -c -.endif - -.if make(execute) || make(test) -TET_OPTIONS+= -e -.endif - -.MAIN: all - -.PHONY: clobber execute tccbuild tccclean test - -execute tccbuild tccclean test: - TET_ROOT=${TET_ROOT} TET_EXECUTE=${TET_EXECUTE} \ - TET_SUITE_ROOT=${.CURDIR} ${TET_ROOT}/bin/tcc ${TET_OPTIONS} . - -clobber: clean - rm -rf ${TET_RESULTS_DIR} ${TET_TMP_DIR} +# $Id: Makefile 3028 2014-04-18 16:20:43Z jkoshy $ +TOP= ../.. SUBDIR= tset -.include +.include "${TOP}/mk/elftoolchain.tetbase.mk" diff --git a/test/libelf/tset/Makefile b/test/libelf/tset/Makefile index 707a3ab82137..63e958691306 100644 --- a/test/libelf/tset/Makefile +++ b/test/libelf/tset/Makefile @@ -1,58 +1,60 @@ # -# $Id: Makefile 1638 2011-07-10 15:43:19Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ # +TOP= ../../.. + SUBDIR+= common # must be first SUBDIR+= abi SUBDIR+= elf_begin SUBDIR+= elf_cntl SUBDIR+= elf_end SUBDIR+= elf_errmsg SUBDIR+= elf_errno SUBDIR+= elf_fill SUBDIR+= elf_flagarhdr SUBDIR+= elf_flagdata SUBDIR+= elf_flagehdr SUBDIR+= elf_flagelf SUBDIR+= elf_flagphdr SUBDIR+= elf_flagscn SUBDIR+= elf_flagshdr SUBDIR+= elf_fsize SUBDIR+= elf_getarhdr SUBDIR+= elf_getarsym SUBDIR+= elf_getbase SUBDIR+= elf_getdata SUBDIR+= elf_getident SUBDIR+= elf_getscn SUBDIR+= elf_getshnum SUBDIR+= elf_getshstrndx SUBDIR+= elf_hash SUBDIR+= elf_kind SUBDIR+= elf_memory SUBDIR+= elf_ndxscn SUBDIR+= elf_next SUBDIR+= elf_newscn SUBDIR+= elf_nextscn SUBDIR+= elf_rawfile SUBDIR+= elf_strptr SUBDIR+= elf_update SUBDIR+= elf_version SUBDIR+= elf32_getehdr SUBDIR+= elf32_getphdr SUBDIR+= elf32_getshdr SUBDIR+= elf32_newehdr SUBDIR+= elf32_xlatetof SUBDIR+= elf32_xlatetom SUBDIR+= elf64_getehdr SUBDIR+= elf64_getphdr SUBDIR+= elf64_getshdr SUBDIR+= elf64_newehdr SUBDIR+= elf64_xlatetof SUBDIR+= elf64_xlatetom SUBDIR+= gelf_getclass SUBDIR+= gelf_getehdr SUBDIR+= gelf_newehdr SUBDIR+= gelf_xlate -.include +.include "${TOP}/mk/elftoolchain.subdir.mk" diff --git a/test/libelf/tset/elf_update/update.m4 b/test/libelf/tset/elf_update/update.m4 index e1d3e6b33f53..5d7e789a8e9c 100644 --- a/test/libelf/tset/elf_update/update.m4 +++ b/test/libelf/tset/elf_update/update.m4 @@ -1,2308 +1,2390 @@ /*- * Copyright (c) 2006,2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: update.m4 2833 2012-12-30 16:16:51Z jkoshy $ + * $Id: update.m4 3081 2014-07-28 08:53:14Z jkoshy $ */ #include #include #include #include #include #include #include #include #include #include "elfts.h" #include "tet_api.h" include(`elfts.m4') define(`TS_OFFSET_SHDR',512) define(`MAKE_EM', `ifelse($1,32, ifelse($2,msb,EM_SPARC,EM_386), ifelse($2,msb,EM_SPARCV9,EM_X86_64))') /* * Tests for the `elf_update' API. */ IC_REQUIRES_VERSION_INIT(); static char rawdata[] = "This is not an ELF file."; /* * A NULL Elf argument returns ELF_E_ARGUMENT. */ void tcArgsNull(void) { int error, result; off_t offset; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("elf_update(NULL,*) fails with ELF_E_ARGUMENT."); if ((offset = elf_update(NULL, 0)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_ARGUMENT) { TP_FAIL("elf_update() did not fail with ELF_E_ARGUMENT; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: tet_result(result); } /* * Illegal values for argument `cmd' are rejected. */ void tcArgsBadCmd(void) { Elf *e; Elf_Cmd c; int error, result; off_t offset; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("illegal cmd values are rejected with ELF_E_ARGUMENT."); TS_OPEN_MEMORY(e, rawdata); result = TET_PASS; for (c = ELF_C_NULL-1; result == TET_PASS && c < ELF_C_NUM; c++) { if (c == ELF_C_WRITE || c == ELF_C_NULL) /* legal values */ continue; if ((offset = elf_update(e, c)) != (off_t) -1) TP_FAIL("elf_update() succeeded unexpectedly; " "offset=%jd.", (intmax_t) offset); else if ((error = elf_errno()) != ELF_E_ARGUMENT) TP_FAIL("elf_update() did not fail with " "ELF_E_ARGUMENT; error=%d \"%s\".", error, elf_errmsg(error)); } (void) elf_end(e); tet_result(result); } /* * Non-ELF descriptors are rejected by elf_update(). */ undefine(`FN') define(`FN',` void tcArgsNonElf$1(void) { Elf *e; int error, fd, result; off_t offset; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("elf_update(non-elf,ELF_C_$1) returns ELF_E_ARGUMENT."); result = TET_UNRESOLVED; e = NULL; fd = -1; _TS_WRITE_FILE(TS_NEWFILE,rawdata,sizeof(rawdata),goto done;); _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_READ, fd, goto done;); if ((offset = elf_update(e, ELF_C_$1)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_ARGUMENT) { TP_FAIL("elf_update() did not fail with ELF_E_ARGUMENT; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); }') FN(`NULL') FN(`WRITE') /* * In-memory (i.e., non-writeable) ELF objects are rejected for * ELF_C_WRITE with error ELF_E_MODE. */ undefine(`FN') define(`FN',` void tcMemElfWrite$1$2(void) { Elf *e; off_t offset; int error, result; char elf[sizeof(Elf64_Ehdr)]; /* larger of the Ehdr variants */ TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: ELF_C_WRITE with in-memory objects " "returns ELF_E_MODE."); result = TET_UNRESOLVED; e = NULL; _TS_READ_FILE("newehdr.$2$1", elf, sizeof(elf), goto done;); TS_OPEN_MEMORY(e, elf); if ((offset = elf_update(e, ELF_C_WRITE)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_MODE) { TP_FAIL("elf_update() did not fail with ELF_E_MODE; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: (void) elf_end(e); tet_result(result); }') FN(`32', `lsb') FN(`32', `msb') FN(`64', `lsb') FN(`64', `msb') /* * In-memory ELF objects are updateable with command ELF_C_NULL. */ undefine(`FN') define(`FN',` void tcMemElfNull$1$2(void) { Elf *e; int result; size_t fsz; off_t offset; char elf[sizeof(Elf64_Ehdr)]; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: ELF_C_NULL updates in-memory objects."); result = TET_UNRESOLVED; _TS_READ_FILE("newehdr.$2$1", elf, sizeof(elf), goto done;); TS_OPEN_MEMORY(e, elf); if ((fsz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0) { TP_UNRESOLVED("elf$2_fsize() failed: %s.", elf_errmsg(-1)); goto done; } result = TET_PASS; if ((offset = elf_update(e, ELF_C_NULL)) != fsz) TP_FAIL("offset=%jd != %d, error=%d \"%s\".", (intmax_t) offset, fsz, elf_errmsg(-1)); done: (void) elf_end(e); tet_result(result); }') FN(`32', `lsb') FN(`32', `msb') FN(`64', `lsb') FN(`64', `msb') /* * A mismatched class in the Ehdr returns an ELF_E_CLASS error. */ undefine(`FN') define(`FN',` void tcClassMismatch$1$2(void) { int error, fd, result; off_t offset; Elf *e; Elf$1_Ehdr *eh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: a class-mismatch is detected."); result = TET_UNRESOLVED; e = NULL; fd = -1; TS_OPEN_FILE(e, "newehdr.$2$1", ELF_C_READ, fd); if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: %s", elf_errmsg(-1)); goto done; } /* change the class */ eh->e_ident[EI_CLASS] = ELFCLASS`'ifelse($1,32,64,32); if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_CLASS) { TP_FAIL("elf_update() did not fail with ELF_E_CLASS; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); tet_result(result); }') FN(`32', `lsb') FN(`32', `msb') FN(`64', `lsb') FN(`64', `msb') /* * Changing the byte order of an ELF file on the fly is not allowed. */ undefine(`FN') define(`FN',` void tcByteOrderChange$1$2(void) { int error, fd, result; Elf *e; off_t offset; Elf$1_Ehdr *eh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: byte order changes are rejected."); result = TET_UNRESOLVED; e = NULL; fd = -1; TS_OPEN_FILE(e, "newehdr.$2$1", ELF_C_READ, fd); if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: %s.", elf_errmsg(-1)); goto done; } eh->e_ident[EI_DATA] = ELFDATA2`'ifelse($2,`lsb',`MSB',`LSB'); if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_HEADER) { TP_FAIL("elf_update() did not fail with ELF_E_HEADER; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); tet_result(result); }') FN(`32', `lsb') FN(`32', `msb') FN(`64', `lsb') FN(`64', `msb') /* * An unsupported ELF version is rejected with ELF_E_VERSION. */ undefine(`FN') define(`FN',` void tcUnsupportedVersion$1$2(void) { int error, fd, result; off_t offset; Elf *e; Elf$1_Ehdr *eh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: version changes are rejected."); result = TET_UNRESOLVED; e = NULL; fd = -1; TS_OPEN_FILE(e, "newehdr.$2$1", ELF_C_READ, fd); if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: %s.", elf_errmsg(-1)); goto done; } eh->e_version = EV_CURRENT+1; if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_VERSION) { TP_FAIL("elf_update() did not fail with ELF_E_VERSION; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); tet_result(result); }') FN(`32', `lsb') FN(`32', `msb') FN(`64', `lsb') FN(`64', `msb') /* * Invoking an elf_cntl(ELF_C_FDDONE) causes a subsequent elf_update() * to fail with ELF_E_SEQUENCE. */ undefine(`FN') define(`FN',` void tcSequenceFdDoneWrite$1(void) { int error, fd, result; off_t offset; Elf *e; Elf$1_Ehdr *eh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("*$1: elf_update(ELF_C_WRITE) after an elf_cntl(FDDONE) " "is rejected."); result = TET_UNRESOLVED; e = NULL; fd = -1; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: %s.", elf_errmsg(-1)); goto done; } if (elf_cntl(e, ELF_C_FDDONE) != 0) { TP_UNRESOLVED("elf_cntl() failed: %s.", elf_errmsg(-1)); goto done; } if ((offset = elf_update(e, ELF_C_WRITE)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_SEQUENCE) { TP_FAIL("elf_update() did not fail with ELF_E_SEQUENCE; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); tet_result(result); }') FN(32) FN(64) /* * Invoking an elf_cntl(ELF_C_FDDONE) causes a subsequent * elf_update(ELF_C_NULL) to succeed. */ undefine(`FN') define(`FN',` void tcSequenceFdDoneNull$1(void) { int fd, result; off_t offset; size_t fsz; Elf *e; Elf$1_Ehdr *eh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("elf_update(ELF_C_NULL) after an elf_cntl(FDDONE) " "succeeds."); result = TET_UNRESOLVED; e = NULL; fd = -1; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: %s.", elf_errmsg(-1)); goto done; } if (elf_cntl(e, ELF_C_FDDONE) != 0) { TP_UNRESOLVED("elf_cntl() failed: %s.", elf_errmsg(-1)); goto done; } if ((fsz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0) { TP_UNRESOLVED("fsize() failed: %s.", elf_errmsg(-1)); goto done; } if ((offset = elf_update(e, ELF_C_NULL)) != fsz) { TP_FAIL("elf_update()->%jd, (expected %d).", (intmax_t) offset, fsz); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); tet_result(result); }') FN(32) FN(64) /* * Check that elf_update() can create a legal ELF file. */ const char strtab[] = { '\0', '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0' }; #define INIT_PHDR(P) do { \ (P)->p_type = PT_NULL; \ (P)->p_offset = 0x0F0F0F0F; \ (P)->p_vaddr = 0xA0A0A0A0; \ (P)->p_filesz = 0x1234; \ (P)->p_memsz = 0x5678; \ (P)->p_flags = PF_X | PF_R; \ (P)->p_align = 64; \ } while (0) #define INIT_SHDR(S,O) do { \ (S)->sh_name = 1; \ (S)->sh_type = SHT_STRTAB; \ (S)->sh_flags = 0; \ (S)->sh_addr = 0; \ (S)->sh_offset = (O); \ (S)->sh_size = sizeof(strtab); \ (S)->sh_link = 0; \ (S)->sh_info = 0; \ (S)->sh_addralign = 1; \ (S)->sh_entsize = 0; \ } while (0) undefine(`FN') define(`FN',` void tcUpdate$1$2(void) { int fd, result; off_t offset; size_t esz, fsz, psz, roundup, ssz; Elf$1_Shdr *sh; Elf$1_Ehdr *eh; Elf$1_Phdr *ph; Elf_Data *d; Elf_Scn *scn; Elf *e; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: elf_update() creates a legal ELF file."); result = TET_UNRESOLVED; fd = -1; e = NULL; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Set the version and endianness */ eh->e_version = EV_CURRENT; eh->e_ident[EI_DATA] = ELFDATA2`'TOUPPER($2); eh->e_type = ET_REL; if ((esz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0 || (psz = elf$1_fsize(ELF_T_PHDR, 1, EV_CURRENT)) == 0 || (ssz = elf$1_fsize(ELF_T_SHDR, 2, EV_CURRENT)) == 0) { TP_UNRESOLVED("elf$1_fsize() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((ph = elf$1_newphdr(e,1)) == NULL) { TP_UNRESOLVED("elf$1_newphdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } INIT_PHDR(ph); if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } eh->e_shstrndx = elf_ndxscn(scn); if ((sh = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((d = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } d->d_buf = (char *) strtab; d->d_size = sizeof(strtab); d->d_off = (off_t) 0; INIT_SHDR(sh, esz+psz); fsz = esz + psz + sizeof(strtab); roundup = ifelse($1,32,4,8); fsz = (fsz + roundup - 1) & ~(roundup - 1); fsz += ssz; if ((offset = elf_update(e, ELF_C_WRITE)) != fsz) { TP_FAIL("ret=%jd != %d [elferror=\"%s\"]", (intmax_t) offset, fsz, elf_errmsg(-1)); goto done; } (void) elf_end(e); e = NULL; (void) close(fd); fd = -1; result = elfts_compare_files("u1.$2$1", TS_NEWFILE); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); }') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') /* * An unsupported section type should be rejected. */ undefine(`FN') define(`FN',` void tcSectionType$2$1(void) { int error, fd, result; off_t offset; Elf *e; Elf_Scn *scn; Elf$1_Shdr *sh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: unsupported section types are rejected."); result = TET_UNRESOLVED; e = NULL; fd = -1; _TS_OPEN_FILE(e, "newehdr.$2$1", ELF_C_READ, fd, goto done;); if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf$1_newscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((sh = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } - sh->sh_type = SHT_NULL - 1; + sh->sh_type = SHT_LOOS - 1; (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_SECTION) { TP_FAIL("elf_update() did not fail with ELF_E_SECTION; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd) (void) close(fd); tet_result(result); }') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') +/* + * Verify that sections with unrecognized sh_type values in the + * range [SHT_LOUSER,SHT_HIUSER], [SHT_LOPROC,SHT_HIPROC], + * and [SHT_LOOS,SHT_HIOS] are accepted. + */ + +define(`ADD_SECTION',` + if ((scn = elf_newscn(e)) == NULL) { + TP_UNRESOLVED("elf_newscn() failed: \"%s\".", + elf_errmsg(-1)); + goto done; + } + if ((sh = elf$1_getshdr(scn)) == NULL) { + TP_UNRESOLVED("elf$1_getshdr() failed: \"%s\".", + elf_errmsg(-1)); + goto done; + } + sh->sh_type = $2; + if ((d = elf_newdata(scn)) == NULL) { + TP_UNRESOLVED("elf_newdata() failed: \"%s\".", + elf_errmsg(-1)); + goto done; + } + d->d_align = 1; + d->d_buf = NULL; + d->d_size = 0; + d->d_off = (off_t) 0; + (void) elf_flagdata(d, ELF_C_SET, ELF_F_DIRTY); + (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);') +undefine(`FN') +define(`FN',` +void +tcSectionTypeOSUserProcDefined_$2$1(void) +{ + int error, fd, result; + off_t offset; + Elf *e; + Elf_Data *d; + Elf_Scn *scn; + Elf$1_Shdr *sh; + + TP_CHECK_INITIALIZATION(); + + TP_ANNOUNCE("TOUPPER($2)$1: user, OS and processor specific " + "section types are accepted.") ; + + result = TET_UNRESOLVED; + e = NULL; + fd = -1; + + _TS_OPEN_FILE(e, "newehdr.$2$1", ELF_C_READ, fd, goto done;); + + /* + * Create two new sections, one of type SHT_LOOS (0x60000000UL), + * and the other of type SHT_HIUSER (0xFFFFFFFFUL). These + * should be accepted as valid sections. + */ + ADD_SECTION($1,`SHT_LOOS') + ADD_SECTION($1,`SHT_HIUSER') + + if ((offset = elf_update(e, ELF_C_NULL)) == (off_t) -1) { + TP_FAIL("elf_update() failed."); + goto done; + } + + result = TET_PASS; + + done: + if (e) + (void) elf_end(e); + if (fd) + (void) close(fd); + tet_result(result); +}') + +FN(32,`lsb') +FN(32,`msb') +FN(64,`lsb') +FN(64,`msb') + +undefine(`ADD_SECTION') + /* * An Elf_Data descriptor that is malformed in various ways * should be rejected. */ undefine(`FN') define(`FN',` void tc$3_$2$1(void) { int error, fd, result; off_t offset; Elf *e; Elf_Data *d; Elf_Scn *scn; Elf$1_Shdr *sh; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: data descriptors with " $6 " are rejected."); result = TET_UNRESOLVED; e = NULL; fd = -1; _TS_OPEN_FILE(e, "newehdr.$2$1", ELF_C_READ, fd, goto done;); if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf$1_newscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((sh = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } sh->sh_type = SHT_SYMTAB; (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY); if ((d = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Setup defaults for the test. */ d->d_buf = (char *) NULL; d->d_size = sizeof(Elf$1_Sym); d->d_type = ELF_T_SYM; d->d_align = 1; /* Override, on a per test case basis. */ $4 if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_$5) { TP_FAIL("elf_update() did not fail with ELF_E_$5; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd) (void) close(fd); tet_result(result); }') define(`MKFN',` FN(32,`lsb',$1,$2,$3,$4) FN(32,`msb',$1,$2,$3,$4) FN(64,`lsb',$1,$2,$3,$4) FN(64,`msb',$1,$2,$3,$4) ') MKFN(IllegalAlignment, `d->d_align = 3;', DATA, "incorrect alignments") MKFN(UnsupportedVersion, `d->d_version = EV_CURRENT+1;', VERSION, "an unknown version") MKFN(UnknownElfType, `d->d_type = ELF_T_NUM;', DATA, "an unknown type") MKFN(IllegalSize, `d->d_size = 1;', DATA, "an illegal size") /* * Ensure that updating the section header on an ELF object opened * in ELF_C_RDWR mode in an idempotent manner leaves the object * in a sane state. See ticket #269. */ undefine(`FN') define(`FN',` void tcRdWrShdrIdempotent$2$1(void) { Elf *e; off_t fsz; struct stat sb; size_t strtabidx; Elf_Scn *strtabscn; int error, fd, tfd, result; GElf_Shdr strtabshdr; char *srcfile = "newscn.$2$1", *tfn; char *reffile = "newscn2.$2$1"; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: (liblayout) a no-op update of section " "headers works as expected"); result = TET_UNRESOLVED; e = NULL; tfn = NULL; fd = tfd = -1; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, tfd, goto done;); if (stat(reffile, &sb) < 0) { TP_UNRESOLVED("stat() failed: \"%s\".", strerror(errno)); goto done; } /* Retrieve the index of the section name string table. */ if (elf_getshdrstrndx(e, &strtabidx) != 0) { TP_UNRESOLVED("elf_getshdrstrndx() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* * Retrieve the section descriptor for the section name string table. */ if ((strtabscn = elf_getscn(e, strtabidx)) == NULL) { TP_UNRESOLVED("elf_getscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Read the section header ... */ if (gelf_getshdr(strtabscn, &strtabshdr) == NULL) { TP_UNRESOLVED("gelf_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* ... and write it back. */ if (gelf_update_shdr(strtabscn, &strtabshdr) == 0) { TP_UNRESOLVED("gelf_update_shdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Update the underlying ELF object. */ if ((fsz = elf_update(e, ELF_C_WRITE)) < 0) { TP_UNRESOLVED("elf_update() failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() returned %d.", error); goto done; } e = NULL; /* Compare against the original. */ result = elfts_compare_files(reffile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfd != -1) (void) close(tfd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); }') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') /* * Ensure that updating the section header table on an ELF object opened * in ELF_C_RDWR mode in an idempotent manner leaves the object * in a sane state. See ticket #269. */ undefine(`FN') define(`FN',` void tcRdWrShdrIdempotentAppLayout$2$1(void) { Elf *e; off_t fsz; struct stat sb; size_t strtabidx; Elf_Scn *strtabscn; unsigned int flags; int error, fd, tfd, result; GElf_Shdr strtabshdr; char *srcfile = "newscn.$2$1", *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: (applayout) a no-op update of section " "headers works as expected"); result = TET_UNRESOLVED; e = NULL; tfn = NULL; fd = tfd = -1; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, tfd, goto done;); flags = elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); if ((flags & ELF_F_LAYOUT) == 0) { TP_UNRESOLVED("elf_flagelf() failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fstat(tfd, &sb) < 0) { TP_UNRESOLVED("fstat() failed: \"%s\".", strerror(errno)); goto done; } /* Retrieve the index of the section name string table. */ if (elf_getshdrstrndx(e, &strtabidx) != 0) { TP_UNRESOLVED("elf_getshdrstrndx() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* * Retrieve the section descriptor for the section name string table. */ if ((strtabscn = elf_getscn(e, strtabidx)) == NULL) { TP_UNRESOLVED("elf_getscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Read the section header ... */ if (gelf_getshdr(strtabscn, &strtabshdr) == NULL) { TP_UNRESOLVED("gelf_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* ... and write it back. */ if (gelf_update_shdr(strtabscn, &strtabshdr) == 0) { TP_UNRESOLVED("gelf_update_shdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Update the underlying ELF object. */ if ((fsz = elf_update(e, ELF_C_WRITE)) < 0) { TP_UNRESOLVED("elf_update() failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() returned %d.", error); goto done; } e = NULL; /* Compare against the original. */ result = elfts_compare_files(srcfile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfd != -1) (void) close(tfd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); }') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') /* * Test handling of sections with buffers of differing Elf_Data types. */ /* * The contents of the first Elf_Data buffer for section ".foo" * (ELF_T_WORD, align 4). */ uint32_t hash_words[] = { 0x01234567, 0x89abcdef, 0xdeadc0de }; /* * The contents of the second Elf_Data buffer for section ".foo" * (ELF_T_BYTE, align 1) */ char data_string[] = "helloworld"; /* * The contents of the third Elf_Data buffer for section ".foo" * (ELF_T_WORD, align 4) */ uint32_t checksum[] = { 0xffffeeee }; /* * The contents of the ".shstrtab" section. */ char string_table[] = { /* Offset 0 */ '\0', /* Offset 1 */ '.', 'f' ,'o', 'o', '\0', /* Offset 6 */ '.', 's' , 'h' , 's' , 't', 'r', 't', 'a', 'b', '\0' }; undefine(`FN') define(`FN',` void tcMixedBuffer_$2$1(void) { Elf *e; Elf_Scn *scn, *strscn; int error, fd, result; Elf$1_Ehdr *ehdr; Elf$1_Shdr *shdr, *strshdr; Elf_Data *data1, *data2, *data3, *data4; char *reffile = "mixedscn.$2$1", *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: sections with mixed data work " "as expected"); result = TET_UNRESOLVED; e = NULL; tfn = NULL; fd = -1; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); if ((ehdr = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } ehdr->e_ident[EI_DATA] = `ELFDATA2'TOUPPER($2); ehdr->e_machine = MAKE_EM($1,$2); ehdr->e_type = ET_REL; if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((data1 = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata(data1) failed: \"%s\".", elf_errmsg(-1)); goto done; } data1->d_align = 4; data1->d_off = 0; data1->d_buf = hash_words; data1->d_type = ELF_T_WORD; data1->d_size = sizeof(hash_words); data1->d_version = EV_CURRENT; if ((data2 = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata(data2) failed: \"%s\".", elf_errmsg(-1)); goto done; } data2->d_align = 1; data2->d_off = 0; data2->d_buf = data_string; data2->d_type = ELF_T_BYTE; data2->d_size = sizeof(data_string); data2->d_version = EV_CURRENT; if ((data3 = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata(data3) failed: \"%s\".", elf_errmsg(-1)); goto done; } data3->d_align = 4; data3->d_off = 0; data3->d_buf = checksum; data3->d_type = ELF_T_WORD; data3->d_size = sizeof(checksum); data3->d_version = EV_CURRENT; if ((shdr = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } shdr->sh_name = 1; /* offset of ".foo" */ shdr->sh_type = SHT_PROGBITS; shdr->sh_flags = SHF_ALLOC; shdr->sh_entsize = 0; shdr->sh_addralign = 4; /* * Create the .shstrtab section. */ if ((strscn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((data4 = elf_newdata(strscn)) == NULL) { TP_UNRESOLVED("elf_newdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } data4->d_align = 1; data4->d_off = 0; data4->d_buf = string_table; data4->d_type = ELF_T_BYTE; data4->d_size = sizeof(string_table); data4->d_version = EV_CURRENT; if ((strshdr = elf$1_getshdr(strscn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } strshdr->sh_name = 6; /* \0 + strlen(".foo") + \0 */ strshdr->sh_type = SHT_STRTAB; strshdr->sh_flags = SHF_STRINGS | SHF_ALLOC; strshdr->sh_entsize = 0; ehdr->e_shstrndx = elf_ndxscn(strscn); if (elf_update(e, ELF_C_WRITE) < 0) { TP_FAIL("elf_update() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Compare files here. */ TP_UNRESOLVED("Verification is yet to be implemented."); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); }') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') /* * Test that a call to elf_update() without any changes flagged * leaves the ELF object unchanged. */ undefine(`FN') define(`FN',` void tcRdWrModeNoOp_$1$2(void) { struct stat sb; int error, fd, result; Elf *e; Elf$1_Ehdr *eh; const char *srcfile = "rdwr.$2$1"; off_t fsz1, fsz2; char *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: elf_update() without flagged changes " "is a no-op"); result = TET_UNRESOLVED; e = NULL; fd = -1; tfn = NULL; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, fd, goto done;); if (fstat(fd, &sb) < 0) { TP_UNRESOLVED("fstat() failed: \"%s\".", strerror(errno)); goto done; } if ((eh = elf$1_getehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_getehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz1 = elf_update(e, ELF_C_NULL)) < 0) { TP_FAIL("elf_update(NULL) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz1); goto done; } if ((fsz2 = elf_update(e, ELF_C_WRITE)) < 0) { TP_FAIL("elf_update(WRITE) failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != fsz2) { TP_FAIL("fsz1 (%d) != fsz2 (%d)", fsz1, fsz2); goto done; } e = NULL; (void) close(fd); /* compare against the original */ result = elfts_compare_files(srcfile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); }') FN(32,lsb) FN(32,msb) FN(64,lsb) FN(64,msb) /* * Test that a call to elf_update() without a change to underlying * data for the object is a no-op. */ undefine(`FN') define(`FN',` void tcRdWrModeNoDataChange_$1$2(void) { int error, fd, result; Elf *e; Elf_Scn *scn; const char *srcfile = "rdwr.$2$1"; off_t fsz1, fsz2; struct stat sb; char *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: elf_update() with no data changes " "is a no-op"); result = TET_UNRESOLVED; e = NULL; fd = -1; tfn = NULL; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, fd, goto done;); if (fstat(fd, &sb) < 0) { TP_UNRESOLVED("fstat() failed: \"%s\".", strerror(errno)); goto done; } if ((scn = elf_getscn(e, 1)) == NULL) { TP_UNRESOLVED("elf_getscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if (elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY) != ELF_F_DIRTY) { TP_UNRESOLVED("elf_flagscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz1 = elf_update(e, ELF_C_NULL)) < 0) { TP_FAIL("elf_update(NULL) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz1); goto done; } if ((fsz2 = elf_update(e, ELF_C_WRITE)) < 0) { TP_FAIL("elf_update(WRITE) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != fsz2) { TP_FAIL("fsz1 (%d) != fsz2 (%d)", fsz1, fsz2); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() failed: \"%s\".", elf_errmsg(-1)); goto done; } e = NULL; (void) close(fd); /* compare against the original */ result = elfts_compare_files(srcfile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); }') FN(32,lsb) FN(32,msb) FN(64,lsb) FN(64,msb) /* * Test that a call to elf_update() with a changed ehdr causes the * underlying file to change. */ undefine(`FN') define(`FN',` void tcRdWrModeEhdrChange_$1$2(void) { int error, fd, result; unsigned int flag; struct stat sb; Elf *e; Elf$1_Ehdr *eh; const char *srcfile = "rdwr.$2$1"; const char *reffile = "rdwr1.$2$1"; off_t fsz1, fsz2; char *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: elf_update() updates a changed " "header correctly"); result = TET_UNRESOLVED; e = NULL; fd = -1; tfn = NULL; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, fd, goto done;); if (fstat(fd, &sb) < 0) { TP_UNRESOLVED("fstat() failed: \"%s\".", strerror(errno)); goto done; } if ((eh = elf$1_getehdr(e)) == NULL) { TP_UNRESOLVED("elf_getscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Change the ELFCLASS of the object. */ eh->e_type = ET_DYN; flag = elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); if ((flag & ELF_F_DIRTY) == 0) { TP_UNRESOLVED("elf_flagehdr failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz1 = elf_update(e, ELF_C_NULL)) < 0) { TP_FAIL("elf_update(NULL) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz1); goto done; } if ((fsz2 = elf_update(e, ELF_C_WRITE)) < 0) { TP_FAIL("elf_update(WRITE) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != fsz2) { TP_FAIL("fsz1 (%d) != fsz2 (%d)", fsz1, fsz2); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() failed: \"%s\".", elf_errmsg(-1)); goto done; } e = NULL; (void) close(fd); /* compare against the reference */ result = elfts_compare_files(reffile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); } ') FN(32,lsb) FN(32,msb) FN(64,lsb) FN(64,msb) /* * Test extending a section. */ static char *base_data = "hello world"; static char *extra_data = "goodbye world"; undefine(`FN') define(`FN',` void tcRdWrExtendSection_$1$2(void) { int error, fd, result; unsigned int flag; struct stat sb; Elf *e; Elf_Scn *scn; Elf_Data *d; const char *srcfile = "rdwr.$2$1"; const char *reffile = "rdwr2.$2$1"; off_t fsz1, fsz2; char *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: elf_update() deals with an " "extended section correctly"); result = TET_UNRESOLVED; e = NULL; fd = -1; tfn = NULL; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, fd, goto done;); if (stat(reffile, &sb) < 0) { TP_UNRESOLVED("stat() failed: \"%s\".", strerror(errno)); goto done; } /* Retrieve section 1 and extend it. */ if ((scn = elf_getscn(e, 1)) == NULL) { TP_UNRESOLVED("elf_getscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((d = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } d->d_buf = extra_data; d->d_size = strlen(extra_data); if (elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY) != ELF_F_DIRTY) { TP_UNRESOLVED("elf_flagscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz1 = elf_update(e, ELF_C_NULL)) < 0) { TP_FAIL("elf_update(NULL) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz1); goto done; } if ((fsz2 = elf_update(e, ELF_C_WRITE)) < 0) { TP_FAIL("elf_update(WRITE) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != fsz2) { TP_FAIL("fsz1 (%d) != fsz2 (%d)", fsz1, fsz2); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() failed: \"%s\".", elf_errmsg(-1)); goto done; } e = NULL; (void) close(fd); /* compare against the reference */ result = elfts_compare_files(reffile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); } ') FN(32,lsb) FN(32,msb) FN(64,lsb) FN(64,msb) /* * Test shrinking a section. */ undefine(`FN') define(`FN',` void tcRdWrShrinkSection_$1$2(void) { int error, fd, result; unsigned int flag; struct stat sb; Elf *e; Elf_Scn *scn; Elf_Data *d; const char *srcfile = "rdwr2.$2$1"; const char *reffile = "rdwr.$2$1"; off_t fsz1, fsz2; char *tfn; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: elf_update() deals with an " "shrunk section correctly"); result = TET_UNRESOLVED; e = NULL; fd = -1; tfn = NULL; /* Make a copy of the reference object. */ if ((tfn = elfts_copy_file(srcfile, &error)) < 0) { TP_UNRESOLVED("elfts_copyfile(%s) failed: \"%s\".", srcfile, strerror(error)); goto done; } /* Open the copied object in RDWR mode. */ _TS_OPEN_FILE(e, tfn, ELF_C_RDWR, fd, goto done;); if (stat(reffile, &sb) < 0) { TP_UNRESOLVED("stat() failed: \"%s\".", strerror(errno)); goto done; } /* Retrieve section 1 and shrink it. */ if ((scn = elf_getscn(e, 1)) == NULL) { TP_UNRESOLVED("elf_getscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((d = elf_getdata(scn, NULL)) == NULL) { TP_UNRESOLVED("elf_getdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } d->d_size = strlen(base_data); if (elf_flagdata(d, ELF_C_SET, ELF_F_DIRTY) != ELF_F_DIRTY) { TP_UNRESOLVED("elf_flagdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } if (elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY) != ELF_F_DIRTY) { TP_UNRESOLVED("elf_flagscn() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz1 = elf_update(e, ELF_C_NULL)) < 0) { TP_FAIL("elf_update(NULL) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != sb.st_size) { TP_FAIL("Size error: expected=%d, elf_update()=%d", sb.st_size, fsz1); goto done; } if ((fsz2 = elf_update(e, ELF_C_WRITE)) < 0) { TP_FAIL("elf_update(WRITE) failed: \"%s\".", elf_errmsg(-1)); goto done; } if (fsz1 != fsz2) { TP_FAIL("fsz1 (%d) != fsz2 (%d)", fsz1, fsz2); goto done; } /* Close the temporary file. */ if ((error = elf_end(e)) != 0) { TP_UNRESOLVED("elf_end() failed: \"%s\".", elf_errmsg(-1)); goto done; } e = NULL; (void) close(fd); /* compare against the reference */ result = elfts_compare_files(reffile, tfn); done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); if (tfn != NULL) (void) unlink(tfn); tet_result(result); } ') FN(32,lsb) FN(32,msb) FN(64,lsb) FN(64,msb) /* * Test cases rejecting malformed ELF files created with the * ELF_F_LAYOUT flag set. */ undefine(`FN') define(`FN',` void tcEhdrPhdrCollision$1$2(void) { int error, fd, result, flags; off_t offset; size_t fsz, psz, roundup, ssz; Elf$1_Ehdr *eh; Elf$1_Phdr *ph; Elf_Data *d; Elf_Scn *scn; Elf *e; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: an overlap of the ehdr and phdr is " "detected."); result = TET_UNRESOLVED; fd = -1; e = NULL; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); flags = elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); if ((flags & ELF_F_LAYOUT) == 0) { TP_UNRESOLVED("elf_flagelf() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Fill in sane values for the Ehdr. */ eh->e_type = ET_REL; eh->e_shoff = 0; eh->e_ident[EI_CLASS] = ELFCLASS`'$1; eh->e_ident[EI_DATA] = ELFDATA2`'TOUPPER($2); if ((ph = elf$1_newphdr(e, 1)) == NULL) { TP_UNRESOLVED("elf$1_newphdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0) { TP_UNRESOLVED("fsize() failed: %s.", elf_errmsg(-1)); goto done; } /* Make the phdr table overlap with the ehdr. */ eh->e_phoff = fsz - 1; /* Check the return values from elf_update(). */ if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_LAYOUT) { TP_FAIL("elf_update() did not fail with ELF_E_LAYOUT, " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); } ') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') undefine(`FN') define(`FN',` void tcShdrPhdrCollision$1$2(void) { int error, fd, result, flags; off_t offset; size_t fsz, psz, roundup, ssz; Elf$1_Ehdr *eh; Elf$1_Phdr *ph; Elf_Data *d; Elf_Scn *scn; Elf *e; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: an overlap of the shdr and phdr is " "detected."); result = TET_UNRESOLVED; fd = -1; e = NULL; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); flags = elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); if ((flags & ELF_F_LAYOUT) == 0) { TP_UNRESOLVED("elf_flagelf() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Fill in sane values for the Ehdr. */ eh->e_type = ET_REL; eh->e_ident[EI_CLASS] = ELFCLASS`'$1; eh->e_ident[EI_DATA] = ELFDATA2`'TOUPPER($2); if ((ph = elf$1_newphdr(e, 1)) == NULL) { TP_UNRESOLVED("elf$1_newphdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((fsz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0) { TP_UNRESOLVED("fsize() failed: %s.", elf_errmsg(-1)); goto done; } if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: %s.", elf_errmsg(-1)); goto done; } /* Make the PHDR and SHDR tables overlap. */ eh->e_phoff = fsz; eh->e_shoff = fsz; if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_LAYOUT) { TP_FAIL("elf_update() did not fail with ELF_E_LAYOUT; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); } ') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') /* * Verify that an overlap between a section's data and the SHDR * table is detected. */ undefine(`FN') define(`FN',` void tcShdrSectionCollision$1$2(void) { int error, fd, result, flags; off_t offset; size_t fsz, psz, roundup, ssz; Elf$1_Ehdr *eh; Elf$1_Shdr *sh; Elf_Data *d; Elf_Scn *scn; Elf *e; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: an overlap of the shdr and a section is " "detected."); result = TET_UNRESOLVED; fd = -1; e = NULL; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); flags = elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); if ((flags & ELF_F_LAYOUT) == 0) { TP_UNRESOLVED("elf_flagelf() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Fill in sane values for the Ehdr. */ eh->e_type = ET_REL; eh->e_ident[EI_CLASS] = ELFCLASS`'$1; eh->e_ident[EI_DATA] = ELFDATA2`'TOUPPER($2); if ((fsz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0) { TP_UNRESOLVED("fsize() failed: %s.", elf_errmsg(-1)); goto done; } if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: %s.", elf_errmsg(-1)); goto done; } eh->e_shoff = fsz; if ((sh = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: %s.", elf_errmsg(-1)); goto done; } /* Fill in application-specified fields. */ sh->sh_type = SHT_PROGBITS; sh->sh_addralign = 1; sh->sh_size = 1; sh->sh_entsize = 1; /* Make this section overlap with the section header. */ sh->sh_offset = fsz; if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_LAYOUT) { TP_FAIL("elf_update() did not fail with ELF_E_LAYOUT; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); } ') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') /* * Check that overlapping sections are rejected when ELF_F_LAYOUT is set. */ undefine(`FN') define(`FN',` void tcSectionOverlap$1$2(void) { int error, fd, result, flags; off_t offset; size_t fsz, psz, roundup, ssz; Elf$1_Ehdr *eh; Elf$1_Shdr *sh; Elf_Data *d; Elf_Scn *scn; Elf *e; TP_CHECK_INITIALIZATION(); TP_ANNOUNCE("TOUPPER($2)$1: an overlap between two sections is " "detected."); result = TET_UNRESOLVED; fd = -1; e = NULL; _TS_OPEN_FILE(e, TS_NEWFILE, ELF_C_WRITE, fd, goto done;); flags = elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); if ((flags & ELF_F_LAYOUT) == 0) { TP_UNRESOLVED("elf_flagelf() failed: \"%s\".", elf_errmsg(-1)); goto done; } if ((eh = elf$1_newehdr(e)) == NULL) { TP_UNRESOLVED("elf$1_newehdr() failed: \"%s\".", elf_errmsg(-1)); goto done; } /* Fill in sane values for the Ehdr. */ eh->e_type = ET_REL; eh->e_ident[EI_CLASS] = ELFCLASS`'$1; eh->e_ident[EI_DATA] = ELFDATA2`'TOUPPER($2); eh->e_shoff = TS_OFFSET_SHDR; if ((fsz = elf$1_fsize(ELF_T_EHDR, 1, EV_CURRENT)) == 0) { TP_UNRESOLVED("fsize() failed: %s.", elf_errmsg(-1)); goto done; } /* * Build the first section. */ if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: %s.", elf_errmsg(-1)); goto done; } if ((sh = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: %s.", elf_errmsg(-1)); goto done; } if ((d = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } d->d_type = ELF_T_BYTE; d->d_off = 0; d->d_buf = base_data; d->d_size = strlen(base_data); /* Fill in application-specified fields. */ sh->sh_type = SHT_PROGBITS; sh->sh_addralign = 1; sh->sh_size = 1; sh->sh_entsize = 1; sh->sh_offset = fsz; /* * Build the second section. */ if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("elf_newscn() failed: %s.", elf_errmsg(-1)); goto done; } if ((sh = elf$1_getshdr(scn)) == NULL) { TP_UNRESOLVED("elf$1_getshdr() failed: %s.", elf_errmsg(-1)); goto done; } if ((d = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("elf_newdata() failed: \"%s\".", elf_errmsg(-1)); goto done; } d->d_buf = base_data; d->d_size = strlen(base_data); /* Fill in application-specified fields. */ sh->sh_type = SHT_PROGBITS; sh->sh_addralign = 1; sh->sh_size = 1; sh->sh_entsize = 1; sh->sh_offset = fsz + 1; /* Overlap with the first section. */ if ((offset = elf_update(e, ELF_C_NULL)) != (off_t) -1) { TP_FAIL("elf_update() succeeded unexpectedly; offset=%jd.", (intmax_t) offset); goto done; } if ((error = elf_errno()) != ELF_E_LAYOUT) { TP_FAIL("elf_update() did not fail with ELF_E_LAYOUT; " "error=%d \"%s\".", error, elf_errmsg(error)); goto done; } result = TET_PASS; done: if (e) (void) elf_end(e); if (fd != -1) (void) close(fd); (void) unlink(TS_NEWFILE); tet_result(result); } ') FN(32,`lsb') FN(32,`msb') FN(64,`lsb') FN(64,`msb') diff --git a/test/libelftc/Makefile b/test/libelftc/Makefile index c9f086cc7b8d..f7a3903e2b9e 100644 --- a/test/libelftc/Makefile +++ b/test/libelftc/Makefile @@ -1,36 +1,6 @@ -# $Id: Makefile 2826 2012-12-29 16:39:18Z jkoshy $ - -TOP = ../.. - -.include "${TOP}/mk/elftoolchain.tetvars.mk" - -.if !defined(TET_EXECUTE) -TET_EXECUTE= ${.OBJDIR} -.endif - -.if make(tccbuild) -TET_OPTIONS+= -b -.endif - -.if make(tccclean) -TET_OPTIONS+= -c -.endif - -.if make(execute) || make(test) -TET_OPTIONS+= -e -.endif - -.MAIN: all - -.PHONY: clobber execute tccbuild tccclean test - -execute tccbuild tccclean test: - TET_ROOT=${TET_ROOT} TET_EXECUTE=${TET_EXECUTE} \ - TET_SUITE_ROOT=${.CURDIR} ${TET_ROOT}/bin/tcc ${TET_OPTIONS} . - -clobber: clean - rm -rf ${TET_RESULTS_DIR} ${TET_TMP_DIR} +# $Id: Makefile 3028 2014-04-18 16:20:43Z jkoshy $ +TOP= ../.. SUBDIR= tset -.include +.include "${TOP}/mk/elftoolchain.tetbase.mk" diff --git a/test/libelftc/tset/Makefile b/test/libelftc/tset/Makefile index f0ba944fee21..6602c88c37ca 100644 --- a/test/libelftc/tset/Makefile +++ b/test/libelftc/tset/Makefile @@ -1,7 +1,8 @@ -# $Id: Makefile 2861 2013-01-05 09:35:42Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ +TOP= ../../.. SUBDIR= SUBDIR+= elftc_string_table SUBDIR+= elftc_version -.include +.include "${TOP}/mk/elftoolchain.subdir.mk" diff --git a/test/libelftc/tset/Makefile.tset b/test/libelftc/tset/Makefile.tset index b28e6f717b48..dc637a90263a 100644 --- a/test/libelftc/tset/Makefile.tset +++ b/test/libelftc/tset/Makefile.tset @@ -1,10 +1,11 @@ -# $Id: Makefile.tset 2845 2012-12-31 04:19:35Z jkoshy $ +# $Id: Makefile.tset 3021 2014-04-17 16:32:00Z jkoshy $ -# All the test cases in this test suite need -lelftc. -DPADD+= ${LIBELFTC} -LDADD+= -lelftc +# All the test cases in this test suite need -lelftc. In addition, +# a few need -lelf. +DPADD+= ${LIBELFTC} ${LIBELF} +LDADD+= -lelftc -lelf GENERATE_TEST_SCAFFOLDING= yes # Test cases do not supply manual pages. NOMAN= noman diff --git a/test/libelftc/tset/elftc_string_table/string_table.m4 b/test/libelftc/tset/elftc_string_table/string_table.m4 index 0c6f730686db..74e66c99c12b 100644 --- a/test/libelftc/tset/elftc_string_table/string_table.m4 +++ b/test/libelftc/tset/elftc_string_table/string_table.m4 @@ -1,983 +1,985 @@ /*- * Copyright (c) 2013 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: string_table.m4 2868 2013-01-06 13:28:47Z jkoshy $ + * $Id: string_table.m4 3021 2014-04-17 16:32:00Z jkoshy $ */ /* * include(`elfts.m4') */ #include #include #include +#include #include #include #include #include +#include #include "tet_api.h" /* * A list of test strings. * * For the curious, these are titles of stories by Cordwainer Smith. */ static const char *test_strings[] = { "Mark Elf", "Scanners Live in Vain", "The Dead Lady of Clown Town", "The Lady Who Sailed the \"The Soul\"", "No, No, Not Rogov!", NULL }; static const int nteststrings = sizeof(test_strings) / sizeof(test_strings[0]); static char test_image[] = { 0, 'M', 'a', 'r', 'k', ' ', 'E', 'l', 'f', 0, 'S', 'c', 'a', 'n', 'n', 'e', 'r', 's', ' ', 'L', 'i', 'v', 'e', ' ', 'i', 'n', ' ', 'V', 'a', 'i', 'n', 0, 'T', 'h', 'e', ' ', 'D', 'e', 'a', 'd', ' ', 'L', 'a', 'd', 'y', ' ', 'o', 'f', ' ', 'C', 'l', 'o', 'w', 'n', ' ', 'T', 'o', 'w', 'n', 0, 'T', 'h', 'e', ' ', 'L', 'a', 'd', 'y', ' ', 'W', 'h', 'o', ' ', 'S', 'a', 'i', 'l', 'e', 'd', ' ', 't', 'h', 'e', ' ', '"', 'T', 'h', 'e', 'S', 'o', 'u', 'l', '"', 0, 'N', 'o', ',', ' ', 'N', 'o', ',', ' ', 'N', 'o', 't', ' ', 'R', 'o', 'g', 'o', 'v', '!', 0 }; #define UNKNOWN_STRING "Don't Panic!" /* * Verify that strings are inserted at the expected offsets, and that * the returned value is equivalent to the original string. */ void tcInsertReturnValues(void) { int result; const char **s; unsigned int expectedindex, hashindex; Elftc_String_Table *table; result = TET_UNRESOLVED; TP_ANNOUNCE("Insertion returns the expected offsets."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } expectedindex = 1; /* Insert test strings. */ for (s = test_strings; *s != NULL; s++) { hashindex = elftc_string_table_insert(table, *s); if (hashindex != expectedindex) { TP_FAIL("incorrect hash index: expected %d, actual %d", expectedindex, hashindex); goto done; } expectedindex += strlen(*s) + 1; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } /* * Verify that multiple insertions of the same string yield the same * return values and offsets. */ void tcInsertDuplicate(void) { const char **s; int n, result; Elftc_String_Table *table; unsigned int hindex, *hashrecord; result = TET_UNRESOLVED; TP_ANNOUNCE("Multiple insertions return the same offset value."); hashrecord = NULL; if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } if ((hashrecord = malloc(nteststrings*sizeof(*hashrecord))) == NULL) { TP_UNRESOLVED("memory allocation failed."); goto done; } /* Insert test strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) hashrecord[n] = elftc_string_table_insert(table, *s); /* Re-insert, and verify the returned pointers and offsets. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) { hindex = elftc_string_table_insert(table, *s); if (hindex != hashrecord[n]) { TP_FAIL("incorrect hash index: expected %d, actual %d", hashrecord[n], hindex); goto done; } } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); free(hashrecord); tet_result(result); } /* * Verify that the lookup() API returns the expected * values. */ void tcLookupReturn(void) { int result; const char **s, *str; unsigned int expectedindex, hashindex; Elftc_String_Table *table; result = TET_UNRESOLVED; TP_ANNOUNCE("A lookup after an insertion returns the correct " "string."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } /* Insert test strings. */ for (s = test_strings; *s != NULL; s++) (void) elftc_string_table_insert(table, *s); expectedindex = 1; for (s = test_strings; *s != NULL; s++) { hashindex = elftc_string_table_lookup(table, *s); if (hashindex != expectedindex) { TP_FAIL("incorrect hash index: expected %d, actual %d", expectedindex, hashindex); goto done; } str = elftc_string_table_to_string(table, hashindex); if (str == NULL || strcmp(str, *s)) { TP_FAIL("Lookup of \"%s\" returned \"%s\".", *s, str); goto done; } expectedindex += strlen(*s) + 1; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } /* * Verify that multiple lookups return the same pointer * and string offset. */ void tcLookupDuplicate(void) { int n, result; const char **s, *str1, *str2; unsigned int hindex1, hindex2, *hashrecord; Elftc_String_Table *table; result = TET_UNRESOLVED; TP_ANNOUNCE("Multiple invocations of lookup on a valid string " "return the same value."); hashrecord = NULL; if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } if ((hashrecord = malloc(nteststrings*sizeof(*hashrecord))) == NULL) { TP_UNRESOLVED("memory allocation failed."); goto done; } /* Insert test strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) hashrecord[n] = elftc_string_table_insert(table, *s); for (n = 0, s = test_strings; *s != NULL; s++, n++) { hindex1 = elftc_string_table_lookup(table, *s); hindex2 = elftc_string_table_lookup(table, *s); if (hindex1 != hindex2 || hindex1 != hashrecord[n]) { TP_FAIL("incorrect hash index: expected %d, " "actual %d & %d", hashrecord[n], hindex1, hindex2); goto done; } str1 = elftc_string_table_to_string(table, hindex1); str2 = elftc_string_table_to_string(table, hindex2); if (str1 == NULL || str2 == NULL || str1 != str2 || strcmp(str1, *s)) { TP_FAIL("Lookup of \"%s\" returned \"%s\" & \"%s\".", *s, str1, str2); goto done; } } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); free(hashrecord); tet_result(result); } /* * Verify that a deleted string cannot be subsequently looked up. */ void tcDeletionCheck(void) { const char **s; Elftc_String_Table *table; int hindex, n, result, status; result = TET_UNRESOLVED; TP_ANNOUNCE("Lookup after deletion should fail."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } /* Insert test strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) (void) elftc_string_table_insert(table, *s); /* Delete strings, and look them up. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) { status = elftc_string_table_remove(table, *s); if (status == 0) { TP_FAIL("Deletion of \"%s\" failed.", *s); goto done; } hindex = elftc_string_table_lookup(table, *s); if (hindex != 0) { TP_FAIL("Lookup of \"%s\" succeeded unexpectedly."); goto done; } } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } /* * Verify that a deleted string is re-inserted at the old index. */ void tcDeletionInsertion(void) { const char **s; unsigned int *hashrecord, hindex; Elftc_String_Table *table; int n, result, status; result = TET_UNRESOLVED; TP_ANNOUNCE("Re-insertion of a string after deletion should " "return the prior offset."); hashrecord = NULL; if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } if ((hashrecord = malloc(nteststrings*sizeof(*hashrecord))) == NULL) { TP_UNRESOLVED("memory allocation failed."); goto done; } /* Insert test strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) hashrecord[n] = elftc_string_table_insert(table, *s); /* Delete strings ... */ for (n = 0, s = test_strings; *s != NULL; s++, n++) { status = elftc_string_table_remove(table, *s); if (status == 0) { TP_UNRESOLVED("Deletion of \"%s\" failed.", *s); goto done; } } /* and re-insert them, and check. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) { hindex = elftc_string_table_insert(table, *s); if (hindex != hashrecord[n]) { TP_FAIL("Re-insertion at a different offset: " "old %d, new %p", hashrecord[n], hindex); goto done; } } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); if (hashrecord) free(hashrecord); tet_result(result); } /* * Verify that the 2nd deletion of the string fails. */ void tcDoubleDeletion(void) { const char **s; int n, result, status; Elftc_String_Table *table; result = TET_UNRESOLVED; TP_ANNOUNCE("Double deletion of a string should fail."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } /* Insert test strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) (void) elftc_string_table_insert(table, *s); /* Delete strings twice. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) { status = elftc_string_table_remove(table, *s); if (status == 0) { TP_FAIL("First deletion of \"%s\" failed.", *s); goto done; } status = elftc_string_table_remove(table, *s); if (status != 0) { TP_FAIL("Second deletion of \"%s\" succeeded.", *s); goto done; } } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } /* * Verify that deletion of an unknown string fails. */ void tcUnknownDeletion(void) { const char **s; int n, result, status; Elftc_String_Table *table; result = TET_UNRESOLVED; TP_ANNOUNCE("Deletion of an unknown string should fail."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } /* Insert test strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) (void) elftc_string_table_insert(table, *s); status = elftc_string_table_remove(table, UNKNOWN_STRING); if (status != 0) { TP_FAIL("Deletion of an unknown string succeeded."); goto done; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } /* * Ensure that string indices remain constant after the underlying * string pool is resized/moved. */ #define TC_STRING_SIZE 64 #define TC_INSERT_SIZE 20 void tcIndicesAfterRebase(void) { int j, n, result; const char *str1, *str2; char buf[TC_STRING_SIZE]; Elftc_String_Table *table; unsigned int offset1, offset2, expectedoffset; n = 0; result = TET_UNRESOLVED; TP_ANNOUNCE("Indices are consistent after a pool resize."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } /* Insert test strings. */ #define TC_BUILD_STRING(buf, n) do { \ (void) snprintf(buf, sizeof(buf), "%-*.*d", \ TC_INSERT_SIZE - 1, TC_INSERT_SIZE - 1, n); \ } while (0) TC_BUILD_STRING(buf, n); offset1 = elftc_string_table_insert(table, buf); str1 = elftc_string_table_to_string(table, offset1); if (offset1 == 0 || str1 == NULL) { TP_UNRESOLVED("Initialization failed."); goto done; } n++; /* * Insert unique strings till we detect a move of the initial * string. */ do { TC_BUILD_STRING(buf, n); if ((offset2 = elftc_string_table_insert(table, buf)) == 0) { TP_UNRESOLVED("String insertion failed at %d", n); goto done; } if ((str2 = elftc_string_table_to_string(table, offset1)) == NULL) { TP_UNRESOLVED("String looked failed at %d", n); goto done; } n++; } while (str2 == str1); /* * Verify the offset for each string inserted so far. */ expectedoffset = 1; for (j = 0; j < n; j++) { TC_BUILD_STRING(buf, j); offset1 = elftc_string_table_lookup(table, buf); if (offset1 != expectedoffset) { TP_FAIL("Offset mismatch: string #%d, " "expected %d, actual %d", j, expectedoffset, offset1); goto done; } expectedoffset += TC_INSERT_SIZE; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } void tcEmptyImage(void) { int result; size_t tblsz; const char *image; Elftc_String_Table *table; TP_ANNOUNCE("Check the image for an empty table."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } tblsz = 0; image = elftc_string_table_image(table, &tblsz); if (image == NULL) { TP_FAIL("Null image returned."); goto done; } if (*image != 0 || tblsz != 1) { TP_FAIL("Incorrect image parameters: [0]=%d, sz=%d", *image, tblsz); goto done; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } void tcImageDeleted(void) { const char **s; int n, result; size_t tblsz; const char *image; Elftc_String_Table *table; TP_ANNOUNCE("Check the image for an empty table."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } /* Insert, then delete a set of strings. */ for (n = 0, s = test_strings; *s != NULL; s++, n++) if (elftc_string_table_insert(table, *s) == 0) { TP_UNRESOLVED("String insertion of \"%s\" failed.", *s); goto done; } for (n = 0, s = test_strings; *s != NULL; s++, n++) if (elftc_string_table_remove(table, *s) == 0) { TP_UNRESOLVED("String deletion of \"%s\" failed.", *s); goto done; } /* Check for an empty table. */ tblsz = 0; image = elftc_string_table_image(table, &tblsz); if (image == NULL) { TP_FAIL("Null image returned."); goto done; } if (*image != 0 || tblsz != 1) { TP_FAIL("Incorrect image parameters: [0]=%d, sz=%d", *image, tblsz); goto done; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } static int validate_string_table(int nstrings, const char *image, size_t imagesz, const char **strings) { int n, result, *seen; const char *s, *end; if (*image != '\0') return (0); if (nstrings == 0) return (1); if ((seen = calloc(nstrings, sizeof(int))) == NULL) return (0); /* * Each string in the image should be in strings[], * and vice-versa. */ s = image + 1; end = image + imagesz; while (s < end) { /* Look for this string in the strings[] array. */ for (n = 0; n < nstrings; n++) if (strcmp(s, strings[n]) == 0) { seen[n] = 1; break; } if (n == nstrings) /* Not in the strings[] array. */ goto fail; s += strlen(s) + 1; } /* Verify all strings in the array were seen. */ for (n = 0; n < nstrings; n++) if (seen[n] == 0) goto fail; free(seen); return (1); fail: free(seen); return (0); } void tcImageInsertOnly(void) { int result; const char **s; const char *image; Elftc_String_Table *table; size_t expectedsize, imagesz; TP_ANNOUNCE("Insertion returns the expected image."); if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } result = TET_PASS; expectedsize = 1; for (s = test_strings; *s != NULL; s++) { expectedsize += strlen(*s) + 1; if(elftc_string_table_insert(table, *s) == 0) { TP_UNRESOLVED("String insertion failed for \"%s\".", *s); goto done; } } imagesz = 0; image = elftc_string_table_image(table, &imagesz); if (image == NULL || imagesz != expectedsize) { TP_FAIL("Incorrect image parameters: [0]=%d, sz=%d != %d", *image, imagesz, expectedsize); goto done; } if (!validate_string_table(nteststrings - 1, image, imagesz, test_strings)) { TP_FAIL("Image mismatch."); goto done; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); tet_result(result); } void tcImagePartiallyDeleted(void) { int n, nstr, result; Elftc_String_Table *table; size_t expectedsize, imagesz; const char *image, **s, **savedstr; TP_ANNOUNCE("Insertion+deletion returns the expected image."); savedstr = NULL; if ((table = elftc_string_table_create(0)) == NULL) { TP_UNRESOLVED("elftc_string_table_create() failed: %s", strerror(errno)); goto done; } expectedsize = 1; for (nstr = 0, s = test_strings; *s != NULL; s++, nstr++) { expectedsize += strlen(*s) + 1; if(elftc_string_table_insert(table, *s) == 0) { TP_UNRESOLVED("String insertion failed for \"%s\".", *s); goto done; } } if ((savedstr = malloc(sizeof(*savedstr) * nstr)) == NULL) { TP_UNRESOLVED("Memory allocation failed."); goto done; } for (nstr = n = 0, s = test_strings; *s != NULL; s++, n++) { if ((n & 1) == 0) { savedstr[nstr++] = *s; continue; } expectedsize -= (strlen(*s) + 1); if (elftc_string_table_remove(table, *s) == 0) { TP_UNRESOLVED("String removal failed for \"%s\".", *s); goto done; } } imagesz = 0; image = elftc_string_table_image(table, &imagesz); if (image == NULL || imagesz != expectedsize) { TP_FAIL("Incorrect image parameters: [0]=%d, sz=%d != %d", *image, imagesz, expectedsize); goto done; } if (!validate_string_table(nstr, image, imagesz, savedstr)) { TP_FAIL("Image mismatch."); goto done; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); free(savedstr); tet_result(result); } /* * Verify that initialization from a ELF string table works. */ void tcFromSection(void) { Elf *e; Elf_Data *d; Elf_Scn *scn; int fd, result; const char *image; Elf32_Ehdr *eh; Elf32_Shdr *shdr; Elftc_String_Table *table; size_t imagesz, scnindex; table = NULL; result = TET_UNRESOLVED; TP_ANNOUNCE("Loading a table form an ELF section works correctly."); fd = -1; e = NULL; scn = NULL; d = NULL; /* * Create the ELF section. */ if ((fd = open("/dev/null", O_RDONLY)) < 0) { TP_UNRESOLVED("File open failed."); goto done; } if (elf_version(EV_CURRENT) == EV_NONE) { TP_UNRESOLVED("libelf initialization failed."); goto done; } if ((e = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) { TP_UNRESOLVED("Elf open failed: %s", elf_errmsg(-1)); goto done; } if ((eh = elf32_getehdr(e)) == NULL) { TP_UNRESOLVED("Elf open failed: %s", elf_errmsg(-1)); goto done; } eh->e_ident[EI_DATA] = ELFDATA2LSB; eh->e_machine = EM_386; eh->e_version = EV_CURRENT; if ((scn = elf_newscn(e)) == NULL) { TP_UNRESOLVED("Elf newscn failed: %s", elf_errmsg(-1)); goto done; } scnindex = elf_ndxscn(scn); if ((shdr = elf32_getshdr(scn)) == NULL) { TP_UNRESOLVED("Elf getshdr failed: %s", elf_errmsg(-1)); goto done; } shdr->sh_type = SHT_STRTAB; if ((d = elf_newdata(scn)) == NULL) { TP_UNRESOLVED("Elf newdata failed: %s", elf_errmsg(-1)); goto done; } d->d_buf = test_image; d->d_size = sizeof(test_image); if (elf_update(e, ELF_C_NULL) < 0) { TP_UNRESOLVED("elf_update failed: %s", elf_errmsg(-1)); goto done; } if ((scn = elf_getscn(e, scnindex)) == NULL) { TP_UNRESOLVED("Elf getscn failed: %s", elf_errmsg(-1)); goto done; } /* Create a string table from the contents. */ if ((table = elftc_string_table_from_section(scn, 0)) == NULL) { TP_FAIL("from_section call failed."); goto done; } /* Retrieve the image. */ if ((image = elftc_string_table_image(table, &imagesz)) == NULL) { TP_FAIL("from_section call failed."); goto done; } /* Check the retrieved image against the original. */ if (imagesz != sizeof(test_image) || memcmp(image, test_image, imagesz) != 0) { TP_FAIL("image compare failed."); goto done; } result = TET_PASS; done: if (table) (void) elftc_string_table_destroy(table); if (e) elf_end(e); if (fd != -1) (void) close(fd); tet_result(result); } diff --git a/test/nm/Makefile b/test/nm/Makefile index df34d664a64f..fc9f5d1667e6 100644 --- a/test/nm/Makefile +++ b/test/nm/Makefile @@ -1,36 +1,6 @@ -# $Id: Makefile 2137 2011-11-10 13:09:30Z jkoshy $ - -TOP = ../.. - -.include "${TOP}/mk/elftoolchain.tetvars.mk" - -.if !defined(TET_EXECUTE) -TET_EXECUTE= ${.OBJDIR} -.endif - -.if make(tccbuild) -TET_OPTIONS+= -b -.endif - -.if make(tccclean) -TET_OPTIONS+= -c -.endif - -.if make(execute) || make(test) -TET_OPTIONS+= -e -.endif - -.MAIN: all - -.PHONY: clobber execute tccbuild tccclean test - -execute tccbuild tccclean test: - TET_EXECUTE=${TET_EXECUTE} TET_SUITE_ROOT=${.CURDIR} \ - TET_ROOT=${TET_ROOT} ${TET_ROOT}/bin/tcc ${TET_OPTIONS} . - -clobber: clean - rm -rf ${TET_RESULTS_DIR} ${TET_TMP_DIR} +# $Id: Makefile 3028 2014-04-18 16:20:43Z jkoshy $ +TOP= ../.. SUBDIR= ts -.include +.include "${TOP}/mk/elftoolchain.tetbase.mk" diff --git a/test/nm/ts/Makefile b/test/nm/ts/Makefile index b5352371f7d7..6d23d32206bb 100644 --- a/test/nm/ts/Makefile +++ b/test/nm/ts/Makefile @@ -1,12 +1,14 @@ -# $Id: Makefile 2085 2011-10-27 05:06:47Z jkoshy $ +# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ + +TOP= ../../.. SUBDIR+= nm_archive1 SUBDIR+= nm_archive2 SUBDIR+= nm_debug SUBDIR+= nm_object1 SUBDIR+= nm_object2 SUBDIR+= nm_option SUBDIR+= nm_shared_object1 SUBDIR+= nm_shared_object2 -.include +.include "${TOP}/mk/elftoolchain.subdir.mk" diff --git a/test/tet/Makefile b/test/tet/Makefile index e5396862ce2d..602ff6771fd4 100644 --- a/test/tet/Makefile +++ b/test/tet/Makefile @@ -1,64 +1,64 @@ # # Build TET from source. # -# $Id: Makefile 2117 2011-11-09 05:48:03Z jkoshy $ +# $Id: Makefile 3024 2014-04-18 16:20:11Z jkoshy $ # TOP= ../.. .include "${TOP}/mk/elftoolchain.tetvars.mk" TET_BUILD_MARKER= .tet-build-done TET_PATCH_MARKER= .tet-patch-done .MAIN: all .PHONY: all clean clobber depend test .if exists(${TET_ROOT}/configure) # # The TET source tree was present. # all: ${TET_BUILD_MARKER} ${TET_BUILD_MARKER}: ${TET_PATCH_MARKER} cd ${TET_ROOT} && sh ./configure -t lite cd ${TET_ROOT}/src && ${MAKE} all install touch ${TET_BUILD_MARKER} ${TET_PATCH_MARKER}: for f in patches/*.patch; do \ patch -p0 < $${f}; \ done touch ${TET_PATCH_MARKER} clean: cd ${TET_ROOT}/src && ${MAKE} clean rm -f ${TET_BUILD_MARKER} clobber: rm -rf ${TET_ROOT} ${TET_BUILD_MARKER} ${TET_PATCH_MARKER} -depend test: .SILENT +cleandepend depend test: .SILENT true .else # # The TET source tree was not detected. # all depend test: .SILENT echo "ERROR: The distribution of TET v${TET_VERSION} is missing." echo echo "Please download the distribution from:" echo " ${TET_DOWNLOAD_URL}" echo "and unpack it into directory \"${TET_ROOT}\"." echo false clean clobber: rm -f ${TET_BUILD_MARKER} ${TET_PATCH_MARKER} .endif