Index: vendor/elftoolchain/dist/INSTALL =================================================================== --- vendor/elftoolchain/dist/INSTALL (revision 282910) +++ vendor/elftoolchain/dist/INSTALL (revision 282911) @@ -1,306 +1,323 @@ 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 + FreeBSD_ v10.1 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 +:FreeBSD 10.1: + - 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 ``python`` and ``py27-yaml`` packages need to be installed:: + + % sudo pkg install python py27-yaml + + - Building additional documentation is not currently supported under + FreeBSD 10.1. + :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``. ``zlib1g-dev`` Compression library. =================== ===================================== 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 zlib1g-dev - 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 12.04: - The following packages are pre-requisites for building the sources on Ubuntu GNU/Linux 12.04: =================== ===================================== **Package** **Description** =================== ===================================== ``bison`` Parser generator. ``build-essential`` Basic build tools. ``flex`` Lexical analyser. ``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``. ``zlib1g-dev`` Compression library. =================== ===================================== The following command line may be used to install the necessary pre-requisites:: % sudo apt-get install bison build-essential flex libarchive-dev \ m4 pmake zlib1g-dev - 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 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 3165 2015-02-20 20:52:18Z emaste $ +.. $Id: INSTALL 3193 2015-05-04 17:47:14Z jkoshy $ .. Local Variables: .. mode: rst .. End: Index: vendor/elftoolchain/dist/addr2line/addr2line.1 =================================================================== --- vendor/elftoolchain/dist/addr2line/addr2line.1 (revision 282910) +++ vendor/elftoolchain/dist/addr2line/addr2line.1 (revision 282911) @@ -1,159 +1,159 @@ .\" Copyright (c) 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 .\" 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: addr2line.1 2066 2011-10-26 15:40:28Z jkoshy $ +.\" $Id: addr2line.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd July 25, 2010 .Os .Dt ADDR2LINE 1 .Sh NAME .Nm addr2line .Nd translate program addresses to source file names and line numbers .Sh SYNOPSIS .Nm .Op Fl b Ar target | Fl -target Ns = Ns Ar target .Op Fl e Ar pathname | Fl -exe Ns = Ns Ar pathname .Op Fl f | Fl -functions .Op Fl j Ar sectionname | Fl -section Ns = Ns Ar sectionname .Op Fl s | Fl -basename .Op Fl C | Fl -demangle .Op Fl H | Fl -help .Op Fl V | Fl -version .Op Ar hexaddress Ns ... .Sh DESCRIPTION The .Nm utility translates program addresses specified by the command line arguments .Ar hexaddress to their corresponding source file names and line numbers. If no arguments are given to .Nm , it will read these addresses from standard input. .Pp Program addresses specified by arguments .Ar hexaddress are encoded using the conventions accepted by .Xr strtoull 3 . .Pp By default, .Nm will use the executable .Dq Pa a.out . The .Fl e option may be used to specified a different ELF object. .Pp The .Nm utility recognizes the following options: .Bl -tag -width indent .It Fl b Ar target | Fl -target Ns = Ns Ar target This option is recognized by .Nm but is ignored. It is supported for compatibility with GNU binutils. .It Fl e Ar pathname | Fl -exe Ns = Ns Ar pathname Use the ELF object specified by argument .Ar pathname to translate addresses. If this option is not specified, .Nm will use the file .Dq Pa a.out . .It Fl f | Fl -functions Display function names in addition to file and line number information. .It Fl j Ar sectionname | Fl -section Ns = Ns Ar sectionname The values specified by arguments .Ar hexaddress are to be treated as offsets into the section named .Ar sectionname . .It Fl s | -basename Display only the base name for each file name. .It Fl C | Fl -demangle Demangle C++ names. .It Fl H | Fl -help Print a help message. .It Fl V | Fl -version Print a version identifier and exit. .El .Sh OUTPUT FORMAT -If the +If the .Fl f option was not specified, .Nm will print the file name and line number for each address specified on a separate line. .Pp If the .Fl f option was specified, .Nm will print a line containing the name of the function corresponding to program address .Ar hexaddress , followed by a line with the file name and line number. .Pp The .Nm utility prints the file name and line number using the format .Dq FILENAME:LINENUMBER . .Pp If a file or function name could not be determined, .Nm will print a question mark in their place. If the line number could not be determined, .Nm will print a zero in its place. .Sh EXAMPLES To map address 080483c4 in the default executable .Pa a.out to a source file name and line number use: .D1 "% addr2line 080483c4" .Pp To map address 080483c4 in executable .Pa helloworld , use: .D1 "% addr2line -e helloworld 080483c4" .Pp To have .Nm act as a filter reading addresses from its standard input use: .D1 "% addr2line" .Pp To print the function name corresponding to an address in addition to its source file and line number use: .D1 "% addr2line -f 080483c4" .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr nm 1 , .Xr elfdump 1 , .Xr elfcopy 1 , .Xr strtoull 3 .Sh AUTHORS The .Nm utility was written by -.An "Kai Wang" Aq kaiwang27@users.sourceforge.net . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: vendor/elftoolchain/dist/addr2line/addr2line.c =================================================================== --- vendor/elftoolchain/dist/addr2line/addr2line.c (revision 282910) +++ vendor/elftoolchain/dist/addr2line/addr2line.c (revision 282911) @@ -1,411 +1,453 @@ /*- * 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 #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: addr2line.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: addr2line.c 3197 2015-05-12 21:01:31Z emaste $"); static struct option longopts[] = { {"target" , required_argument, NULL, 'b'}, {"demangle", no_argument, NULL, 'C'}, {"exe", required_argument, NULL, 'e'}, {"functions", no_argument, NULL, 'f'}, {"section", required_argument, NULL, 'j'}, {"basename", no_argument, NULL, 's'}, {"help", no_argument, NULL, 'H'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; static int demangle, func, base; static char unknown[] = { '?', '?', '\0' }; static Dwarf_Addr section_base; #define USAGE_MESSAGE "\ Usage: %s [options] hexaddress...\n\ Map program addresses to source file names and line numbers.\n\n\ Options:\n\ -b TGT | --target=TGT (Accepted but ignored).\n\ -e EXE | --exec=EXE Use program \"EXE\" to translate addresses.\n\ -f | --functions Display function names.\n\ -j NAME | --section=NAME Values are offsets into section \"NAME\".\n\ -s | --basename Only show the base name for each file name.\n\ -C | --demangle Demangle C++ names.\n\ -H | --help Print a help message.\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 version(void) { fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(0); } +/* + * Handle DWARF 4 'offset from' DW_AT_high_pc. Although we don't + * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1) + * generate DW_AT_high_pc as an offset from DW_AT_low_pc. + * + * "If the value of the DW_AT_high_pc is of class address, it is the + * relocated address of the first location past the last instruction + * associated with the entity; if it is of class constant, the value + * is an unsigned integer offset which when added to the low PC gives + * the address of the first location past the last instruction + * associated with the entity." + * + * DWARF4 spec, section 2.17.2. + */ +static int +handle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc) +{ + Dwarf_Error de; + Dwarf_Half form; + Dwarf_Attribute at; + int ret; + + ret = dwarf_attr(die, DW_AT_high_pc, &at, &de); + if (ret == DW_DLV_ERROR) { + warnx("dwarf_attr failed: %s", dwarf_errmsg(de)); + return (ret); + } + ret = dwarf_whatform(at, &form, &de); + if (ret == DW_DLV_ERROR) { + warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); + return (ret); + } + if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT) + *hipc += lopc; + + return (DW_DLV_OK); +} + static void search_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr, const char **rlt_func) { Dwarf_Die ret_die, spec_die; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned lopc, hipc; Dwarf_Off ref; Dwarf_Attribute sub_at, spec_at; char *func0; int ret; if (*rlt_func != NULL) return; if (dwarf_tag(die, &tag, &de)) { warnx("dwarf_tag: %s", dwarf_errmsg(de)); goto cont_search; } if (tag == DW_TAG_subprogram) { if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) || dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) goto cont_search; + if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) + goto cont_search; if (addr < lopc || addr >= hipc) goto cont_search; /* Found it! */ *rlt_func = unknown; ret = dwarf_attr(die, DW_AT_name, &sub_at, &de); if (ret == DW_DLV_ERROR) return; if (ret == DW_DLV_OK) { if (dwarf_formstring(sub_at, &func0, &de)) *rlt_func = unknown; else *rlt_func = func0; return; } /* * If DW_AT_name is not present, but DW_AT_specification is * present, then probably the actual name is in the DIE * referenced by DW_AT_specification. */ if (dwarf_attr(die, DW_AT_specification, &spec_at, &de)) return; if (dwarf_global_formref(spec_at, &ref, &de)) return; if (dwarf_offdie(dbg, ref, &spec_die, &de)) return; if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de)) *rlt_func = unknown; return; } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_func(dbg, ret_die, addr, rlt_func); /* Search sibling. */ ret = dwarf_siblingof(dbg, die, &ret_die, &de); if (ret == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_func(dbg, ret_die, addr, rlt_func); } static void translate(Dwarf_Debug dbg, const char* addrstr) { Dwarf_Die die; Dwarf_Line *lbuf; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned lopc, hipc, addr, lineno, plineno; Dwarf_Signed lcount; Dwarf_Addr lineaddr, plineaddr; const char *funcname; char *file, *file0, *pfile; char demangled[1024]; int i, ret; addr = strtoull(addrstr, NULL, 16); addr += section_base; lineno = 0; file = unknown; 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)); goto out; } /* 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"); goto out; } if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) && !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) { /* * Check if the address falls into the PC range of * this CU. */ + if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) + continue; if (addr < lopc || addr >= hipc) continue; } if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK) { warnx("dwarf_srclines: %s", dwarf_errmsg(de)); goto out; } plineaddr = ~0ULL; plineno = 0; pfile = unknown; for (i = 0; i < lcount; i++) { if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); goto out; } if (dwarf_lineno(lbuf[i], &lineno, &de)) { warnx("dwarf_lineno: %s", dwarf_errmsg(de)); goto out; } if (dwarf_linesrc(lbuf[i], &file0, &de)) { warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); } else file = file0; if (addr == lineaddr) goto out; else if (addr < lineaddr && addr > plineaddr) { lineno = plineno; file = pfile; goto out; } plineaddr = lineaddr; plineno = lineno; pfile = file; } } out: funcname = NULL; if (ret == DW_DLV_OK && func) search_func(dbg, die, addr, &funcname); if (func) { if (funcname == NULL) funcname = unknown; if (demangle && !elftc_demangle(funcname, demangled, sizeof(demangled), 0)) printf("%s\n", demangled); else printf("%s\n", funcname); } (void) printf("%s:%ju\n", base ? basename(file) : file, lineno); /* * Reset internal CU pointer, so we will start from the first CU * next round. */ while (ret != DW_DLV_NO_ENTRY) { if (ret == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", dwarf_errmsg(de)); ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de); } } static void find_section_base(const char *exe, Elf *e, const char *section) { Dwarf_Addr off; Elf_Scn *scn; GElf_Ehdr eh; GElf_Shdr sh; size_t shstrndx; int elferr; const char *name; if (gelf_getehdr(e, &eh) != &eh) { warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); return; } if (!elf_getshstrndx(e, &shstrndx)) { warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); return; } (void) elf_errno(); off = 0; scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { if (gelf_getshdr(scn, &sh) == NULL) { warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); continue; } if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL) goto next; if (!strcmp(section, name)) { if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) { /* * For executables, section base is the virtual * address of the specified section. */ section_base = sh.sh_addr; } else if (eh.e_type == ET_REL) { /* * For relocatables, section base is the * relative offset of the specified section * to the start of the first section. */ section_base = off; } else warnx("unknown e_type %u", eh.e_type); return; } next: off += sh.sh_size; } elferr = elf_errno(); if (elferr != 0) warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section); } int main(int argc, char **argv) { Elf *e; Dwarf_Debug dbg; Dwarf_Error de; const char *exe, *section; char line[1024]; int fd, i, opt; exe = NULL; section = NULL; while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) != -1) { switch (opt) { case 'b': /* ignored */ break; case 'C': demangle = 1; break; case 'e': exe = optarg; break; case 'f': func = 1; break; case 'j': section = optarg; break; case 's': base = 1; break; case 'H': usage(); case 'V': version(); default: usage(); } } argv += optind; argc -= optind; if (exe == NULL) exe = "a.out"; if ((fd = open(exe, O_RDONLY)) < 0) err(EXIT_FAILURE, "%s", exe); if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de)) errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de)); if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de)); if (section) find_section_base(exe, e, section); else section_base = 0; if (argc > 0) for (i = 0; i < argc; i++) translate(dbg, argv[i]); else while (fgets(line, sizeof(line), stdin) != NULL) { translate(dbg, line); fflush(stdout); } dwarf_finish(dbg, &de); (void) elf_end(e); exit(0); } Index: vendor/elftoolchain/dist/ar/ar.1 =================================================================== --- vendor/elftoolchain/dist/ar/ar.1 (revision 282910) +++ vendor/elftoolchain/dist/ar/ar.1 (revision 282911) @@ -1,603 +1,603 @@ .\" Copyright (c) 2007,2009-2012 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: ar.1 2742 2012-12-10 18:47:36Z jkoshy $ +.\" $Id: ar.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd December 10, 2012 .Os .Dt AR 1 .Sh NAME .Nm ar .Nd manage archives .Sh SYNOPSIS .Nm .Fl d .Op Fl T .Op Fl f .Op Fl j .Op Fl v .Op Fl z .Ar archive .Ar .Nm .Fl m .Op Fl T .Op Fl a Ar position-after .Op Fl b Ar position-before .Op Fl f .Op Fl i Ar position-before .Op Fl j .Op Fl s | Fl S .Op Fl z .Ar archive .Ar .Nm .Fl p .Op Fl T .Op Fl f .Op Fl v .Ar archive .Op Ar .Nm .Fl q .Op Fl T .Op Fl c .Op Fl D .Op Fl f .Op Fl F Ar flavor | Fl -flavor Ar flavor .Op Fl s | Fl S .Op Fl v .Op Fl z .Ar archive .Ar .Nm .Fl r .Op Fl T .Op Fl a Ar position-after .Op Fl b Ar position-before .Op Fl c .Op Fl D .Op Fl f .Op Fl F Ar flavor | Fl -flavor Ar flavor .Op Fl i Ar position-before .Op Fl j .Op Fl s | Fl S .Op Fl u .Op Fl v .Op Fl z .Ar archive .Ar .Nm .Fl s .Op Fl D .Op Fl j .Op Fl z .Ar archive .Nm .Fl t .Op Fl f .Op Fl T .Op Fl v .Ar archive .Op Ar .Nm .Fl x .Op Fl C .Op Fl T .Op Fl f .Op Fl o .Op Fl u .Op Fl v .Ar archive .Op Ar .Nm .Fl M .Nm .Fl V .Sh DESCRIPTION The .Nm utility creates and maintains groups of files combined into an archive. Once an archive has been created, new files can be added to it, and existing files can be extracted, deleted or replaced. .Pp Files are named in the archive by their last file name component, so if a file referenced by a path containing a .Dq / is archived, it will be named by the last component of the path. Similarly when matching paths listed on the command line against file names stored in the archive, only the last component of the path will be compared. .Pp The normal use of .Nm is for the creation and maintenance of libraries suitable for use with the link editor .Xr ld 1 , although it is not restricted to this purpose. The .Nm utility can create and manage an archive symbol table (see .Xr ar 5 ) used to speed up link editing operations. If a symbol table is present in an archive, it will be kept up-to-date by subsequent operations on the archive. .Sh OPTIONS The .Nm utility supports the following options: .Bl -tag -width indent .It Fl a Ar member-after When used with option .Fl m this option specifies that the archive members specified by arguments .Ar are moved to after the archive member named by argument .Ar member-after . When used with option .Fl r this option specifies that the files specified by arguments .Ar are added after the archive member named by argument .Ar member-after . .It Fl b Ar member-before When used with option .Fl m this option specifies that the archive members specified by arguments .Ar are moved to before the archive member named by argument .Ar member-before . When used with option .Fl r this option specifies that the files specified by arguments .Ar are added before the archive member named by argument .Ar member-before . .It Fl c Suppress the informational message printed when a new archive is created using the .Fl r and .Fl q options. .It Fl C Prevent extracted files from replacing like-named files in the file system. .It Fl d Delete the members named by arguments .Ar from the archive specified by argument .Ar archive . The archive's symbol table, if present, is updated to reflect the new contents of the archive. .It Fl D -When used in combination with the +When used in combination with the .Fl r or .Fl q -option, insert 0's instead of the real mtime, uid and gid values +option, insert 0's instead of the real mtime, uid and gid values and 0644 instead of file mode from the members named by arguments .Ar . This ensures that checksums on the resulting archives are reproducible when member contents are identical. .It Fl f Synonymous with option .Fl T . .It Fl F Ar flavor | Fl -flavor Ar flavor Create archives with the specified archive format. Legal values for argument .Ar flavor are: .Bl -tag -width indent -compact .It Ar bsd Create BSD format archives. .It Ar gnu An alias for .Ar svr4 . .It Ar svr4 Create SVR4 format archives. .El If this option is not specified, .Nm will create archives using the SVR4 format. .It Fl i Ar member-before Synonymous with option .Fl b . .It Fl j This option is accepted for compatibility with the .Tn FreeBSD version of the .Nm utility, but is ignored. .It Fl l This option is accepted for compatibility with GNU .Xr ar 1 , but is ignored. .It Fl m Move archive members specified by arguments .Ar within the archive. If a position has been specified by one of the .Fl a , .Fl b or .Fl i options, the members are moved to before or after the specified position. If no position has been specified, the specified members are moved to the end of the archive. If the archive has a symbol table, it is updated to reflect the new contents of the archive. .It Fl M Read and execute MRI librarian commands from standard input. The commands understood by the .Nm utility are described in the section .Sx "MRI Librarian Commands" . .It Fl o Preserve the original modification times of members when extracting them. .It Fl p Write the contents of the specified archive members named by arguments .Ar to standard output. If no members were specified, the contents of all the files in the archive are written in the order they appear in the archive. .It Fl q Append the files specified by arguments .Ar to the archive specified by argument .Ar archive without checking if the files already exist in the archive. The archive symbol table will be updated as needed. If the file specified by the argument .Ar archive does not already exist, a new archive will be created. .It Fl r Replace (add) the files specified by arguments .Ar in the archive specified by argument .Ar archive , creating the archive if necessary. Replacing existing members will not change the order of members within the archive. If a file named in arguments .Ar does not exist, existing members in the archive that match that name are not changed. New files are added to the end of the archive unless one of the positioning options .Fl a , .Fl b or .Fl i is specified. The archive symbol table, if it exists, is updated to reflect the new state of the archive. .It Fl s Add an archive symbol table (see .Xr ar 5 ) to the archive specified by argument .Ar archive . Invoking .Nm with the .Fl s option alone is equivalent to invoking .Xr ranlib 1 . .It Fl S Do not generate an archive symbol table. .It Fl t For .Nm , list the files specified by arguments .Ar in the order in which they appear in the archive, one per line. If no files are specified, all files in the archive are listed. .It Fl T Use only the first fifteen characters of the archive member name or command line file name argument when naming archive members. .It Fl u Conditionally update the archive or extract members. When used with the .Fl r option, files named by arguments .Ar will be replaced in the archive if they are newer than their archived versions. When used with the .Fl x option, the members specified by arguments .Ar will be extracted only if they are newer than the corresponding files in the file system. .It Fl v Provide verbose output. When used with the .Fl d , .Fl m , .Fl q or .Fl x options, .Nm gives a file-by-file description of the archive modification being -performed, which consists of three white-space seperated fields: +performed, which consists of three white-space separated fields: the option letter, a dash .Dq "-" , and the file name. When used with the .Fl r option, .Nm displays the description as above, but the initial letter is an .Dq a if the file is added to the archive, or an .Dq r if the file replaces a file already in the archive. When used with the .Fl p option, the name of the file enclosed in .Dq < and .Dq > characters is written to standard output preceded by a single newline character and followed by two newline characters. The contents of the named file follow the file name. When used with the .Fl t option, .Nm displays eight whitespace separated fields: the file permissions as displayed by .Xr strmode 3 , decimal user and group IDs separated by a slash ( .Dq / Ns ) , the file size in bytes, the file modification time in .Xr strftime 3 format .Dq "%b %e %H:%M %Y" , and the name of the file. .It Fl V Print a version identifier and exit. .It Fl x Extract archive members specified by arguments .Ar into the current directory. If no members have been specified, extract all members of the archive. If the file corresponding to an extracted member does not exist it will be created. If the file corresponding to an extracted member does exist, its owner and group will not be changed while its contents will be overwritten and its permissions will set to that entered in the archive. The file's access and modification time would be that of the time of extraction unless the .Fl o option was specified. .It Fl z This option is accepted for compatibility with the .Tn FreeBSD version of the .Nm utility, but is ignored. .El .Ss "MRI Librarian Commands" If the .Fl M option is specified, the .Nm utility will read and execute commands from its standard input. If standard input is a terminal, the .Nm utility will display the prompt .Dq Li "AR >" before reading a line, and will continue operation even if errors are encountered. If standard input is not a terminal, the .Nm utility will not display a prompt and will terminate execution on encountering an error. .Pp Each input line contains a single command. Words in an input line are separated by whitespace characters. The first word of the line is the command, the remaining words are the arguments to the command. The command word may be specified in either case. Arguments may be separated by commas or blanks. .Pp Empty lines are allowed and are ignored. Long lines are continued by ending them with the .Dq Li + character. .Pp The .Dq Li * and .Dq Li "\;" characters start a comment. Comments extend till the end of the line. .Pp When executing an MRI librarian script the .Nm utility works on a temporary copy of an archive. Changes to the copy are made permanent using the .Ic save command. .Pp Commands understood by the .Nm utility are: .Bl -tag -width indent .It Ic addlib Ar archive | Ic addlib Ar archive Pq Ar member Oo Li , Ar member Oc Ns ... Add the contents of the archive named by argument .Ar archive to the current archive. If specific members are named using the arguments .Ar member , then those members are added to the current archive. If no members are specified, the entire contents of the archive are added to the current archive. .It Ic addmod Ar member Oo Li , Ar member Oc Ns ... Add the files named by arguments .Ar member to the current archive. .It Ic clear Discard all the contents of the current archive. .It Ic create Ar archive Create a new archive named by the argument .Ar archive , and makes it the current archive. If the named archive already exists, it will be overwritten when the .Ic save command is issued. .It Ic delete Ar module Oo Li , Ar member Oc Ns ... Delete the modules named by the arguments .Ar member from the current archive. .It Ic directory Ar archive Po Ar member Oo Li , Ar member Oc Ns ... Pc Op Ar outputfile List each named module in the archive. The format of the output depends on the verbosity setting set using the .Ic verbose command. Output is sent to standard output, or to the file specified by argument .Ar outputfile . .It Ic end Exit successfully from the .Nm utility. Any unsaved changes to the current archive will be discarded. .It Ic extract Ar member Oo Li , Ar member Oc Ns ... Extract the members named by the arguments .Ar member from the current archive. .It Ic list Display the contents of the current archive in verbose style. .It Ic open Ar archive Open the archive named by argument .Ar archive and make it the current archive. .It Ic replace Ar member Oo Li , Ar member Oc Ns ... Replace named members in the current archive with the files specified by arguments .Ar member . The files must be present in the current directory and the named modules must already exist in the current archive. .It Ic save Commit all changes to the current archive. .It Ic verbose Toggle the verbosity of the .Ic directory command. .El .Sh EXAMPLES To create a new archive .Pa ex.a containing three files .Pa ex1.o , .Pa ex2.o and .Pa ex3.o , use: .Dl "ar -rc ex.a ex1.o ex2.o ex3.o" .Pp To add an archive symbol table to an existing archive .Pa ex.a , use: .Dl "ar -s ex.a" .Pp To delete file .Pa ex1.o from archive .Pa ex.a , use: .D1 "ar -d ex.a ex1.o" .Pp To verbosely list the contents of archive .Pa ex.a , use: .D1 "ar -tv ex.a" .Pp To create a new archive .Pa ex.a containing the files .Pa ex1.o , and .Pa ex2.o , using MRI librarian commands, use the following script: .Bd -literal -offset indent create ex.a * specify the output archive addmod ex1.o ex2.o * add modules -save * save pending changes +save * save pending changes end * exit the utility .Ed .Sh DIAGNOSTICS .Ex -std .Sh SEE ALSO .Xr ld 1 , .Xr ranlib 1 , .Xr archive 3 , .Xr elf 3 , .Xr strftime 3 , .Xr strmode 3 , .Xr ar 5 .Sh STANDARDS COMPLIANCE The .Nm utility's support for the .Fl a , .Fl b , .Fl c , .Fl i , .Fl m , .Fl p , .Fl q , .Fl r , .Fl s , .Fl t , .Fl u , .Fl v , .Fl C and .Fl T options is believed to be compliant with .St -p1003.2 . .Sh HISTORY An .Nm command first appeared in AT&T UNIX Version 1. In .Fx 8.0 , -.An "Kai Wang" Aq kaiw@FreeBSD.org +.An Kai Wang Aq Mt kaiw@FreeBSD.org reimplemented .Nm using the .Lb libarchive and the .Lb libelf . Index: vendor/elftoolchain/dist/ar/ar.5 =================================================================== --- vendor/elftoolchain/dist/ar/ar.5 (revision 282910) +++ vendor/elftoolchain/dist/ar/ar.5 (revision 282911) @@ -1,327 +1,327 @@ .\" 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: ar.5 2066 2011-10-26 15:40:28Z jkoshy $ +.\" $Id: ar.5 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd November 28, 2010 .Os .Dt AR 5 .Sh NAME .Nm ar .Nd archive file format for .Xr ar 1 and .Xr ranlib 1 .Sh SYNOPSIS .In ar.h .Sh DESCRIPTION .Xr ar 1 archives are created and managed by the .Xr ar 1 and .Xr ranlib 1 utilities. These archives are typically used during program development to hold libraries of program objects. An .Xr ar 1 archive is contained in a single operating system file. .Pp This manual page documents two variants of the .Xr ar 1 archive format: the BSD archive format, and the SVR4/GNU archive format. .Pp In both variants the archive file starts with an identifying byte sequence of the seven ASCII characters .Sq Li "!" followed by a ASCII linefeed character .Po see the constant .Dq ARMAG in the header file .In ar.h .Pc . .Pp Archive members follow the initial identifying byte sequence. Each archive member is prefixed by a fixed size header describing the file attributes associated with the member. .Ss "Archive Headers" An archive header describes the file attributes for the archive member that follows it. The .Xr ar 5 format only supports a limited number of attributes: the file name, the file creation time stamp, the uid and gid of the creator, the file mode and the file size. .Pp Archive headers are placed at an even byte offset in the archive file. If the data for an archive member ends at an odd byte offset, then a padding byte with value 0x0A is used to position the next archive header on an even byte offset. .Pp An archive header comprises the following fixed sized fields: .Bl -tag -width "Li ar_name" .It Ar ar_name (16 bytes) The file name of the archive member. The format of this field varies between the BSD and SVR4/GNU formats and is described in more detail in the section .Sx "Representing File Names" below. .It Ar ar_date (12 bytes) The file modification time for the member in seconds since the epoch, encoded as a decimal number. .It Ar ar_uid (6 bytes) The uid associated with the archive member, encoded as a decimal number. .It Ar ar_gid (6 bytes) The gid associated with the archive member, encoded as a decimal number. .It Ar ar_mode (8 bytes) The file mode for the archive member, encoded as an octal number. .It Ar ar_size (10 bytes) In the SVR4/GNU archive format this field holds the size in bytes of the archive member, encoded as a decimal number. In the BSD archive format, for short file names, this field holds the size in bytes of the archive member, encoded as a decimal number. For long file names .Po see .Sx "Representing File Names" below .Pc , the field contains the combined size of the archive member and its file name, encoded as a decimal number. .It Ar ar_fmag (2 bytes) This field holds 2 bytes with values 0x96 and 0x0A respectively, marking the end of the header. .El .Pp Unused bytes in the fields of an archive header are set to the value 0x20. .Ss "Representing File Names" The BSD and SVR4/GNU variants use different schemes for encoding file names for members. .Bl -tag -width "SVR4/GNU" .It "BSD" -File names that are upto 16 bytes long and which do not contain +File names that are up to 16 bytes long and which do not contain embedded spaces are stored directly in the .Ar ar_name field of the archive header. File names that are either longer than 16 bytes or which contain embedded spaces are stored immediately after the archive header and the .Ar ar_name field of the archive header is set to the string .Dq "#1/" followed by a decimal representation of the number of bytes needed for the file name. In addition, the .Ar ar_size field of the archive header is set to the decimal representation of the combined sizes of the archive member and the file name. The file contents of the member follows the file name without further padding. .Pp As an example, if the file name for a member was .Dq "A B" and its contents was the string .Dq "C D" , then the .Ar ar_name field of the header would contain .Dq Li "#1/3" , the .Ar ar_size field of the header would contain .Dq Li 6 , and the bytes immediately following the header would be 0x41, 0x20, 0x42, 0x43, 0x20 and 0x44 .Po ASCII .Dq "A BC D" .Pc . .It "SVR4/GNU" -File names that are upto 15 characters long are stored directly in the +File names that are up to 15 characters long are stored directly in the .Ar ar_name field of the header, terminated by a .Dq Li / character. .Pp If the file name is larger than would fit in space for the .Ar ar_name field, then the actual file name is kept in the archive string table .Po see .Sx "Archive String Tables" below .Pc , and the decimal offset of the file name in the string table is stored in the .Ar ar_name field, prefixed by a .Dq Li / character. .Pp As an example, if the real file name has been stored at offset 768 in the archive string table, the .Ar ar_name field of the header will contain the string .Dq /768 . .El .Ss "Special Archive Members" The following archive members are special. .Bl -tag -width indent .It Dq Li / In the SVR4/GNU variant of the archive format, the archive member with name .Dq Li / denotes an archive symbol table. If present, this member will be the very first member in the archive. .It Dq Li // In the SVR4/GNU variant of the archive format, the archive member with name .Dq Li // denotes the archive string table. This special member is used to hold filenames that do not fit in the file name field of the header .Po see .Sx "Representing File Names" above .Pc . If present, this member immediately follows the archive symbol table if an archive symbol table is present, or is the first member otherwise. .It Dq Li "__.SYMDEF" This special member contains the archive symbol table in the BSD variant of the archive format. If present, this member will be the very first member in the archive. .El .Ss "Archive String Tables" An archive string table is used in the SVR4/GNU archive format to hold file names that are too large to fit into the constraints of the .Ar ar_name field of the archive header. An archive string table contains a sequence of file names. Each file name in the archive string table is terminated by the byte sequence 0x2F, 0x0A .Po the ASCII string .Dq "/\en" .Pc . No padding is used to separate adjacent file names. .Ss "Archive Symbol Tables" Archive symbol tables are used to speed up link editing by providing a -mapping between the program symbols defined in the archive +mapping between the program symbols defined in the archive and the corresponding archive members. Archive symbol tables are managed by the .Xr ranlib 1 utility. .Pp The format of archive symbol tables is as follows: .Bl -tag -width "SVR4/GNU" .It BSD In the BSD archive format, the archive symbol table comprises of two parts: a part containing an array of .Vt "struct ranlib" descriptors, followed by a part containing a symbol string table. The sizes and layout of the structures that make up a BSD format archive symbol table are machine dependent. .Pp The part containing .Vt "struct ranlib" descriptors begins with a field containing the size in bytes of the array of .Vt "struct ranlib" descriptors encoded as a C .Vt long value. .Pp The array of .Vt "struct ranlib" descriptors follows the size field. Each .Vt "struct ranlib" descriptor describes one symbol. .Pp A .Vt "struct ranlib" descriptor comprises two fields: .Bl -tag -width "Ar ran_strx" -compact .It Ar ran_strx .Pq C Vt long This field contains the zero-based offset of the symbol name in the symbol string table. .It Ar ran_off .Pq C Vt long This field is the file offset to the archive header for the archive member defining the symbol. .El .Pp The part containing the symbol string table begins with a field containing the size in bytes of the string table, encoded as a C .Vt long value. This string table follows the size field, and contains NUL-terminated strings for the symbols in the symbol table. .It SVR4/GNU In the SVR4/GNU archive format, the archive symbol table starts with a 4-byte binary value containing the number of entries contained in the archive symbol table. This count of entries is stored most significant byte first. .Pp Next, there are .Ar count 4-byte numbers, each stored most significant byte first. Each number is a binary offset to the archive header for the member in the archive file for the corresponding symbol table entry. .Pp After the binary offset values, there are .Ar count NUL-terminated strings in sequence, holding the symbol names for the corresponding symbol table entries. .El .Sh STANDARDS COMPLIANCE The .Xr ar 1 archive format is not currently specified by a standard. .Pp This manual page documents the .Xr ar 1 archive formats used by the .Bx 4.4 and .Ux SVR4 operating system releases. .Sh SEE ALSO .Xr ar 1 , .Xr ld 1 , .Xr ranlib 1 , .Xr elf 3 , .Xr elf_getarsym 3 , .Xr elf_rand 3 Index: vendor/elftoolchain/dist/ar/ar.c =================================================================== --- vendor/elftoolchain/dist/ar/ar.c (revision 282910) +++ vendor/elftoolchain/dist/ar/ar.c (revision 282911) @@ -1,433 +1,433 @@ /*- * Copyright (c) 2007 Kai Wang * Copyright (c) 2007 Tim Kientzle * Copyright (c) 2007 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. */ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Hugh Smith at The University of Guelph. * * 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 University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 "ar.h" -ELFTC_VCSID("$Id: ar.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: ar.c 3183 2015-04-10 16:18:42Z emaste $"); enum options { OPTION_HELP }; static struct option longopts[] = { {"flavor", required_argument, NULL, 'F'}, {"help", no_argument, NULL, OPTION_HELP}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; static void bsdar_usage(void); static void ranlib_usage(void); static void set_mode(struct bsdar *bsdar, char opt); static void only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes); static void bsdar_version(void); int main(int argc, char **argv) { struct bsdar *bsdar, bsdar_storage; char *arcmd, *argv1_saved; size_t len; int i, opt; bsdar = &bsdar_storage; memset(bsdar, 0, sizeof(*bsdar)); arcmd = argv1_saved = NULL; bsdar->output = stdout; if ((bsdar->progname = ELFTC_GETPROGNAME()) == NULL) bsdar->progname = "ar"; if (elf_version(EV_CURRENT) == EV_NONE) bsdar_errc(bsdar, 0, "ELF library initialization failed: %s", elf_errmsg(-1)); /* * Act like ranlib if our name ends in "ranlib"; this - * accomodates names like "arm-freebsd7.1-ranlib", + * accommodates names like "arm-freebsd7.1-ranlib", * "bsdranlib", etc. */ len = strlen(bsdar->progname); if (len >= strlen("ranlib") && strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) { while ((opt = getopt_long(argc, argv, "tDV", longopts, NULL)) != -1) { switch(opt) { case 't': /* Ignored. */ break; case 'D': bsdar->options |= AR_D; break; case 'V': bsdar_version(); break; case OPTION_HELP: ranlib_usage(); default: ranlib_usage(); } } argv += optind; argc -= optind; if (*argv == NULL) ranlib_usage(); bsdar->options |= AR_S; for (;(bsdar->filename = *argv++) != NULL;) ar_write_archive(bsdar, 's'); exit(EXIT_SUCCESS); } else { if (argc < 2) bsdar_usage(); /* * Tack on a leading '-', for old-style usage. */ if (*argv[1] != '-') { argv1_saved = argv[1]; len = strlen(argv[1]) + 2; if ((arcmd = malloc(len)) == NULL) bsdar_errc(bsdar, errno, "malloc failed"); (void) snprintf(arcmd, len, "-%s", argv[1]); argv[1] = arcmd; } } while ((opt = getopt_long(argc, argv, "abCcdDfF:ijlMmopqrSsTtuVvxz", longopts, NULL)) != -1) { switch(opt) { case 'a': bsdar->options |= AR_A; break; case 'b': case 'i': bsdar->options |= AR_B; break; case 'C': bsdar->options |= AR_CC; break; case 'c': bsdar->options |= AR_C; break; case 'd': set_mode(bsdar, opt); break; case 'D': bsdar->options |= AR_D; break; case 'F': if (!strcasecmp(optarg, "svr4") || !strcasecmp(optarg, "gnu")) bsdar->options &= ~AR_BSD; else if (!strcasecmp(optarg, "bsd")) bsdar->options |= AR_BSD; else bsdar_usage(); break; case 'f': case 'T': bsdar->options |= AR_TR; break; case 'j': /* ignored */ break; case 'l': /* ignored, for GNU ar comptibility */ break; case 'M': set_mode(bsdar, opt); break; case 'm': set_mode(bsdar, opt); break; case 'o': bsdar->options |= AR_O; break; case 'p': set_mode(bsdar, opt); break; case 'q': set_mode(bsdar, opt); break; case 'r': set_mode(bsdar, opt); break; case 'S': bsdar->options |= AR_SS; break; case 's': bsdar->options |= AR_S; break; case 't': set_mode(bsdar, opt); break; case 'u': bsdar->options |= AR_U; break; case 'V': bsdar_version(); break; case 'v': bsdar->options |= AR_V; break; case 'x': set_mode(bsdar, opt); break; case 'z': /* ignored */ break; case OPTION_HELP: bsdar_usage(); default: bsdar_usage(); } } /* Restore argv[1] if we had modified it. */ if (arcmd != NULL) { argv[1] = argv1_saved; free(arcmd); arcmd = argv1_saved = NULL; } argv += optind; argc -= optind; if (*argv == NULL && bsdar->mode != 'M') bsdar_usage(); if (bsdar->options & AR_A && bsdar->options & AR_B) bsdar_errc(bsdar, 0, "only one of -a and -[bi] options allowed"); if (bsdar->options & AR_J && bsdar->options & AR_Z) bsdar_errc(bsdar, 0, "only one of -j and -z options allowed"); if (bsdar->options & AR_S && bsdar->options & AR_SS) bsdar_errc(bsdar, 0, "only one of -s and -S options allowed"); if (bsdar->options & (AR_A | AR_B)) { if (*argv == NULL) bsdar_errc(bsdar, 0, "no position operand specified"); if ((bsdar->posarg = basename(*argv)) == NULL) bsdar_errc(bsdar, errno, "basename failed"); argc--; argv++; } if (bsdar->options & AR_A) only_mode(bsdar, "-a", "mqr"); if (bsdar->options & AR_B) only_mode(bsdar, "-b", "mqr"); if (bsdar->options & AR_C) only_mode(bsdar, "-c", "qr"); if (bsdar->options & AR_CC) only_mode(bsdar, "-C", "x"); if (bsdar->options & AR_D) only_mode(bsdar, "-D", "qr"); if (bsdar->options & AR_O) only_mode(bsdar, "-o", "x"); if (bsdar->options & AR_SS) only_mode(bsdar, "-S", "mqr"); if (bsdar->options & AR_U) only_mode(bsdar, "-u", "qrx"); if (bsdar->mode == 'M') { ar_mode_script(bsdar); exit(EXIT_SUCCESS); } if ((bsdar->filename = *argv) == NULL) bsdar_usage(); bsdar->argc = --argc; bsdar->argv = ++argv; if ((!bsdar->mode || strchr("ptx", bsdar->mode)) && bsdar->options & AR_S) { ar_write_archive(bsdar, 's'); if (!bsdar->mode) exit(EXIT_SUCCESS); } switch(bsdar->mode) { case 'd': case 'm': case 'q': case 'r': ar_write_archive(bsdar, bsdar->mode); break; case 'p': case 't': case 'x': ar_read_archive(bsdar, bsdar->mode); break; default: bsdar_usage(); /* NOTREACHED */ } for (i = 0; i < bsdar->argc; i++) if (bsdar->argv[i] != NULL) bsdar_warnc(bsdar, 0, "%s: not found in archive", bsdar->argv[i]); exit(EXIT_SUCCESS); } static void set_mode(struct bsdar *bsdar, char opt) { if (bsdar->mode != '\0' && bsdar->mode != opt) bsdar_errc(bsdar, 0, "Can't specify both -%c and -%c", opt, bsdar->mode); bsdar->mode = opt; } static void only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes) { if (strchr(valid_modes, bsdar->mode) == NULL) bsdar_errc(bsdar, 0, "Option %s is not permitted in mode -%c", opt, bsdar->mode); } #define AR_USAGE_MESSAGE "\ Usage: %s [options] archive file...\n\ Manage archives.\n\n\ Where is one of:\n\ -d Delete members from the archive.\n\ -m Move archive members within the archive.\n\ -p Write the contents of members to standard output.\n\ -q Append files to an archive.\n\ -r Replace (add) files to an archive.\n\ -s Add an archive symbol to an archive.\n\ -t List files in an archive.\n\ -x Extract members from an archive.\n\ -M Execute MRI librarian commands.\n\ -V Print a version identifier and exit.\n\n\ Options:\n\ -a MEMBER Add members after the specified member.\n\ -b MEMBER | -i MEMBER\n\ Add members before the specified member.\n\ -c Do not print a message when creating a new archive.\n\ -f | -T Only use the first fifteen characters of the member name.\n\ -j (This option is accepted, but is ignored).\n\ -l (This option is accepted, but is ignored).\n\ -o Preserve modification times when extracting members.\n\ -u Conditionally update or extract members.\n\ -v Be verbose.\n\ -z (This option is accepted, but is ignored).\n\ -C Do not overwrite existing files in the file system.\n\ -D Use fixed metadata, for consistent archive checksums.\n\ -F FORMAT | --flavor=FORMAT\n\ Create archives with the specified format.\n\ -S Do not generate an archive symbol table.\n" static void bsdar_usage(void) { (void) fprintf(stderr, AR_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } #define RANLIB_USAGE_MESSAGE "\ Usage: %s [options] archive...\n\ Update or create archive symbol tables.\n\n\ Options:\n\ -t (This option is accepted, but ignored).\n\ -D Use fixed metadata, for consistent archive checksums.\n\ -V Print a version identifier and exit.\n" static void ranlib_usage(void) { (void)fprintf(stderr, RANLIB_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } static void bsdar_version(void) { (void)printf("%s (%s, %s)\n", ELFTC_GETPROGNAME(), archive_version_string(), elftc_version()); exit(EXIT_SUCCESS); } Index: vendor/elftoolchain/dist/ar/ranlib.1 =================================================================== --- vendor/elftoolchain/dist/ar/ranlib.1 (revision 282910) +++ vendor/elftoolchain/dist/ar/ranlib.1 (revision 282911) @@ -1,86 +1,86 @@ .\" Copyright (c) 2007,2009-2012 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: ranlib.1 2739 2012-12-09 17:07:46Z jkoshy $ +.\" $Id: ranlib.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd December 9, 2012 .Os .Dt RANLIB 1 .Sh NAME .Nm ranlib .Nd update archive symbol tables .Sh SYNOPSIS .Nm .Op Fl D .Op Fl t .Ar archive Ns ... .Nm .Fl V .Sh DESCRIPTION The .Nm ranlib utility is used to update an existing archive symbol table in an .Xr ar 1 archive, or to add an archive symbol table to an archive lacking one. .Sh OPTIONS The .Nm utility supports the following options: .Bl -tag -width indent .It Fl D Use zeros for the mtime, uid and gid fields, and use mode 0644 for the file mode field for all archive member headers. This ensures that checksums on the resulting archives are reproducible when member contents are identical. .It Fl t This option is accepted, but is ignored. .It Fl V Print a version identifier and exit. .El .Sh EXAMPLES To update the archive symbol table for an archive .Pa lib.a , use: .Dl "ranlib lib.a" .Sh DIAGNOSTICS .Ex -std .Sh SEE ALSO .Xr ar 1 , .Xr ld 1 , .Xr archive 3 , .Xr elf 3 , .Xr ar 5 .Sh HISTORY The .Nm command first appeared in AT&T UNIX Version 7. .Pp In .Fx 8.0 , -.An "Kai Wang" Aq kaiw@FreeBSD.org +.An Kai Wang Aq Mt kaiw@FreeBSD.org reimplemented .Nm using the .Lb libarchive and the .Lb libelf . Index: vendor/elftoolchain/dist/ar/read.c =================================================================== --- vendor/elftoolchain/dist/ar/read.c (revision 282910) +++ vendor/elftoolchain/dist/ar/read.c (revision 282911) @@ -1,199 +1,199 @@ /*- * 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 "ar.h" -ELFTC_VCSID("$Id: read.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: read.c 3180 2015-04-09 15:13:57Z emaste $"); /* * 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_format_ar(a); 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; if ((name = archive_entry_pathname(entry)) == NULL) break; /* 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); /* Disallow absolute paths. */ if (name[0] == '/') { bsdar_warnc(bsdar, 0, "Absolute path '%s'", name); continue; } /* Basic path security flags. */ - flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS | \ + flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_SECURE_NODOTDOT; 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_free(a)); } Index: vendor/elftoolchain/dist/ar/write.c =================================================================== --- vendor/elftoolchain/dist/ar/write.c (revision 282910) +++ vendor/elftoolchain/dist/ar/write.c (revision 282911) @@ -1,975 +1,975 @@ /*- * 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 "ar.h" -ELFTC_VCSID("$Id: write.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: write.c 3183 2015-04-10 16:18:42Z emaste $"); #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 + * option was specified 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_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_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 + * 'ADDLIB' command. If there are members specified 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 + * user, silently 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); 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_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'; } Index: vendor/elftoolchain/dist/brandelf/brandelf.1 =================================================================== --- vendor/elftoolchain/dist/brandelf/brandelf.1 (revision 282910) +++ vendor/elftoolchain/dist/brandelf/brandelf.1 (revision 282911) @@ -1,151 +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 3101 2014-10-27 22:24:40Z jkoshy $ +.\" $Id: brandelf.1 3195 2015-05-12 17:22:19Z emaste $ .\" .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 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 . +.An John-Mark Gurney Aq Mt gurney_j@efn.org . Index: vendor/elftoolchain/dist/common/native-elf-format =================================================================== --- vendor/elftoolchain/dist/common/native-elf-format (revision 282910) +++ vendor/elftoolchain/dist/common/native-elf-format (revision 282911) @@ -1,47 +1,47 @@ #!/bin/sh # -# $Id: native-elf-format 3167 2015-02-24 19:10:08Z emaste $ +# $Id: native-elf-format 3186 2015-04-16 22:16:40Z emaste $ # # Find the native ELF format for a host platform by compiling a # test object and examining the resulting object. # # This script is used if there is no easy way to determine this # information statically at compile time. program=`basename $0` tmp_c=`mktemp -u nefXXXXXX`.c tmp_o=`echo ${tmp_c} | sed -e 's/.c$/.o/'` trap "rm -f ${tmp_c} ${tmp_o}" 0 1 2 3 15 touch ${tmp_c} echo "/* Generated by ${program} on `date` */" cc -c ${tmp_c} -o ${tmp_o} LC_ALL=C readelf -h ${tmp_o} | awk ' $1 ~ "Class:" { sub("ELF","",$2); elfclass = $2; } $1 ~ "Data:" { if (match($0, "little")) { elfdata = "LSB"; } else { elfdata = "MSB"; } } $1 ~ "Machine:" { if (match($0, "Intel.*386")) { elfarch = "EM_386"; - } else if (match($0, ".*X86-64")) { + } else if (match($0, ".*[xX]86-64")) { elfarch = "EM_X86_64"; } else { elfarch = "unknown"; } } END { printf("#define ELFTC_CLASS ELFCLASS%s\n", elfclass); printf("#define ELFTC_ARCH %s\n", elfarch); printf("#define ELFTC_BYTEORDER ELFDATA2%s\n", elfdata); }' Index: vendor/elftoolchain/dist/cxxfilt/c++filt.1 =================================================================== --- vendor/elftoolchain/dist/cxxfilt/c++filt.1 (revision 282910) +++ vendor/elftoolchain/dist/cxxfilt/c++filt.1 (revision 282911) @@ -1,109 +1,109 @@ .\" 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: c++filt.1 2175 2011-11-16 05:51:49Z jkoshy $ +.\" $Id: c++filt.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd August 24, 2011 .Os .Dt C++FILT 1 .Sh NAME .Nm c++filt .Nd decode C++ symbols .Sh SYNOPSIS .Nm .Op Fl -help .Op Fl _ | Fl -strip-underscores .Op Fl n | Fl -no-strip-underscores .Op Fl p | Fl -no-params .Op Fl s Ar scheme | Fl -format Ns = Ns Ar scheme .Op Fl V | Fl -version .Op Ar encoded-names ... .Sh DESCRIPTION The .Nm utility translates encoded C++ symbol names to human-readable form. .Pp The .Nm utility has two operating modes. .Bl -bullet .It If arguments .Ar encoded-names are not specified, then .Nm will act as a filter, reading from standard input and writing to standard output. .It If arguments .Ar encoded-names are specified, then .Nm will decode each such argument in turn, writing its decoded form to standard output. .El .Pp The .Nm utility recognizes the following options: .Bl -tag -width indent .It Fl -help Print a help message and exit. .It Fl _ | Fl -strip-underscores Remove a leading underscore from symbol names prior to decoding them. .It Fl n | Fl -no-strip-underscores Do not remove leading underscores from names. .It Fl p | Fl -no-params This option is recognized but ignored. .It Fl s Ar scheme | Fl -format Ns = Ns Ar scheme Select the encoding scheme to use. Argument .Ar scheme can be one of the following: .Bl -tag -width "gnu-v5" .It Ar arm Use the encoding scheme specified by the C++ Annotated Reference Manual. .It Ar auto Guess the encoding scheme from the input. .It Ar gnu Use the encoding scheme used by the GNU C++ compiler. .It Ar gnu-v3 Use the encoding scheme used by the GNU C++ compiler, version 3. .El .It Fl V | Fl -version Print a version identifier for .Nm and exit. .El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr nm 1 , .Xr strip 1 , .Xr elftc_demangle 3 .Sh AUTHORS The .Nm utility was written by -.An "Kai Wang" Aq kaiwang27@users.sourceforge.net . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: vendor/elftoolchain/dist/elfcopy/elfcopy.1 =================================================================== --- vendor/elftoolchain/dist/elfcopy/elfcopy.1 (revision 282910) +++ vendor/elftoolchain/dist/elfcopy/elfcopy.1 (revision 282911) @@ -1,333 +1,333 @@ .\" Copyright (c) 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 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: elfcopy.1 3173 2015-03-27 16:46:13Z emaste $ +.\" $Id: elfcopy.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd March 27, 2015 .Os .Dt ELFCOPY 1 .Sh NAME .Nm elfcopy .Nd copy and translate object files .Sh SYNOPSIS .Nm .Op Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat .Op Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname .Op Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname .Op Fl N Ar symbolname | Fl -strip-symbol= Ns Ar symbolname .Op Fl O Ar objformat | Fl -output-target= Ns Ar objformat .Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname .Op Fl S | Fl -strip-all .Op Fl V | Fl -version .Op Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname .Op Fl X | Fl -discard-locals .Op Fl d | Fl g | Fl -strip-debug .Op Fl h | Fl -help .Op Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname .Op Fl p | Fl -preserve-dates .Op Fl w | Fl -wildcard .Op Fl x | Fl -discard-all .Op Fl -add-section Ar sectionname Ns = Ns Ar filename .Oo .Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val | .Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val .Oc .Oo .Fl -adjust-start Ns = Ns Ar increment | .Fl -change-start Ns = Ns Ar increment .Oc .Oo .Fl -adjust-vma Ns = Ns Ar increment | .Fl -change-addresses Ns = Ns Ar increment .Oc .Op Fl -adjust-warnings | Fl -change-warnings .Op Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val .Op Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val .Op Fl -extract-dwo .Op Fl -gap-fill Ns = Ns Ar val .Op Fl -localize-hidden .Op Fl -no-adjust-warnings | Fl -no-change-warnings .Op Fl -only-keep-debug .Op Fl -pad-to Ns = Ns Ar address .Op Fl -prefix-alloc-sections Ns = Ns Ar string .Op Fl -prefix-sections Ns = Ns Ar string .Op Fl -prefix-symbols Ns = Ns Ar string .Op Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags .Op Fl -set-section-flags Ar sectionname Ns = Ns Ar flags .Op Fl -set-start Ns = Ns Ar address .Op Fl -srec-forceS3 .Op Fl -srec-len Ns = Ns Ar val .Op Fl -strip-dwo .Op Fl -strip-unneeded .Ar infile .Op Ar outfile .Sh DESCRIPTION The .Nm utility copies the content of the ELF object named by argument .Ar infile to that named by argument .Ar outfile , transforming it according to the command line options specified. If argument .Ar outfile is not specified, .Nm will create a temporary file and will subsequently rename it as .Ar infile . .Pp The .Nm utility supports the following options: .Bl -tag -width indent .It Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat Specify that the input file named by the argument .Ar infile is in the object format specified by the argument .Ar objformat . .It Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname Copy the symbol named by argument .Ar symbolname to the output. .It Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname Make the symbol named by argument .Ar symbolname local to the output file. .It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbolname Do not copy the symbol named by argument .Ar symbolname to the output. .It Fl O Ar objformat | Fl -output-target= Ns Ar objformat Write the output file using the object format specified in argument .Ar objformat . .It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname Remove any section with name .Ar sectionname from the output file. .It Fl S | Fl -strip-all Do not copy symbol and relocation information to the target file. .It Fl V | Fl -version Print a version identifier and exit. .It Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname Mark the symbol named by argument .Ar symbolname as weak in the output. .It Fl X | Fl -discard-locals Do not copy compiler generated local symbols to the output. .It Fl d | Fl g | Fl -strip-debug Do not copy debugging information to the target file. .It Fl h | Fl -help Display a help message and exit. .It Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname Copy only the section named by argument .Ar sectionname to the output. .It Fl p | Fl -preserve-dates Set the access and modification times of the output file to the same as those of the input. .It Fl w | Fl -wildcard Use shell-style patterns to name symbols. The following meta-characters are recognized in patterns: .Bl -tag -width "...." -compact .It Li ! If this is the first character of the pattern, invert the sense of the pattern match. .It Li * Matches any string of characters in a symbol name. .It Li ? Matches zero or one character in a symbol name. .It Li [ Mark the start of a character class. .It Li \e Remove the special meaning of the next character in the pattern. .It Li ] Mark the end of a character class. .El .It Fl x | Fl -discard-all Do not copy non-global symbols to the output. .It Fl -add-section Ar sectionname Ns = Ns Ar filename Add a new section to the output file with name .Ar sectionname . The contents of the section are taken from the file named by argument .Ar filename . The size of the section will be the number of bytes in file .Ar filename . .It Xo .Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val | .Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val .Xc Depending on the operator specified, increase, decrease or set both the virtual memory address and the load memory address of the section named by the argument .Ar section . The argument .Ar val specifies the desired increment, decrement or new value for the address. .It Xo .Fl -adjust-start Ns = Ns Ar increment | .Fl -change-start Ns = Ns Ar increment .Xc Increase the entry point address of the output ELF object by the value specified in the argument .Ar increment . .It Xo .Fl -adjust-vma Ns = Ns Ar increment | .Fl -change-addresses Ns = Ns Ar increment .Xc Increase the virtual memory address and the load memory address of all sections by the value specified by the argument .Ar increment . .It Fl -adjust-warnings | Fl -change-warnings Issue a warning if the section specified by the options .Fl -change-section-address , .Fl -change-section-lma or .Fl -change-section-vma does not exist in the input object. This is the default. .It Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val Change or set the load memory address of the section named by the argument .Ar section . Depending on the operator specified, the value in argument .Ar val will be used as an increment, a decrement or as the new value of the load memory address. .It Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val Change or set the virtual memory address of the section named by the argument .Ar section . Depending on the operator specified, the value in argument .Ar val will be used as an increment, a decrement or as the new value of the virtual memory address. .It Fl -extract-dwo Copy only .dwo debug sections to the output file. .It Fl -gap-fill Ns = Ns Ar val Fill the gaps between sections with the byte value specified by the argument .Ar val . .It Fl -localize-hidden Make all hidden symbols local to the output file. This includes symbols with internal visiblity. .It Fl -no-adjust-warnings | Fl -no-change-warnings Do not issue a warning if the section specified by the options .Fl -change-section-address , .Fl -change-section-lma or .Fl -change-section-vma is missing in the input object. .It Fl -only-keep-debug Copy only debugging information to the output file. .It Fl -pad-to Ns = Ns Ar address Pad the load memory address of the output object to the value specified by the argument .Ar address by increasing the size of the section with the highest load memory address. .It Fl -prefix-alloc-sections Ns = Ns Ar string Prefix the section names of all the allocated sections with .Ar string . .It Fl -prefix-sections Ns = Ns Ar string Prefix the section names of all the sections with .Ar string . .It Fl -prefix-symbols Ns = Ns Ar string Prefix the symbol names of all the symbols with .Ar string . .It Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags Rename the section named by argument .Ar oldname to .Ar newname , optionally changing the sections flags to that specified by argument .Ar flags . Allowed values for the argument .Ar flags are as for option .Fl -set-section-flags below. .It Fl -set-section-flags Ar sectionname Ns = Ns Ar flags Set the flags for the section named by argument .Ar sectionname to those specified by argument .Ar flags . Argument .Ar flags is a comma separated list of the following flag names: .Bl -tag -width "readonly" -compact .It alloc The section occupies space in the output file. .It code The section contains machine instructions. .It contents This flag is accepted but is ignored. .It data The section contains writeable data. .It debug The section holds debugging information. .It load The section is loadable. .It noload The section should not be loaded into memory. .It readonly The section is not writable. .It rom The section contains ROM'able contents. .It share This flag is accepted but is ignored. .El .It Fl -set-start Ns = Ns Ar address Set the start address of the output ELF object to the value specified by the argument .Ar address . .It Fl -srec-forceS3 Only generate S-records of type .Dq S3 . This option is only meaningful when the output target is set to .Dq srec . .It Fl -srec-len Ns = Ns Ar val Set the maximum length of an S-record line to .Ar val . This option is only meaningful when the output target is set to .Dq srec . .It Fl -strip-dwo Do not copy .dwo debug sections to the output file. .It Fl -strip-unneeded Do not copy symbols that are not needed for relocation processing. .El .Sh DIAGNOSTICS .Ex -std .Sh SEE ALSO .Xr ar 1 , .Xr ld 1 , .Xr mcs 1 , .Xr strip 1 , .Xr elf 3 , .Xr ar 5 , .Xr elf 5 .Sh HISTORY .Nm has been implemented by -.An "Kai Wang" Aq kaiwang27@users.sourceforge.net . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: vendor/elftoolchain/dist/elfcopy/sections.c =================================================================== --- vendor/elftoolchain/dist/elfcopy/sections.c (revision 282910) +++ vendor/elftoolchain/dist/elfcopy/sections.c (revision 282911) @@ -1,1565 +1,1573 @@ /*- * Copyright (c) 2007-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 #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: sections.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: sections.c 3185 2015-04-11 08:56:34Z 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_dwo_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 (ecp->strip == STRIP_DWO && is_dwo_section(name)) return (1); if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name)) return (1); 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_dwo_section(const char *name) { size_t len; if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 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 for section * resync later. */ 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; } /* * Ignore TLS sections with load address 0 and without * content. We don't need to adjust their file offset or * VMA, only the size matters. */ if (s->seg_tls != NULL && s->type == SHT_NOBITS && s->off == 0) continue; /* Align section offset. */ if (s->align == 0) s->align = 1; if (off <= s->off) { if (!s->loadable) s->off = roundup(off, s->align); } else { if (s->loadable) 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; } /* * Alignment Fixup. libelf does not allow the alignment for * Elf_Data descriptor to be set to 0. In this case we workaround * it by setting the alignment to 1. * * According to the ELF ABI, alignment 0 and 1 has the same * meaning: the section has no alignment constraints. */ if (od->d_align == 0) od->d_align = 1; } 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; 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]; + + /* + * sh_info of SHT_GROUP section needs to point to the correct + * string in the symbol table. + */ + if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) && + (ecp->flags & SYMTAB_INTACT) == 0) + osh.sh_info = ecp->symndx[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); } Index: vendor/elftoolchain/dist/elfcopy/segments.c =================================================================== --- vendor/elftoolchain/dist/elfcopy/segments.c (revision 282910) +++ vendor/elftoolchain/dist/elfcopy/segments.c (revision 282911) @@ -1,495 +1,495 @@ /*- * 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 3177 2015-03-30 18:19:41Z emaste $"); +ELFTC_VCSID("$Id: segments.c 3196 2015-05-12 17:33:48Z emaste $"); 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 || (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; else if (seg->type == PT_TLS) s->seg_tls = 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, 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) { /* 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->vma + s->sz - seg->addr; if (s->type != SHT_NOBITS) - seg->fsz = seg->msz; + seg->fsz = s->off + s->sz - seg->off; } } /* * 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++; } } Index: vendor/elftoolchain/dist/elfcopy/symbols.c =================================================================== --- vendor/elftoolchain/dist/elfcopy/symbols.c (revision 282910) +++ vendor/elftoolchain/dist/elfcopy/symbols.c (revision 282911) @@ -1,1097 +1,1097 @@ /*- * 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 "elfcopy.h" -ELFTC_VCSID("$Id: symbols.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: symbols.c 3191 2015-05-04 17:07:01Z 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. */ }; struct sthash { LIST_ENTRY(sthash) sh_next; size_t sh_off; }; typedef LIST_HEAD(,sthash) hash_head; #define STHASHSIZE 65536 struct strimpl { char *buf; /* string table */ size_t sz; /* entries */ size_t cap; /* buffer capacity */ hash_head hash[STHASHSIZE]; }; /* String table buffer structure. */ struct strbuf { struct strimpl l; /* local symbols */ struct strimpl g; /* global symbols */ }; 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(hash_head *hash, const char *buf, 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); uint32_t str_hash(const char *s); /* 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_hidden_symbol(unsigned char st_other) { if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN || GELF_ST_VISIBILITY(st_other) == STV_INTERNAL) 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, 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->g.cap = 256; st_buf->l.cap = 64; st_buf->l.sz = 1; /* '\0' at start. */ st_buf->g.sz = 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)); if (ecp->flags & LOCALIZE_HIDDEN && sym.st_shndx != SHN_UNDEF && is_hidden_symbol(sym.st_other)) 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->l.sz; else sy_buf->g64[ecp->symndx[i]].st_name += st_buf->l.sz; /* 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; struct sthash *sh, *shtmp; int i; 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.buf != NULL) free(st_buf->l.buf); if (st_buf->g.buf != NULL) free(st_buf->g.buf); for (i = 0; i < STHASHSIZE; i++) { LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next, shtmp) { LIST_REMOVE(sh, sh_next); free(sh); } LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next, shtmp) { LIST_REMOVE(sh, sh_next); free(sh); } } } } 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->g.cap = 256; st_buf->l.cap = 64; st_buf->l.sz = 1; /* '\0' at start. */ st_buf->g.sz = 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; struct sthash *sh; uint32_t hash; 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.buf == NULL) { \ st_buf->B.buf = calloc(st_buf->B.cap, \ sizeof(*st_buf->B.buf)); \ if (st_buf->B.buf == NULL) \ err(EXIT_FAILURE, "malloc failed"); \ } \ if (name != NULL && *name != '\0') { \ pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\ 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.buf = realloc(st_buf->B.buf, \ st_buf->B.cap); \ if (st_buf->B.buf == NULL) \ err(EXIT_FAILURE, \ "realloc failed"); \ } \ if ((sh = malloc(sizeof(*sh))) == NULL) \ err(EXIT_FAILURE, "malloc failed"); \ sh->sh_off = st_buf->B.sz; \ hash = str_hash(name); \ LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh, \ sh_next); \ strncpy(&st_buf->B.buf[st_buf->B.sz], name, \ strlen(name)); \ st_buf->B.buf[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->l.sz + st_buf->g.sz; #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->l.sz; else sy_buf->g64[i].st_name += st_buf->l.sz; } } 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.buf; lstdata->d_size = st_buf->l.sz; lstdata->d_type = ELF_T_BYTE; lstdata->d_version = EV_CURRENT; if (st_buf->g.sz > 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.buf; gstdata->d_size = st_buf->g.sz; 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; 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(hash_head *buckets, const char *buf, const char *s) { struct sthash *sh; uint32_t hash; hash = str_hash(s); LIST_FOREACH(sh, &buckets[hash], sh_next) if (strcmp(buf + sh->sh_off, s) == 0) return sh->sh_off; return (-1); } uint32_t str_hash(const char *s) { uint32_t hash; - for (hash = 2166136261; *s; s++) + for (hash = 2166136261UL; *s; s++) hash = (hash ^ *s) * 16777619; return (hash & (STHASHSIZE - 1)); } Index: vendor/elftoolchain/dist/elfdump/elfdump.1 =================================================================== --- vendor/elftoolchain/dist/elfdump/elfdump.1 (revision 282910) +++ vendor/elftoolchain/dist/elfdump/elfdump.1 (revision 282911) @@ -1,158 +1,158 @@ .\" Copyright (c) 2003 David O'Brien .\" 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. .\" .\" $FreeBSD: src/usr.bin/elfdump/elfdump.1,v 1.6 2005/01/18 13:43:48 ru Exp $ -.\" $Id: elfdump.1 2069 2011-10-26 15:53:48Z jkoshy $ +.\" $Id: elfdump.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd August 25, 2011 .Dt ELFDUMP 1 .Os .Sh NAME .Nm elfdump .Nd "display information about" .Tn ELF files .Sh SYNOPSIS .Nm .Fl a | cdeGhiknprsv .Op Fl S .Op Fl V .Op Fl N Ar name .Op Fl w Ar file .Ar file ... .Sh DESCRIPTION The .Nm utility dumps various information about the specified .Tn ELF .Ar file . .Pp The options are as follows: .Bl -tag -width ".Fl w Ar file" .It Fl a Dump all information. .It Fl c Dump shared headers. .It Fl d Dump dynamic symbols. .It Fl e Dump ELF header. .It Fl G Dump the GOT. .It Fl h Dump the hash values. .It Fl i Dump the dynamic interpreter. .It Fl k Dump the ELF checksum. .It Fl n Dump note sections. .It Fl N Ar name Only dump the section with the specific .Ar name . Archive symbol table can be specified with the special section name ARSYM. More than one .Fl N option may appear. .It Fl p Dump the program header. .It Fl r Dump relocations. .It Fl s Dump the symbol table. .It Fl S Output in the Solaris .Nm format. .It Fl v Dump the symbol-versioning sections. .It Fl V Print a version identifier and exit. .It Fl w Ar file Write output to a .Ar file instead of the standard output. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES The following is an example of a typical usage of the .Nm command: .Pp .Dl "elfdump -a -w output /bin/ls" .Pp To dump the content of '.dynsym' symbol table: .Pp .Dl "elfdump -s -N .dynsym /bin/ls" .Pp To dump the archive symbol table, but not the symbol tables of archive members: .Pp .Dl "elfdump -s -N ARSYM /usr/lib/libelf.a" .Pp To dump the content of .got section and the symbol-versioning sections in Solaris .Nm format: .Pp .Dl "elfdump -S -Gv /bin/ls" .Sh SEE ALSO .Xr objdump 1 , .Xr readelf 1 , .Xr elf 3 .Rs .%A "AT&T Unix Systems Labs" .%T "System V Application Binary Interface" .%O http://www.sco.com/developers/gabi/ .Re .Sh HISTORY The .Nm utility first appeared in .Fx 5.0 . .Sh AUTHORS .An -nosplit The .Nm utility was written by -.An Jake Burkholder Aq jake@FreeBSD.org . +.An Jake Burkholder Aq Mt jake@FreeBSD.org . Later it was rewritten based on the libelf library. This manual page was written by -.An David O'Brien Aq obrien@FreeBSD.org . +.An David O'Brien Aq Mt obrien@FreeBSD.org . .Pp -.An Kai Wang Aq kaiw@FreeBSD.org +.An Kai Wang Aq Mt kaiw@FreeBSD.org rewrote it using the .Lb libelf and implemented additional functionality. .Sh BUGS Does not fully implement the .Tn ELF gABI. Index: vendor/elftoolchain/dist/elfdump/elfdump.c =================================================================== --- vendor/elftoolchain/dist/elfdump/elfdump.c (revision 282910) +++ vendor/elftoolchain/dist/elfdump/elfdump.c (revision 282911) @@ -1,2818 +1,2817 @@ /*- * Copyright (c) 2007-2012 Kai Wang * Copyright (c) 2003 David O'Brien. All rights reserved. * Copyright (c) 2001 Jake Burkholder * 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 #ifdef USE_LIBARCHIVE_AR #include #include #endif #include "_elftc.h" -ELFTC_VCSID("$Id: elfdump.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: elfdump.c 3189 2015-04-20 17:02:01Z emaste $"); #if defined(ELFTC_NEED_ELF_NOTE_DEFINITION) #include "native-elf-format.h" #if ELFTC_CLASS == ELFCLASS32 typedef Elf32_Nhdr Elf_Note; #else typedef Elf64_Nhdr Elf_Note; #endif #endif /* elfdump(1) options. */ #define ED_DYN (1<<0) #define ED_EHDR (1<<1) #define ED_GOT (1<<2) #define ED_HASH (1<<3) #define ED_INTERP (1<<4) #define ED_NOTE (1<<5) #define ED_PHDR (1<<6) #define ED_REL (1<<7) #define ED_SHDR (1<<8) #define ED_SYMTAB (1<<9) #define ED_SYMVER (1<<10) #define ED_CHECKSUM (1<<11) #define ED_ALL ((1<<12)-1) /* elfdump(1) run control flags. */ #define SOLARIS_FMT (1<<0) #define PRINT_FILENAME (1<<1) #define PRINT_ARSYM (1<<2) #define ONLY_ARSYM (1<<3) /* Convenient print macro. */ #define PRT(...) fprintf(ed->out, __VA_ARGS__) /* 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 spec_name { const char *name; STAILQ_ENTRY(spec_name) sn_list; }; /* Structure encapsulates the global data for readelf(1). */ struct elfdump { FILE *out; /* output redirection. */ const char *filename; /* current processing file. */ const char *archive; /* archive name */ int options; /* command line options. */ int flags; /* run control flags. */ Elf *elf; /* underlying ELF descriptor. */ #ifndef USE_LIBARCHIVE_AR Elf *ar; /* ar(1) archive descriptor. */ #endif GElf_Ehdr ehdr; /* ELF header. */ int ec; /* ELF class. */ size_t shnum; /* #sections. */ struct section *sl; /* list of sections. */ STAILQ_HEAD(, spec_name) snl; /* list of names specified by -N. */ }; /* Relocation entry. */ struct rel_entry { union { GElf_Rel rel; GElf_Rela rela; } u_r; const char *symn; uint32_t type; }; #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]); } #endif /* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */ static const char * d_tags(uint64_t tag) { switch (tag) { case 0: return "DT_NULL"; case 1: return "DT_NEEDED"; case 2: return "DT_PLTRELSZ"; case 3: return "DT_PLTGOT"; case 4: return "DT_HASH"; case 5: return "DT_STRTAB"; case 6: return "DT_SYMTAB"; case 7: return "DT_RELA"; case 8: return "DT_RELASZ"; case 9: return "DT_RELAENT"; case 10: return "DT_STRSZ"; case 11: return "DT_SYMENT"; case 12: return "DT_INIT"; case 13: return "DT_FINI"; case 14: return "DT_SONAME"; case 15: return "DT_RPATH"; case 16: return "DT_SYMBOLIC"; case 17: return "DT_REL"; case 18: return "DT_RELSZ"; case 19: return "DT_RELENT"; case 20: return "DT_PLTREL"; case 21: return "DT_DEBUG"; case 22: return "DT_TEXTREL"; case 23: return "DT_JMPREL"; case 24: return "DT_BIND_NOW"; case 25: return "DT_INIT_ARRAY"; case 26: return "DT_FINI_ARRAY"; case 27: return "DT_INIT_ARRAYSZ"; case 28: return "DT_FINI_ARRAYSZ"; case 29: return "DT_RUNPATH"; case 30: return "DT_FLAGS"; case 32: return "DT_PREINIT_ARRAY"; /* XXX: DT_ENCODING */ case 33: return "DT_PREINIT_ARRAYSZ"; /* 0x6000000D - 0x6ffff000 operating system-specific semantics */ case 0x6ffffdf5: return "DT_GNU_PRELINKED"; case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ"; case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ"; case 0x6ffffdf8: return "DT_SUNW_CHECKSUM"; case 0x6ffffdf9: return "DT_PLTPADSZ"; case 0x6ffffdfa: return "DT_MOVEENT"; case 0x6ffffdfb: return "DT_MOVESZ"; case 0x6ffffdfc: return "DT_FEATURE"; case 0x6ffffdfd: return "DT_POSFLAG_1"; case 0x6ffffdfe: return "DT_SYMINSZ"; case 0x6ffffdff: return "DT_SYMINENT (DT_VALRNGHI)"; case 0x6ffffe00: return "DT_ADDRRNGLO"; case 0x6ffffef5: return "DT_GNU_HASH"; case 0x6ffffef8: return "DT_GNU_CONFLICT"; case 0x6ffffef9: return "DT_GNU_LIBLIST"; case 0x6ffffefa: return "DT_SUNW_CONFIG"; case 0x6ffffefb: return "DT_SUNW_DEPAUDIT"; case 0x6ffffefc: return "DT_SUNW_AUDIT"; case 0x6ffffefd: return "DT_SUNW_PLTPAD"; case 0x6ffffefe: return "DT_SUNW_MOVETAB"; case 0x6ffffeff: return "DT_SYMINFO (DT_ADDRRNGHI)"; case 0x6ffffff9: return "DT_RELACOUNT"; case 0x6ffffffa: return "DT_RELCOUNT"; case 0x6ffffffb: return "DT_FLAGS_1"; case 0x6ffffffc: return "DT_VERDEF"; case 0x6ffffffd: return "DT_VERDEFNUM"; case 0x6ffffffe: return "DT_VERNEED"; case 0x6fffffff: return "DT_VERNEEDNUM"; case 0x6ffffff0: return "DT_GNU_VERSYM"; /* 0x70000000 - 0x7fffffff processor-specific semantics */ case 0x70000000: return "DT_IA_64_PLT_RESERVE"; case 0x7ffffffd: return "DT_SUNW_AUXILIARY"; case 0x7ffffffe: return "DT_SUNW_USED"; case 0x7fffffff: return "DT_SUNW_FILTER"; default: return "ERROR: TAG NOT DEFINED"; } } static const char * e_machines(unsigned int mach) { static char machdesc[64]; switch (mach) { case EM_NONE: return "EM_NONE"; case EM_M32: return "EM_M32"; case EM_SPARC: return "EM_SPARC"; case EM_386: return "EM_386"; case EM_68K: return "EM_68K"; case EM_88K: return "EM_88K"; case EM_860: return "EM_860"; case EM_MIPS: return "EM_MIPS"; case EM_PPC: return "EM_PPC"; case EM_ARM: return "EM_ARM"; case EM_ALPHA: return "EM_ALPHA (legacy)"; case EM_SPARCV9:return "EM_SPARCV9"; case EM_IA_64: return "EM_IA_64"; case EM_X86_64: return "EM_X86_64"; } snprintf(machdesc, sizeof(machdesc), "(unknown machine) -- type 0x%x", mach); return (machdesc); } static const char *e_types[] = { "ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE" }; static const char *ei_versions[] = { "EV_NONE", "EV_CURRENT" }; static const char *ei_classes[] = { "ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64" }; static const char *ei_data[] = { "ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB" }; static const char *ei_abis[] = { "ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_MONTEREY", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD" }; static const char *p_types[] = { "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE", "PT_SHLIB", "PT_PHDR", "PT_TLS" }; static const char *p_flags[] = { "", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R", "PF_X|PF_W|PF_R" }; static const char * sh_name(struct elfdump *ed, int ndx) { static char num[10]; switch (ndx) { case SHN_UNDEF: return "UNDEF"; case SHN_ABS: return "ABS"; case SHN_COMMON: return "COMMON"; default: if ((uint64_t)ndx < ed->shnum) return (ed->sl[ndx].name); else { snprintf(num, sizeof(num), "%d", ndx); return (num); } } } /* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */ static const char * sh_types(u_int64_t sht) { switch (sht) { case 0: return "SHT_NULL"; case 1: return "SHT_PROGBITS"; case 2: return "SHT_SYMTAB"; case 3: return "SHT_STRTAB"; case 4: return "SHT_RELA"; case 5: return "SHT_HASH"; case 6: return "SHT_DYNAMIC"; case 7: return "SHT_NOTE"; case 8: return "SHT_NOBITS"; case 9: return "SHT_REL"; case 10: return "SHT_SHLIB"; case 11: return "SHT_DYNSYM"; case 14: return "SHT_INIT_ARRAY"; case 15: return "SHT_FINI_ARRAY"; case 16: return "SHT_PREINIT_ARRAY"; case 17: return "SHT_GROUP"; case 18: return "SHT_SYMTAB_SHNDX"; /* 0x60000000 - 0x6fffffff operating system-specific semantics */ case 0x6ffffff0: return "XXX:VERSYM"; case 0x6ffffff6: return "SHT_GNU_HASH"; case 0x6ffffff7: return "SHT_GNU_LIBLIST"; case 0x6ffffffc: return "XXX:VERDEF"; case 0x6ffffffd: return "SHT_SUNW(GNU)_verdef"; case 0x6ffffffe: return "SHT_SUNW(GNU)_verneed"; case 0x6fffffff: return "SHT_SUNW(GNU)_versym"; /* 0x70000000 - 0x7fffffff processor-specific semantics */ case 0x70000000: return "SHT_IA_64_EXT"; case 0x70000001: return "SHT_IA_64_UNWIND"; case 0x7ffffffd: return "XXX:AUXILIARY"; case 0x7fffffff: return "XXX:FILTER"; /* 0x80000000 - 0xffffffff application programs */ default: return "ERROR: SHT NOT DEFINED"; } } /* * Define known section flags. These flags are defined in the order * they are to be printed out. */ #define DEFINE_SHFLAGS() \ DEFINE_SHF(WRITE) \ DEFINE_SHF(ALLOC) \ DEFINE_SHF(EXECINSTR) \ DEFINE_SHF(MERGE) \ DEFINE_SHF(STRINGS) \ DEFINE_SHF(INFO_LINK) \ DEFINE_SHF(LINK_ORDER) \ DEFINE_SHF(OS_NONCONFORMING) \ DEFINE_SHF(GROUP) \ DEFINE_SHF(TLS) #undef DEFINE_SHF #define DEFINE_SHF(F) "SHF_" #F "|" #define ALLSHFLAGS DEFINE_SHFLAGS() static const char * sh_flags(uint64_t shf) { static char flg[sizeof(ALLSHFLAGS)+1]; flg[0] = '\0'; #undef DEFINE_SHF #define DEFINE_SHF(N) \ if (shf & SHF_##N) \ strcat(flg, "SHF_" #N "|"); \ DEFINE_SHFLAGS() flg[strlen(flg) - 1] = '\0'; /* Remove the trailing "|". */ return (flg); } static const char *st_types[] = { "STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE", "STT_COMMON", "STT_TLS" }; static const char *st_types_S[] = { "NOTY", "OBJT", "FUNC", "SECT", "FILE" }; static const char *st_bindings[] = { "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" }; static const char *st_bindings_S[] = { "LOCL", "GLOB", "WEAK" }; static unsigned char st_others[] = { 'D', 'I', 'H', 'P' }; 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_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 void add_name(struct elfdump *ed, const char *name); static void elf_print_object(struct elfdump *ed); static void elf_print_elf(struct elfdump *ed); static void elf_print_ehdr(struct elfdump *ed); static void elf_print_phdr(struct elfdump *ed); static void elf_print_shdr(struct elfdump *ed); static void elf_print_symtab(struct elfdump *ed, int i); static void elf_print_symtabs(struct elfdump *ed); static void elf_print_symver(struct elfdump *ed); static void elf_print_verdef(struct elfdump *ed, struct section *s); static void elf_print_verneed(struct elfdump *ed, struct section *s); static void elf_print_interp(struct elfdump *ed); static void elf_print_dynamic(struct elfdump *ed); static void elf_print_rel_entry(struct elfdump *ed, struct section *s, int j, struct rel_entry *r); static void elf_print_rela(struct elfdump *ed, struct section *s, Elf_Data *data); static void elf_print_rel(struct elfdump *ed, struct section *s, Elf_Data *data); static void elf_print_reloc(struct elfdump *ed); static void elf_print_got(struct elfdump *ed); static void elf_print_got_section(struct elfdump *ed, struct section *s); static void elf_print_note(struct elfdump *ed); static void elf_print_svr4_hash(struct elfdump *ed, struct section *s); static void elf_print_svr4_hash64(struct elfdump *ed, struct section *s); static void elf_print_gnu_hash(struct elfdump *ed, struct section *s); static void elf_print_hash(struct elfdump *ed); static void elf_print_checksum(struct elfdump *ed); static void find_gotrel(struct elfdump *ed, struct section *gs, struct rel_entry *got); static struct spec_name *find_name(struct elfdump *ed, const char *name); static const char *get_symbol_name(struct elfdump *ed, int symtab, int i); static const char *get_string(struct elfdump *ed, int strtab, size_t off); static void get_versym(struct elfdump *ed, int i, uint16_t **vs, int *nvs); static void load_sections(struct elfdump *ed); static void unload_sections(struct elfdump *ed); static void usage(void); #ifdef USE_LIBARCHIVE_AR static int ac_detect_ar(int fd); static void ac_print_ar(struct elfdump *ed, int fd); #else static void elf_print_ar(struct elfdump *ed, int fd); #endif /* USE_LIBARCHIVE_AR */ static struct option elfdump_longopts[] = { { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; int main(int ac, char **av) { struct elfdump *ed, ed_storage; struct spec_name *sn; int ch, i; ed = &ed_storage; memset(ed, 0, sizeof(*ed)); STAILQ_INIT(&ed->snl); ed->out = stdout; while ((ch = getopt_long(ac, av, "acdeiGHhknN:prsSvVw:", elfdump_longopts, NULL)) != -1) switch (ch) { case 'a': ed->options = ED_ALL; break; case 'c': ed->options |= ED_SHDR; break; case 'd': ed->options |= ED_DYN; break; case 'e': ed->options |= ED_EHDR; break; case 'i': ed->options |= ED_INTERP; break; case 'G': ed->options |= ED_GOT; break; case 'h': ed->options |= ED_HASH; break; case 'k': ed->options |= ED_CHECKSUM; break; case 'n': ed->options |= ED_NOTE; break; case 'N': add_name(ed, optarg); break; case 'p': ed->options |= ED_PHDR; break; case 'r': ed->options |= ED_REL; break; case 's': ed->options |= ED_SYMTAB; break; case 'S': ed->flags |= SOLARIS_FMT; break; case 'v': ed->options |= ED_SYMVER; break; case 'V': (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); break; case 'w': if ((ed->out = fopen(optarg, "w")) == NULL) err(EXIT_FAILURE, "%s", optarg); break; case '?': case 'H': default: usage(); } ac -= optind; av += optind; if (ed->options == 0) ed->options = ED_ALL; sn = NULL; if (ed->options & ED_SYMTAB && (STAILQ_EMPTY(&ed->snl) || (sn = find_name(ed, "ARSYM")) != NULL)) { ed->flags |= PRINT_ARSYM; if (sn != NULL) { STAILQ_REMOVE(&ed->snl, sn, spec_name, sn_list); if (STAILQ_EMPTY(&ed->snl)) ed->flags |= ONLY_ARSYM; } } if (ac == 0) usage(); if (ac > 1) ed->flags |= PRINT_FILENAME; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); - for (i = 0; i < ac; i++) - if (av[i] != NULL) { - ed->filename = av[i]; - ed->archive = NULL; - elf_print_object(ed); - } + for (i = 0; i < ac; i++) { + ed->filename = av[i]; + ed->archive = NULL; + elf_print_object(ed); + } exit(EXIT_SUCCESS); } #ifdef USE_LIBARCHIVE_AR /* Archive symbol table entry. */ struct arsym_entry { char *sym_name; size_t off; }; /* * Convenient wrapper for general libarchive error handling. */ #define AC(CALL) do { \ if ((CALL)) { \ warnx("%s", archive_error_string(a)); \ return; \ } \ } while (0) /* * Detect an ar(1) archive using libarchive(3). */ static int ac_detect_ar(int fd) { struct archive *a; struct archive_entry *entry; int r; r = -1; if ((a = archive_read_new()) == NULL) return (0); archive_read_support_format_ar(a); if (archive_read_open_fd(a, fd, 10240) == ARCHIVE_OK) r = archive_read_next_header(a, &entry); archive_read_close(a); archive_read_free(a); return (r == ARCHIVE_OK); } /* * Dump an ar(1) archive using libarchive(3). */ static void ac_print_ar(struct elfdump *ed, int fd) { struct archive *a; struct archive_entry *entry; struct arsym_entry *arsym; const char *name; char idx[10], *b; void *buff; size_t size; uint32_t cnt; int i, r; if (lseek(fd, 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_format_ar(a); AC(archive_read_open_fd(a, fd, 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); size = archive_entry_size(entry); if (size == 0) continue; if ((buff = malloc(size)) == NULL) { warn("malloc failed"); continue; } if (archive_read_data(a, buff, size) != (ssize_t)size) { warnx("%s", archive_error_string(a)); free(buff); continue; } /* * Note that when processing arsym via libarchive, there is * no way to tell which member a certain symbol belongs to, * since we can not just "lseek" to a member offset and read * the member header. */ if (!strcmp(name, "/") && ed->flags & PRINT_ARSYM) { b = buff; cnt = be32dec(b); if (cnt == 0) { free(buff); continue; } arsym = calloc(cnt, sizeof(*arsym)); if (arsym == NULL) err(EXIT_FAILURE, "calloc failed"); b += sizeof(uint32_t); for (i = 0; (size_t)i < cnt; i++) { arsym[i].off = be32dec(b); b += sizeof(uint32_t); } for (i = 0; (size_t)i < cnt; i++) { arsym[i].sym_name = b; b += strlen(b) + 1; } if (ed->flags & SOLARIS_FMT) { PRT("\nSymbol Table: (archive)\n"); PRT(" index offset symbol\n"); } else PRT("\nsymbol table (archive):\n"); for (i = 0; (size_t)i < cnt; i++) { if (ed->flags & SOLARIS_FMT) { snprintf(idx, sizeof(idx), "[%d]", i); PRT("%10s ", idx); PRT("0x%8.8jx ", (uintmax_t)arsym[i].off); PRT("%s\n", arsym[i].sym_name); } else { PRT("\nentry: %d\n", i); PRT("\toffset: %#jx\n", (uintmax_t)arsym[i].off); PRT("\tsymbol: %s\n", arsym[i].sym_name); } } free(arsym); free(buff); /* No need to continue if we only dump ARSYM. */ if (ed->flags & ONLY_ARSYM) { AC(archive_read_close(a)); AC(archive_read_free(a)); return; } continue; } if ((ed->elf = elf_memory(buff, size)) == NULL) { warnx("elf_memroy() failed: %s", elf_errmsg(-1)); free(buff); continue; } /* Skip non-ELF member. */ if (elf_kind(ed->elf) == ELF_K_ELF) { printf("\n%s(%s):\n", ed->archive, name); elf_print_elf(ed); } elf_end(ed->elf); free(buff); } AC(archive_read_close(a)); AC(archive_read_free(a)); } #else /* USE_LIBARCHIVE_AR */ /* * Dump an ar(1) archive. */ static void elf_print_ar(struct elfdump *ed, int fd) { Elf *e; Elf_Arhdr *arh; Elf_Arsym *arsym; Elf_Cmd cmd; char idx[10]; size_t cnt; int i; ed->ar = ed->elf; if (ed->flags & PRINT_ARSYM) { cnt = 0; if ((arsym = elf_getarsym(ed->ar, &cnt)) == NULL) { warnx("elf_getarsym failed: %s", elf_errmsg(-1)); goto print_members; } if (cnt == 0) goto print_members; if (ed->flags & SOLARIS_FMT) { PRT("\nSymbol Table: (archive)\n"); PRT(" index offset member name and symbol\n"); } else PRT("\nsymbol table (archive):\n"); for (i = 0; (size_t)i < cnt - 1; i++) { if (elf_rand(ed->ar, arsym[i].as_off) != arsym[i].as_off) { warnx("elf_rand failed: %s", elf_errmsg(-1)); break; } if ((e = elf_begin(fd, ELF_C_READ, ed->ar)) == NULL) { warnx("elf_begin failed: %s", elf_errmsg(-1)); break; } if ((arh = elf_getarhdr(e)) == NULL) { warnx("elf_getarhdr failed: %s", elf_errmsg(-1)); break; } if (ed->flags & SOLARIS_FMT) { snprintf(idx, sizeof(idx), "[%d]", i); PRT("%10s ", idx); PRT("0x%8.8jx ", (uintmax_t)arsym[i].as_off); PRT("(%s):%s\n", arh->ar_name, arsym[i].as_name); } else { PRT("\nentry: %d\n", i); PRT("\toffset: %#jx\n", (uintmax_t)arsym[i].as_off); PRT("\tmember: %s\n", arh->ar_name); PRT("\tsymbol: %s\n", arsym[i].as_name); } elf_end(e); } /* No need to continue if we only dump ARSYM. */ if (ed->flags & ONLY_ARSYM) return; } print_members: /* Rewind the archive. */ if (elf_rand(ed->ar, SARMAG) != SARMAG) { warnx("elf_rand failed: %s", elf_errmsg(-1)); return; } /* Dump each member of the archive. */ cmd = ELF_C_READ; while ((ed->elf = elf_begin(fd, cmd, ed->ar)) != NULL) { /* Skip non-ELF member. */ if (elf_kind(ed->elf) == ELF_K_ELF) { if ((arh = elf_getarhdr(ed->elf)) == NULL) { warnx("elf_getarhdr failed: %s", elf_errmsg(-1)); break; } printf("\n%s(%s):\n", ed->archive, arh->ar_name); elf_print_elf(ed); } cmd = elf_next(ed->elf); elf_end(ed->elf); } } #endif /* USE_LIBARCHIVE_AR */ /* * Dump an object. (ELF object or ar(1) archive) */ static void elf_print_object(struct elfdump *ed) { int fd; if ((fd = open(ed->filename, O_RDONLY)) == -1) { warn("open %s failed", ed->filename); return; } #ifdef USE_LIBARCHIVE_AR if (ac_detect_ar(fd)) { ed->archive = ed->filename; ac_print_ar(ed, fd); return; } #endif /* USE_LIBARCHIVE_AR */ if ((ed->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warnx("elf_begin() failed: %s", elf_errmsg(-1)); return; } switch (elf_kind(ed->elf)) { case ELF_K_NONE: warnx("Not an ELF file."); return; case ELF_K_ELF: if (ed->flags & PRINT_FILENAME) printf("\n%s:\n", ed->filename); elf_print_elf(ed); break; case ELF_K_AR: #ifndef USE_LIBARCHIVE_AR ed->archive = ed->filename; elf_print_ar(ed, fd); #endif break; default: warnx("Internal: libelf returned unknown elf kind."); return; } elf_end(ed->elf); } /* * Dump an ELF object. */ static void elf_print_elf(struct elfdump *ed) { if (gelf_getehdr(ed->elf, &ed->ehdr) == NULL) { warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); return; } if ((ed->ec = gelf_getclass(ed->elf)) == ELFCLASSNONE) { warnx("gelf_getclass failed: %s", elf_errmsg(-1)); return; } if (ed->options & (ED_SHDR | ED_DYN | ED_REL | ED_GOT | ED_SYMTAB | ED_SYMVER | ED_NOTE | ED_HASH)) load_sections(ed); if (ed->options & ED_EHDR) elf_print_ehdr(ed); if (ed->options & ED_PHDR) elf_print_phdr(ed); if (ed->options & ED_INTERP) elf_print_interp(ed); if (ed->options & ED_SHDR) elf_print_shdr(ed); if (ed->options & ED_DYN) elf_print_dynamic(ed); if (ed->options & ED_REL) elf_print_reloc(ed); if (ed->options & ED_GOT) elf_print_got(ed); if (ed->options & ED_SYMTAB) elf_print_symtabs(ed); if (ed->options & ED_SYMVER) elf_print_symver(ed); if (ed->options & ED_NOTE) elf_print_note(ed); if (ed->options & ED_HASH) elf_print_hash(ed); if (ed->options & ED_CHECKSUM) elf_print_checksum(ed); unload_sections(ed); } /* * Read the section headers from ELF object and store them in the * internal cache. */ static void load_sections(struct elfdump *ed) { struct section *s; const char *name; Elf_Scn *scn; GElf_Shdr sh; size_t shstrndx, ndx; int elferr; assert(ed->sl == NULL); if (!elf_getshnum(ed->elf, &ed->shnum)) { warnx("elf_getshnum failed: %s", elf_errmsg(-1)); return; } if (ed->shnum == 0) return; if ((ed->sl = calloc(ed->shnum, sizeof(*ed->sl))) == NULL) err(EXIT_FAILURE, "calloc failed"); if (!elf_getshstrndx(ed->elf, &shstrndx)) { warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); return; } if ((scn = elf_getscn(ed->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(ed->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 >= ed->shnum) { warnx("section index of '%s' out of range", name); continue; } s = &ed->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(ed->elf, scn)) != NULL); elferr = elf_errno(); if (elferr != 0) warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); } /* * Release section related resources. */ static void unload_sections(struct elfdump *ed) { if (ed->sl != NULL) { free(ed->sl); ed->sl = NULL; } } /* * Add a name to the '-N' name list. */ static void add_name(struct elfdump *ed, const char *name) { struct spec_name *sn; if (find_name(ed, name)) return; if ((sn = malloc(sizeof(*sn))) == NULL) { warn("malloc failed"); return; } sn->name = name; STAILQ_INSERT_TAIL(&ed->snl, sn, sn_list); } /* * Lookup a name in the '-N' name list. */ static struct spec_name * find_name(struct elfdump *ed, const char *name) { struct spec_name *sn; STAILQ_FOREACH(sn, &ed->snl, sn_list) { if (!strcmp(sn->name, name)) return (sn); } return (NULL); } /* * 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 elfdump *ed, int symtab, int i) { static char sname[64]; struct section *s; const char *name; GElf_Sym sym; Elf_Data *data; int elferr; s = &ed->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 (""); if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) { if (sym.st_shndx < ed->shnum) { snprintf(sname, sizeof(sname), "%s (section)", ed->sl[sym.st_shndx].name); return (sname); } else return (""); } if ((name = elf_strptr(ed->elf, s->link, sym.st_name)) == NULL) return (""); return (name); } /* * Retrieve a string using string table section index and the string offset. */ static const char* get_string(struct elfdump *ed, int strtab, size_t off) { const char *name; if ((name = elf_strptr(ed->elf, strtab, off)) == NULL) return (""); return (name); } /* * Dump the ELF Executable Header. */ static void elf_print_ehdr(struct elfdump *ed) { if (!STAILQ_EMPTY(&ed->snl)) return; if (ed->flags & SOLARIS_FMT) { PRT("\nELF Header\n"); PRT(" ei_magic: { %#x, %c, %c, %c }\n", ed->ehdr.e_ident[0], ed->ehdr.e_ident[1], ed->ehdr.e_ident[2], ed->ehdr.e_ident[3]); PRT(" ei_class: %-18s", ei_classes[ed->ehdr.e_ident[EI_CLASS]]); PRT(" ei_data: %s\n", ei_data[ed->ehdr.e_ident[EI_DATA]]); PRT(" e_machine: %-18s", e_machines(ed->ehdr.e_machine)); PRT(" e_version: %s\n", ei_versions[ed->ehdr.e_version]); PRT(" e_type: %s\n", e_types[ed->ehdr.e_type]); PRT(" e_flags: %18d\n", ed->ehdr.e_flags); PRT(" e_entry: %#18jx", (uintmax_t)ed->ehdr.e_entry); PRT(" e_ehsize: %6d", ed->ehdr.e_ehsize); PRT(" e_shstrndx:%5d\n", ed->ehdr.e_shstrndx); PRT(" e_shoff: %#18jx", (uintmax_t)ed->ehdr.e_shoff); PRT(" e_shentsize: %3d", ed->ehdr.e_shentsize); PRT(" e_shnum: %5d\n", ed->ehdr.e_shnum); PRT(" e_phoff: %#18jx", (uintmax_t)ed->ehdr.e_phoff); PRT(" e_phentsize: %3d", ed->ehdr.e_phentsize); PRT(" e_phnum: %5d\n", ed->ehdr.e_phnum); } else { PRT("\nelf header:\n"); PRT("\n"); PRT("\te_ident: %s %s %s\n", ei_classes[ed->ehdr.e_ident[EI_CLASS]], ei_data[ed->ehdr.e_ident[EI_DATA]], ei_abis[ed->ehdr.e_ident[EI_OSABI]]); PRT("\te_type: %s\n", e_types[ed->ehdr.e_type]); PRT("\te_machine: %s\n", e_machines(ed->ehdr.e_machine)); PRT("\te_version: %s\n", ei_versions[ed->ehdr.e_version]); PRT("\te_entry: %#jx\n", (uintmax_t)ed->ehdr.e_entry); PRT("\te_phoff: %ju\n", (uintmax_t)ed->ehdr.e_phoff); PRT("\te_shoff: %ju\n", (uintmax_t) ed->ehdr.e_shoff); PRT("\te_flags: %u\n", ed->ehdr.e_flags); PRT("\te_ehsize: %u\n", ed->ehdr.e_ehsize); PRT("\te_phentsize: %u\n", ed->ehdr.e_phentsize); PRT("\te_phnum: %u\n", ed->ehdr.e_phnum); PRT("\te_shentsize: %u\n", ed->ehdr.e_shentsize); PRT("\te_shnum: %u\n", ed->ehdr.e_shnum); PRT("\te_shstrndx: %u\n", ed->ehdr.e_shstrndx); } } /* * Dump the ELF Program Header Table. */ static void elf_print_phdr(struct elfdump *ed) { GElf_Phdr ph; size_t phnum; int header, i; if (elf_getphnum(ed->elf, &phnum) == 0) { warnx("elf_getphnum failed: %s", elf_errmsg(-1)); return; } header = 0; for (i = 0; (u_int64_t) i < phnum; i++) { if (gelf_getphdr(ed->elf, i, &ph) != &ph) { warnx("elf_getphdr failed: %s", elf_errmsg(-1)); continue; } if (!STAILQ_EMPTY(&ed->snl) && find_name(ed, p_types[ph.p_type & 0x7]) == NULL) continue; if (ed->flags & SOLARIS_FMT) { PRT("\nProgram Header[%d]:\n", i); PRT(" p_vaddr: %#-14jx", (uintmax_t)ph.p_vaddr); PRT(" p_flags: [ %s ]\n", p_flags[ph.p_flags]); PRT(" p_paddr: %#-14jx", (uintmax_t)ph.p_paddr); PRT(" p_type: [ %s ]\n", p_types[ph.p_type & 0x7]); PRT(" p_filesz: %#-14jx", (uintmax_t)ph.p_filesz); PRT(" p_memsz: %#jx\n", (uintmax_t)ph.p_memsz); PRT(" p_offset: %#-14jx", (uintmax_t)ph.p_offset); PRT(" p_align: %#jx\n", (uintmax_t)ph.p_align); } else { if (!header) { PRT("\nprogram header:\n"); header = 1; } PRT("\n"); PRT("entry: %d\n", i); PRT("\tp_type: %s\n", p_types[ph.p_type & 0x7]); PRT("\tp_offset: %ju\n", (uintmax_t)ph.p_offset); PRT("\tp_vaddr: %#jx\n", (uintmax_t)ph.p_vaddr); PRT("\tp_paddr: %#jx\n", (uintmax_t)ph.p_paddr); PRT("\tp_filesz: %ju\n", (uintmax_t)ph.p_filesz); PRT("\tp_memsz: %ju\n", (uintmax_t)ph.p_memsz); PRT("\tp_flags: %s\n", p_flags[ph.p_flags]); PRT("\tp_align: %ju\n", (uintmax_t)ph.p_align); } } } /* * Dump the ELF Section Header Table. */ static void elf_print_shdr(struct elfdump *ed) { struct section *s; int i; if (!STAILQ_EMPTY(&ed->snl)) return; if ((ed->flags & SOLARIS_FMT) == 0) PRT("\nsection header:\n"); for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if (ed->flags & SOLARIS_FMT) { if (i == 0) continue; PRT("\nSection Header[%d]:", i); PRT(" sh_name: %s\n", s->name); PRT(" sh_addr: %#-14jx", (uintmax_t)s->addr); if (s->flags != 0) PRT(" sh_flags: [ %s ]\n", sh_flags(s->flags)); else PRT(" sh_flags: 0\n"); PRT(" sh_size: %#-14jx", (uintmax_t)s->sz); PRT(" sh_type: [ %s ]\n", sh_types(s->type)); PRT(" sh_offset: %#-14jx", (uintmax_t)s->off); PRT(" sh_entsize: %#jx\n", (uintmax_t)s->entsize); PRT(" sh_link: %-14u", s->link); PRT(" sh_info: %u\n", s->info); PRT(" sh_addralign: %#jx\n", (uintmax_t)s->align); } else { PRT("\n"); PRT("entry: %ju\n", (uintmax_t)i); PRT("\tsh_name: %s\n", s->name); PRT("\tsh_type: %s\n", sh_types(s->type)); PRT("\tsh_flags: %s\n", sh_flags(s->flags)); PRT("\tsh_addr: %#jx\n", (uintmax_t)s->addr); PRT("\tsh_offset: %ju\n", (uintmax_t)s->off); PRT("\tsh_size: %ju\n", (uintmax_t)s->sz); PRT("\tsh_link: %u\n", s->link); PRT("\tsh_info: %u\n", s->info); PRT("\tsh_addralign: %ju\n", (uintmax_t)s->align); PRT("\tsh_entsize: %ju\n", (uintmax_t)s->entsize); } } } /* * Retrieve the content of the corresponding SHT_SUNW_versym section for * a symbol table section. */ static void get_versym(struct elfdump *ed, int i, uint16_t **vs, int *nvs) { struct section *s; Elf_Data *data; int j, elferr; s = NULL; for (j = 0; (size_t)j < ed->shnum; j++) { s = &ed->sl[j]; if (s->type == SHT_SUNW_versym && s->link == (uint32_t)i) break; } if ((size_t)j >= ed->shnum) { *vs = NULL; 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)); *vs = NULL; return; } *vs = data->d_buf; *nvs = data->d_size / s->entsize; } /* * Dump the symbol table section. */ static void elf_print_symtab(struct elfdump *ed, int i) { struct section *s; const char *name; uint16_t *vs; char idx[10]; Elf_Data *data; GElf_Sym sym; int len, j, elferr, nvs; s = &ed->sl[i]; if (ed->flags & SOLARIS_FMT) PRT("\nSymbol Table Section: %s\n", s->name); else PRT("\nsymbol table (%s):\n", s->name); (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; } vs = NULL; nvs = 0; len = data->d_size / s->entsize; if (ed->flags & SOLARIS_FMT) { if (ed->ec == ELFCLASS32) PRT(" index value "); else PRT(" index value "); PRT("size type bind oth ver shndx name\n"); get_versym(ed, i, &vs, &nvs); if (vs != NULL && nvs != len) { warnx("#symbol not equal to #versym"); vs = NULL; } } for (j = 0; j < len; j++) { if (gelf_getsym(data, j, &sym) != &sym) { warnx("gelf_getsym failed: %s", elf_errmsg(-1)); continue; } name = get_string(ed, s->link, sym.st_name); if (ed->flags & SOLARIS_FMT) { snprintf(idx, sizeof(idx), "[%d]", j); if (ed->ec == ELFCLASS32) PRT("%10s ", idx); else PRT("%10s ", idx); PRT("0x%8.8jx ", (uintmax_t)sym.st_value); if (ed->ec == ELFCLASS32) PRT("0x%8.8jx ", (uintmax_t)sym.st_size); else PRT("0x%12.12jx ", (uintmax_t)sym.st_size); PRT("%s ", st_types_S[GELF_ST_TYPE(sym.st_info)]); PRT("%s ", st_bindings_S[GELF_ST_BIND(sym.st_info)]); PRT("%c ", st_others[sym.st_other]); PRT("%3u ", (vs == NULL ? 0 : vs[j])); PRT("%-11.11s ", sh_name(ed, sym.st_shndx)); PRT("%s\n", name); } else { PRT("\nentry: %d\n", j); PRT("\tst_name: %s\n", name); PRT("\tst_value: %#jx\n", (uintmax_t)sym.st_value); PRT("\tst_size: %ju\n", (uintmax_t)sym.st_size); PRT("\tst_info: %s %s\n", st_types[GELF_ST_TYPE(sym.st_info)], st_bindings[GELF_ST_BIND(sym.st_info)]); PRT("\tst_shndx: %ju\n", (uintmax_t)sym.st_shndx); } } } /* * Dump the symbol tables. (.dynsym and .symtab) */ static void elf_print_symtabs(struct elfdump *ed) { int i; for (i = 0; (size_t)i < ed->shnum; i++) if ((ed->sl[i].type == SHT_SYMTAB || ed->sl[i].type == SHT_DYNSYM) && (STAILQ_EMPTY(&ed->snl) || find_name(ed, ed->sl[i].name))) elf_print_symtab(ed, i); } /* * Dump the content of .dynamic section. */ static void elf_print_dynamic(struct elfdump *ed) { struct section *s; const char *name; char idx[10]; Elf_Data *data; GElf_Dyn dyn; int elferr, i, len; s = NULL; for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if (s->type == SHT_DYNAMIC && (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) break; } if ((size_t)i >= ed->shnum) return; if (ed->flags & SOLARIS_FMT) { PRT("Dynamic Section: %s\n", s->name); PRT(" index tag value\n"); } else PRT("\ndynamic:\n"); (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; } len = data->d_size / s->entsize; for (i = 0; i < len; i++) { if (gelf_getdyn(data, i, &dyn) != &dyn) { warnx("gelf_getdyn failed: %s", elf_errmsg(-1)); continue; } if (ed->flags & SOLARIS_FMT) { snprintf(idx, sizeof(idx), "[%d]", i); PRT("%10s %-16s ", idx, d_tags(dyn.d_tag)); } else { PRT("\n"); PRT("entry: %d\n", i); PRT("\td_tag: %s\n", d_tags(dyn.d_tag)); } switch(dyn.d_tag) { case DT_NEEDED: case DT_SONAME: case DT_RPATH: if ((name = elf_strptr(ed->elf, s->link, dyn.d_un.d_val)) == NULL) name = ""; if (ed->flags & SOLARIS_FMT) PRT("%#-16jx %s\n", (uintmax_t)dyn.d_un.d_val, name); else PRT("\td_val: %s\n", name); break; case DT_PLTRELSZ: case DT_RELA: case DT_RELASZ: case DT_RELAENT: case DT_RELACOUNT: case DT_STRSZ: case DT_SYMENT: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: case DT_VERDEF: case DT_VERDEFNUM: case DT_VERNEED: case DT_VERNEEDNUM: case DT_VERSYM: if (ed->flags & SOLARIS_FMT) PRT("%#jx\n", (uintmax_t)dyn.d_un.d_val); else PRT("\td_val: %ju\n", (uintmax_t)dyn.d_un.d_val); break; case DT_PLTGOT: case DT_HASH: case DT_GNU_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_INIT: case DT_FINI: case DT_REL: case DT_JMPREL: case DT_DEBUG: if (ed->flags & SOLARIS_FMT) PRT("%#jx\n", (uintmax_t)dyn.d_un.d_ptr); else PRT("\td_ptr: %#jx\n", (uintmax_t)dyn.d_un.d_ptr); break; case DT_NULL: case DT_SYMBOLIC: case DT_TEXTREL: default: if (ed->flags & SOLARIS_FMT) PRT("\n"); break; } } } /* * Dump a .rel/.rela section entry. */ static void elf_print_rel_entry(struct elfdump *ed, struct section *s, int j, struct rel_entry *r) { if (ed->flags & SOLARIS_FMT) { PRT(" %-23s ", r_type(ed->ehdr.e_machine, GELF_R_TYPE(r->u_r.rel.r_info))); PRT("%#12jx ", (uintmax_t)r->u_r.rel.r_offset); if (r->type == SHT_RELA) PRT("%10jd ", (intmax_t)r->u_r.rela.r_addend); else PRT(" "); PRT("%-14s ", s->name); PRT("%s\n", r->symn); } else { PRT("\n"); PRT("entry: %d\n", j); PRT("\tr_offset: %#jx\n", (uintmax_t)r->u_r.rel.r_offset); if (ed->ec == ELFCLASS32) PRT("\tr_info: %#jx\n", (uintmax_t) ELF32_R_INFO(ELF64_R_SYM(r->u_r.rel.r_info), ELF64_R_TYPE(r->u_r.rel.r_info))); else PRT("\tr_info: %#jx\n", (uintmax_t)r->u_r.rel.r_info); if (r->type == SHT_RELA) PRT("\tr_addend: %jd\n", (intmax_t)r->u_r.rela.r_addend); } } /* * Dump a relocation section of type SHT_RELA. */ static void elf_print_rela(struct elfdump *ed, struct section *s, Elf_Data *data) { struct rel_entry r; int j, len; if (ed->flags & SOLARIS_FMT) { PRT("\nRelocation Section: %s\n", s->name); PRT(" type offset " "addend section with respect to\n"); } else PRT("\nrelocation with addend (%s):\n", s->name); r.type = SHT_RELA; len = data->d_size / s->entsize; for (j = 0; j < len; j++) { if (gelf_getrela(data, j, &r.u_r.rela) != &r.u_r.rela) { warnx("gelf_getrela failed: %s", elf_errmsg(-1)); continue; } r.symn = get_symbol_name(ed, s->link, GELF_R_SYM(r.u_r.rela.r_info)); elf_print_rel_entry(ed, s, j, &r); } } /* * Dump a relocation section of type SHT_REL. */ static void elf_print_rel(struct elfdump *ed, struct section *s, Elf_Data *data) { struct rel_entry r; int j, len; if (ed->flags & SOLARIS_FMT) { PRT("\nRelocation Section: %s\n", s->name); PRT(" type offset " "section with respect to\n"); } else PRT("\nrelocation (%s):\n", s->name); r.type = SHT_REL; len = data->d_size / s->entsize; for (j = 0; j < len; j++) { if (gelf_getrel(data, j, &r.u_r.rel) != &r.u_r.rel) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } r.symn = get_symbol_name(ed, s->link, GELF_R_SYM(r.u_r.rel.r_info)); elf_print_rel_entry(ed, s, j, &r); } } /* * Dump relocation sections. */ static void elf_print_reloc(struct elfdump *ed) { struct section *s; Elf_Data *data; int i, elferr; for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if ((s->type == SHT_REL || s->type == SHT_RELA) && (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) { (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)); continue; } if (s->type == SHT_REL) elf_print_rel(ed, s, data); else elf_print_rela(ed, s, data); } } } /* * Dump the content of PT_INTERP segment. */ static void elf_print_interp(struct elfdump *ed) { const char *s; GElf_Phdr phdr; size_t phnum; int i; if (!STAILQ_EMPTY(&ed->snl) && find_name(ed, "PT_INTERP") == NULL) return; if ((s = elf_rawfile(ed->elf, NULL)) == NULL) { warnx("elf_rawfile failed: %s", elf_errmsg(-1)); return; } if (!elf_getphnum(ed->elf, &phnum)) { warnx("elf_getphnum failed: %s", elf_errmsg(-1)); return; } for (i = 0; (size_t)i < phnum; i++) { if (gelf_getphdr(ed->elf, i, &phdr) != &phdr) { warnx("elf_getphdr failed: %s", elf_errmsg(-1)); continue; } if (phdr.p_type == PT_INTERP) { PRT("\ninterp:\n"); PRT("\t%s\n", s + phdr.p_offset); } } } /* * Search the relocation sections for entries refering to the .got section. */ static void find_gotrel(struct elfdump *ed, struct section *gs, struct rel_entry *got) { struct section *s; struct rel_entry r; Elf_Data *data; int elferr, i, j, k, len; for(i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if (s->type != SHT_REL && s->type != SHT_RELA) continue; (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; } memset(&r, 0, sizeof(struct rel_entry)); r.type = s->type; len = data->d_size / s->entsize; for (j = 0; j < len; j++) { if (s->type == SHT_REL) { if (gelf_getrel(data, j, &r.u_r.rel) != &r.u_r.rel) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } } else { if (gelf_getrela(data, j, &r.u_r.rela) != &r.u_r.rela) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } } if (r.u_r.rel.r_offset >= gs->addr && r.u_r.rel.r_offset < gs->addr + gs->sz) { r.symn = get_symbol_name(ed, s->link, GELF_R_SYM(r.u_r.rel.r_info)); k = (r.u_r.rel.r_offset - gs->addr) / gs->entsize; memcpy(&got[k], &r, sizeof(struct rel_entry)); } } } } static void elf_print_got_section(struct elfdump *ed, struct section *s) { struct rel_entry *got; Elf_Data *data, dst; int elferr, i, len; if (s->entsize == 0) { /* XXX IA64 GOT section generated by gcc has entry size 0. */ if (s->align != 0) s->entsize = s->align; else return; } if (ed->flags & SOLARIS_FMT) PRT("\nGlobal Offset Table Section: %s (%jd entries)\n", s->name, s->sz / s->entsize); else PRT("\nglobal offset table: %s\n", s->name); (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; } /* * GOT section has section type SHT_PROGBITS, thus libelf treats it as * byte stream and will not perfrom any translation on it. As a result, * an exlicit call to gelf_xlatetom is needed here. Depends on arch, * GOT section should be translated to either WORD or XWORD. */ if (ed->ec == ELFCLASS32) data->d_type = ELF_T_WORD; else data->d_type = ELF_T_XWORD; memcpy(&dst, data, sizeof(Elf_Data)); if (gelf_xlatetom(ed->elf, &dst, data, ed->ehdr.e_ident[EI_DATA]) != &dst) { warnx("gelf_xlatetom failed: %s", elf_errmsg(-1)); return; } len = dst.d_size / s->entsize; if (ed->flags & SOLARIS_FMT) { /* * In verbose/Solaris mode, we search the relocation sections * and try to find the corresponding reloc entry for each GOT * section entry. */ if ((got = calloc(len, sizeof(struct rel_entry))) == NULL) err(EXIT_FAILURE, "calloc failed"); find_gotrel(ed, s, got); if (ed->ec == ELFCLASS32) { PRT(" ndx addr value reloc "); PRT("addend symbol\n"); } else { PRT(" ndx addr value "); PRT("reloc addend symbol\n"); } for(i = 0; i < len; i++) { PRT("[%5.5d] ", i); if (ed->ec == ELFCLASS32) { PRT("%-8.8jx ", s->addr + i * s->entsize); PRT("%-8.8x ", *((uint32_t *)dst.d_buf + i)); } else { PRT("%-16.16jx ", s->addr + i * s->entsize); PRT("%-16.16jx ", *((uint64_t *)dst.d_buf + i)); } PRT("%-18s ", r_type(ed->ehdr.e_machine, GELF_R_TYPE(got[i].u_r.rel.r_info))); if (ed->ec == ELFCLASS32) PRT("%-8.8jd ", (intmax_t)got[i].u_r.rela.r_addend); else PRT("%-12.12jd ", (intmax_t)got[i].u_r.rela.r_addend); if (got[i].symn == NULL) got[i].symn = ""; PRT("%s\n", got[i].symn); } free(got); } else { for(i = 0; i < len; i++) { PRT("\nentry: %d\n", i); if (ed->ec == ELFCLASS32) PRT("\t%#x\n", *((uint32_t *)dst.d_buf + i)); else PRT("\t%#jx\n", *((uint64_t *)dst.d_buf + i)); } } } /* * Dump the content of Global Offset Table section. */ static void elf_print_got(struct elfdump *ed) { struct section *s; int i; if (!STAILQ_EMPTY(&ed->snl)) return; s = NULL; for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if (s->name && !strncmp(s->name, ".got", 4) && (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) elf_print_got_section(ed, s); } } /* * Dump the content of .note.ABI-tag section. */ static void elf_print_note(struct elfdump *ed) { struct section *s; Elf_Data *data; Elf_Note *en; uint32_t namesz; uint32_t descsz; uint32_t desc; size_t count; int elferr, i; char *src, idx[10]; s = NULL; for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if (s->type == SHT_NOTE && s->name && !strcmp(s->name, ".note.ABI-tag") && (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) break; } if ((size_t)i >= ed->shnum) return; if (ed->flags & SOLARIS_FMT) PRT("\nNote Section: %s\n", s->name); else PRT("\nnote (%s):\n", s->name); (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; } src = data->d_buf; count = data->d_size; while (count > sizeof(Elf_Note)) { en = (Elf_Note *) (uintptr_t) src; namesz = en->n_namesz; descsz = en->n_descsz; src += sizeof(Elf_Note); count -= sizeof(Elf_Note); if (ed->flags & SOLARIS_FMT) { PRT("\n type %#x\n", en->n_type); PRT(" namesz %#x:\n", en->n_namesz); PRT("%s\n", src); } else PRT("\t%s ", src); src += roundup2(namesz, 4); count -= roundup2(namesz, 4); /* * Note that we dump the whole desc part if we're in * "Solaris mode", while in the normal mode, we only look * at the first 4 bytes (a 32bit word) of the desc, i.e, * we assume that it's always a FreeBSD version number. */ if (ed->flags & SOLARIS_FMT) { PRT(" descsz %#x:", en->n_descsz); for (i = 0; (uint32_t)i < descsz; i++) { if ((i & 0xF) == 0) { snprintf(idx, sizeof(idx), "desc[%d]", i); PRT("\n %-9s", idx); } else if ((i & 0x3) == 0) PRT(" "); PRT(" %2.2x", src[i]); } PRT("\n"); } else { if (ed->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) desc = be32dec(src); else desc = le32dec(src); PRT("%d\n", desc); } src += roundup2(descsz, 4); count -= roundup2(descsz, 4); } } /* * Dump a hash table. */ static void elf_print_svr4_hash(struct elfdump *ed, struct section *s) { Elf_Data *data; uint32_t *buf; uint32_t *bucket, *chain; uint32_t nbucket, nchain; uint32_t *bl, *c, maxl, total; int i, j, first, elferr; char idx[10]; if (ed->flags & SOLARIS_FMT) PRT("\nHash Section: %s\n", s->name); else PRT("\nhash table (%s):\n", s->name); (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 (data->d_size < 2 * sizeof(uint32_t)) { warnx(".hash section too small"); return; } buf = data->d_buf; nbucket = buf[0]; nchain = buf[1]; if (nbucket <= 0 || nchain <= 0) { warnx("Malformed .hash section"); return; } if (data->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) { warnx("Malformed .hash section"); return; } bucket = &buf[2]; chain = &buf[2 + nbucket]; if (ed->flags & SOLARIS_FMT) { maxl = 0; if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) err(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) err(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) c[bl[i]]++; PRT(" bucket symndx name\n"); for (i = 0; (uint32_t)i < nbucket; i++) { first = 1; for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j]) { if (first) { PRT("%10d ", i); first = 0; } else PRT(" "); snprintf(idx, sizeof(idx), "[%d]", j); PRT("%-10s ", idx); PRT("%s\n", get_symbol_name(ed, s->link, j)); } } PRT("\n"); total = 0; for (i = 0; (uint32_t)i <= maxl; i++) { total += c[i] * i; PRT("%10u buckets contain %8d symbols\n", c[i], i); } PRT("%10u buckets %8u symbols (globals)\n", nbucket, total); } else { PRT("\nnbucket: %u\n", nbucket); PRT("nchain: %u\n\n", nchain); for (i = 0; (uint32_t)i < nbucket; i++) PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]); for (i = 0; (uint32_t)i < nchain; i++) PRT("chain[%d]:\n\t%u\n\n", i, chain[i]); } } /* * Dump a 64bit hash table. */ static void elf_print_svr4_hash64(struct elfdump *ed, struct section *s) { Elf_Data *data, dst; uint64_t *buf; uint64_t *bucket, *chain; uint64_t nbucket, nchain; uint64_t *bl, *c, maxl, total; int i, j, elferr, first; char idx[10]; if (ed->flags & SOLARIS_FMT) PRT("\nHash Section: %s\n", s->name); else PRT("\nhash table (%s):\n", s->name); /* * 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 ((data = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_rawdata failed: %s", elf_errmsg(elferr)); return; } data->d_type = ELF_T_XWORD; memcpy(&dst, data, sizeof(Elf_Data)); if (gelf_xlatetom(ed->elf, &dst, data, ed->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 (dst.d_size != (nbucket + nchain + 2) * sizeof(uint64_t)) { warnx("Malformed .hash section"); return; } bucket = &buf[2]; chain = &buf[2 + nbucket]; if (ed->flags & SOLARIS_FMT) { maxl = 0; if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) err(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint64_t)i < nbucket; i++) for (j = bucket[i]; j > 0 && (uint64_t)j < nchain; j = chain[j]) if (++bl[i] > maxl) maxl = bl[i]; if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) err(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint64_t)i < nbucket; i++) c[bl[i]]++; PRT(" bucket symndx name\n"); for (i = 0; (uint64_t)i < nbucket; i++) { first = 1; for (j = bucket[i]; j > 0 && (uint64_t)j < nchain; j = chain[j]) { if (first) { PRT("%10d ", i); first = 0; } else PRT(" "); snprintf(idx, sizeof(idx), "[%d]", j); PRT("%-10s ", idx); PRT("%s\n", get_symbol_name(ed, s->link, j)); } } PRT("\n"); total = 0; for (i = 0; (uint64_t)i <= maxl; i++) { total += c[i] * i; PRT("%10ju buckets contain %8d symbols\n", (uintmax_t)c[i], i); } PRT("%10ju buckets %8ju symbols (globals)\n", (uintmax_t)nbucket, (uintmax_t)total); } else { PRT("\nnbucket: %ju\n", (uintmax_t)nbucket); PRT("nchain: %ju\n\n", (uintmax_t)nchain); for (i = 0; (uint64_t)i < nbucket; i++) PRT("bucket[%d]:\n\t%ju\n\n", i, (uintmax_t)bucket[i]); for (i = 0; (uint64_t)i < nchain; i++) PRT("chain[%d]:\n\t%ju\n\n", i, (uintmax_t)chain[i]); } } /* * Dump a GNU hash table. */ static void elf_print_gnu_hash(struct elfdump *ed, struct section *s) { struct section *ds; Elf_Data *data; uint32_t *buf; uint32_t *bucket, *chain; uint32_t nbucket, nchain, symndx, maskwords, shift2; uint32_t *bl, *c, maxl, total; int i, j, first, elferr, dynsymcount; char idx[10]; if (ed->flags & SOLARIS_FMT) PRT("\nGNU Hash Section: %s\n", s->name); else PRT("\ngnu hash table (%s):\n", s->name); (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 (data->d_size < 4 * sizeof(uint32_t)) { warnx(".gnu.hash section too small"); return; } buf = data->d_buf; nbucket = buf[0]; symndx = buf[1]; maskwords = buf[2]; shift2 = buf[3]; buf += 4; ds = &ed->sl[s->link]; dynsymcount = ds->sz / ds->entsize; nchain = dynsymcount - symndx; if (data->d_size != 4 * sizeof(uint32_t) + maskwords * (ed->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) + (nbucket + nchain) * sizeof(uint32_t)) { warnx("Malformed .gnu.hash section"); return; } bucket = buf + (ed->ec == ELFCLASS32 ? maskwords : maskwords * 2); chain = bucket + nbucket; if (ed->flags & SOLARIS_FMT) { maxl = 0; if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) err(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) err(EXIT_FAILURE, "calloc failed"); for (i = 0; (uint32_t)i < nbucket; i++) c[bl[i]]++; PRT(" bucket symndx name\n"); for (i = 0; (uint32_t)i < nbucket; i++) { first = 1; for (j = bucket[i]; j > 0 && (uint32_t)j - symndx < nchain; j++) { if (first) { PRT("%10d ", i); first = 0; } else PRT(" "); snprintf(idx, sizeof(idx), "[%d]", j ); PRT("%-10s ", idx); PRT("%s\n", get_symbol_name(ed, s->link, j)); if (chain[j - symndx] & 1) break; } } PRT("\n"); total = 0; for (i = 0; (uint32_t)i <= maxl; i++) { total += c[i] * i; PRT("%10u buckets contain %8d symbols\n", c[i], i); } PRT("%10u buckets %8u symbols (globals)\n", nbucket, total); } else { PRT("\nnbucket: %u\n", nbucket); PRT("symndx: %u\n", symndx); PRT("maskwords: %u\n", maskwords); PRT("shift2: %u\n", shift2); PRT("nchain: %u\n\n", nchain); for (i = 0; (uint32_t)i < nbucket; i++) PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]); for (i = 0; (uint32_t)i < nchain; i++) PRT("chain[%d]:\n\t%u\n\n", i, chain[i]); } } /* * Dump hash tables. */ static void elf_print_hash(struct elfdump *ed) { struct section *s; int i; for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if ((s->type == SHT_HASH || s->type == SHT_GNU_HASH) && (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) { if (s->type == SHT_GNU_HASH) elf_print_gnu_hash(ed, s); else if (ed->ehdr.e_machine == EM_ALPHA && s->entsize == 8) elf_print_svr4_hash64(ed, s); else elf_print_svr4_hash(ed, s); } } } /* * Dump the content of a Version Definition(SHT_SUNW_Verdef) Section. */ static void elf_print_verdef(struct elfdump *ed, struct section *s) { Elf_Data *data; Elf32_Verdef *vd; Elf32_Verdaux *vda; const char *str; char idx[10]; uint8_t *buf, *end, *buf2; int i, j, elferr, count; if (ed->flags & SOLARIS_FMT) PRT("Version Definition Section: %s\n", s->name); else PRT("\nversion definition section (%s):\n", s->name); (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; } buf = data->d_buf; end = buf + data->d_size; i = 0; if (ed->flags & SOLARIS_FMT) PRT(" index version dependency\n"); while (buf + sizeof(Elf32_Verdef) <= end) { vd = (Elf32_Verdef *) (uintptr_t) buf; if (ed->flags & SOLARIS_FMT) { snprintf(idx, sizeof(idx), "[%d]", vd->vd_ndx); PRT("%10s ", idx); } else { PRT("\nentry: %d\n", i++); PRT("\tvd_version: %u\n", vd->vd_version); PRT("\tvd_flags: %u\n", vd->vd_flags); PRT("\tvd_ndx: %u\n", vd->vd_ndx); PRT("\tvd_cnt: %u\n", vd->vd_cnt); PRT("\tvd_hash: %u\n", vd->vd_hash); PRT("\tvd_aux: %u\n", vd->vd_aux); PRT("\tvd_next: %u\n\n", vd->vd_next); } buf2 = buf + vd->vd_aux; j = 0; count = 0; while (buf2 + sizeof(Elf32_Verdaux) <= end && j < vd->vd_cnt) { vda = (Elf32_Verdaux *) (uintptr_t) buf2; str = get_string(ed, s->link, vda->vda_name); if (ed->flags & SOLARIS_FMT) { if (count == 0) PRT("%-26.26s", str); else if (count == 1) PRT(" %-20.20s", str); else { PRT("\n%40.40s", ""); PRT("%s", str); } } else { PRT("\t\tvda: %d\n", j++); PRT("\t\t\tvda_name: %s\n", str); PRT("\t\t\tvda_next: %u\n", vda->vda_next); } if (vda->vda_next == 0) { if (ed->flags & SOLARIS_FMT) { if (vd->vd_flags & VER_FLG_BASE) { if (count == 0) PRT("%-20.20s", ""); PRT("%s", "[ BASE ]"); } PRT("\n"); } break; } if (ed->flags & SOLARIS_FMT) count++; buf2 += vda->vda_next; } if (vd->vd_next == 0) break; buf += vd->vd_next; } } /* * Dump the content of a Version Needed(SHT_SUNW_Verneed) Section. */ static void elf_print_verneed(struct elfdump *ed, struct section *s) { Elf_Data *data; Elf32_Verneed *vn; Elf32_Vernaux *vna; uint8_t *buf, *end, *buf2; int i, j, elferr, first; if (ed->flags & SOLARIS_FMT) PRT("\nVersion Needed Section: %s\n", s->name); else PRT("\nversion need section (%s):\n", s->name); (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; } buf = data->d_buf; end = buf + data->d_size; if (ed->flags & SOLARIS_FMT) PRT(" file version\n"); i = 0; while (buf + sizeof(Elf32_Verneed) <= end) { vn = (Elf32_Verneed *) (uintptr_t) buf; if (ed->flags & SOLARIS_FMT) PRT(" %-26.26s ", get_string(ed, s->link, vn->vn_file)); else { PRT("\nentry: %d\n", i++); PRT("\tvn_version: %u\n", vn->vn_version); PRT("\tvn_cnt: %u\n", vn->vn_cnt); PRT("\tvn_file: %s\n", get_string(ed, s->link, vn->vn_file)); PRT("\tvn_aux: %u\n", vn->vn_aux); PRT("\tvn_next: %u\n\n", vn->vn_next); } buf2 = buf + vn->vn_aux; j = 0; first = 1; while (buf2 + sizeof(Elf32_Vernaux) <= end && j < vn->vn_cnt) { vna = (Elf32_Vernaux *) (uintptr_t) buf2; if (ed->flags & SOLARIS_FMT) { if (!first) PRT("%40.40s", ""); else first = 0; PRT("%s\n", get_string(ed, s->link, vna->vna_name)); } else { PRT("\t\tvna: %d\n", j++); PRT("\t\t\tvna_hash: %u\n", vna->vna_hash); PRT("\t\t\tvna_flags: %u\n", vna->vna_flags); PRT("\t\t\tvna_other: %u\n", vna->vna_other); PRT("\t\t\tvna_name: %s\n", get_string(ed, s->link, vna->vna_name)); PRT("\t\t\tvna_next: %u\n", vna->vna_next); } if (vna->vna_next == 0) break; buf2 += vna->vna_next; } if (vn->vn_next == 0) break; buf += vn->vn_next; } } /* * Dump the symbol-versioning sections. */ static void elf_print_symver(struct elfdump *ed) { struct section *s; int i; for (i = 0; (size_t)i < ed->shnum; i++) { s = &ed->sl[i]; if (!STAILQ_EMPTY(&ed->snl) && !find_name(ed, s->name)) continue; if (s->type == SHT_SUNW_verdef) elf_print_verdef(ed, s); if (s->type == SHT_SUNW_verneed) elf_print_verneed(ed, s); } } /* * Dump the ELF checksum. See gelf_checksum(3) for details. */ static void elf_print_checksum(struct elfdump *ed) { if (!STAILQ_EMPTY(&ed->snl)) return; PRT("\nelf checksum: %#lx\n", gelf_checksum(ed->elf)); } #define USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Display information about ELF objects and ar(1) archives.\n\n\ Options:\n\ -a Show all information.\n\ -c Show shared headers.\n\ -d Show dynamic symbols.\n\ -e Show the ELF header.\n\ -G Show the GOT.\n\ -H | --help Show a usage message and exit.\n\ -h Show hash values.\n\ -i Show the dynamic interpreter.\n\ -k Show the ELF checksum.\n\ -n Show the contents of note sections.\n\ -N NAME Show the section named \"NAME\".\n\ -p Show the program header.\n\ -r Show relocations.\n\ -s Show the symbol table.\n\ -S Use the Solaris elfdump format.\n\ -v Show symbol-versioning information.\n\ -V | --version Print a version identifier and exit.\n\ -w FILE Write output to \"FILE\".\n" static void usage(void) { fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } Index: vendor/elftoolchain/dist/findtextrel/findtextrel.1 =================================================================== --- vendor/elftoolchain/dist/findtextrel/findtextrel.1 (revision 282910) +++ vendor/elftoolchain/dist/findtextrel/findtextrel.1 (revision 282911) @@ -1,104 +1,104 @@ .\" Copyright (c) 2010,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: findtextrel.1 2069 2011-10-26 15:53:48Z jkoshy $ +.\" $Id: findtextrel.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd August 25, 2011 .Os .Dt FINDTEXTREL 1 .Sh NAME .Nm findtextrel .Nd locate text relocation entries in position independent ELF executables .Sh SYNOPSIS .Nm .Op Fl V .Op Fl H .Op Ar .Sh DESCRIPTION The .Nm utility displays information about text relocations in ELF objects containing position independent code. .Pp Text relocations are usually undesirable because they require that the text sections of objects be modified at load time, preventing the sharing of text sections across multiple processes using a dynamic shared object. .Pp Arguments .Ar name ELF executables to be examined. If no files are specified, the .Nm utility will examine the file .Pa a.out in the current directory. .Pp The .Nm utility recognizes the following options: .Bl -tag -width indent .It Fl H Print a brief help message. .It Fl V Print a version identifier and exit. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES To list text relocations in an object, use: .Bd -literal -offset indent % findtextrel a.out a.out: ELF object contains text relocation records: a.out: off: 0x530, func: main, file: a.c, line: 5 .Ed .Sh DIAGNOSTICS The .Nm may issue the following diagnostics: .Bl -diag .It "ELF object is not a DSO/PIE" The ELF executable specified by argument .Ar object was not a position independent executable. .It "ELF object does not contain a text relocation" The ELF executable specified by argument .Ar object contained no text relocations. .El .Sh SEE ALSO .Xr addr2line 1 , .Xr nm 1 , .Xr readelf 1 .Sh HISTORY A .Nm utility first appeared in the .Nm elfutils toolset from Red Hat, Inc. .Sh AUTHORS This implementation of the .Nm utility was created by -.An "Kai Wang" Aq kaiwang27@users.sourceforge.net . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: vendor/elftoolchain/dist/isa/isa.1 =================================================================== --- vendor/elftoolchain/dist/isa/isa.1 (revision 282910) +++ vendor/elftoolchain/dist/isa/isa.1 (revision 282911) @@ -1,248 +1,247 @@ .\" Copyright (c) 2012,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 AND 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: isa.1 2889 2013-01-13 15:36:04Z jkoshy $ +.\" $Id: isa.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd January 13, 2013 .Os .Dt ISA 1 .Sh NAME .Nm isa .Nd instruction set analyser .Sh SYNOPSIS .Nm .Op Fl a Ar architecture | Fl -arch Ns = Ns Ar architecture .Op Fl c Ar cpu | Fl -cpu Ns = Ns Ar cpu .Op Fl h | Fl -help .Op Fl i Ar filename | Fl -input Ns = Ns Ar filename .Op Fl n | Fl -dry-run .Op Fl o Ar filename | Fl -output Ns = Ns Ar filename .Op Fl p Ar string | Fl -prefix Ns = Ns Ar string .Op Fl s Ar filename | Fl -spec Ns = Ns Ar filename .Op Fl q | Fl -quiet .Op Fl v | Fl -verbose .Op Fl D | Fl -decode .Op Fl E | Fl -encode .Op Fl L | Fl -list-instructions .Op Fl N Ar number | Fl -ntests Ns = Ns Ar number .Op Fl Q | Fl -query .Op Fl R Ar number | Fl -random-seed Ns = Ns Ar number .Op Fl T | Fl -test .Op Fl V | Fl -version .Ar .Sh DESCRIPTION The .Nm utility is used to generate instruction stream encoders and decoders from a textual description of a CPU instruction set. .Pp The .Nm utility supports three operational modes, as specified by the use of the .Fl D , .Fl E or .Fl Q options: .Bl -tag -width indent .It Cm Decode .Pq Fl D | Fl -decode In this mode, the .Nm utility transforms source code, expanding match pattern between the tokens .Dq Li "[ISA[" and .Dq Li "]ISA]" into the appropriate code for matching instruction streams. The section .Sx "Matching Instructions" describes the decode functionality in greater depth. .It Cm Encode .Pq Fl E | Fl -encode In this mode, the .Nm utility generates C code to emit binary instruction streams. .It Cm Query .Pq Fl Q | Fl -query In this mode, the .Nm utility is used to retrieve information from instruction set specifications. .El .Pp If no operational mode is specified, a default of .Cm Query will be used. .Pp Instruction set specifications may be specified using the .Fa a option, or by using the command line arguments .Ar . .Pp The .Nm utility accepts the following options: .Bl -tag -width indent .It Fl a Ar architecture | Fl -arch Ns = N Ar architecture Use instruction set specifications specified by the argument .Ar architecture . The .Nm utility will look for these specifications in the locations specified by the environment variable .Ev ISAPATH , in addition to a built-in search location. The default architecture is that for the host the .Nm utility is being executed on.s .It Fl c Ar cpu | Fl -cpu Ns = Ns Ar cpu Generate encoders and decoders for the specific instruction set variant supported by CPU .Ar cpu . This option may be specified multiple times. If the argument .Ar cpu starts with a minus, the CPU specified will be removed from list of CPUs to be supported. .It Fl h | Fl -help Print a help message and exit. .It Fl i Ar filename | Fl -input Ns = Ns Ar filename When generating a decoder, read the source to be expanded from the file named in the argument .Ar filename . If an input file is not specified, the .Nm utility will read from its standard input. .It Fl n | Fl -dry-run Exit without creating any output after checking inputs for errors. .It Fl o Ar filename | Fl -output Ns = Ns Ar filename When generating encoders and decoders, send the output to the file specified by the argument .Ar filename . If an output file is not specified, the .Nm utility will write to its standard output. .It Fl p Ar string | Fl -prefix Ns = Ns Ar string When in encode mode, use the string in argument .Ar string as a prefix for generated symbols. .It Fl q | Fl -quiet Suppress warning messages. .It Fl s Ar filename | Fl -spec Ns = Ns Ar filename Read an instruction set specification from the file named by argument .Ar filename . This option may be specified multiple times, in which case the .Nm utilitiy behaves as if the specifications had been concatenated in the sequence specified. .It Fl v | Fl -verbose Increase the verbosity level. This option may be specified multiple times. .It Fl D | Fl -decode Transform sources expanding match patterns in source code to lower-level instruction stream decoding code. By default, the .Nm utility will read from standard input and write to standard output, unless otherwise specified by the .Fl i and .Fl o options. .It Fl E | Fl -encode Build an instruction stream encoder. .It Fl L | Fl -list-instructions When in query mode, generate a list of all known instructions. .It Fl N Ar number | Fl -ntests Ns = Ns Ar number When in query mode, specify the number of test sequences to be generated if the .Fl -T | Fl -test option was specified. .It Fl Q | Fl -query Retrieve information about an instruction set. .It Fl R Ar number | Fl -random-seed Ns = Ns Ar number Use the argument .Ar number as the seed for pseudorandom number generation. If this option is not specified, the .Nm utility will initialize the pseudorandom number generator in an implementation-defined manner. .It Fl T | Fl -test Generate instruction sequences for use in testing tools such as assemblers. .It Fl V | Fl -version Print a version identifier and exit. .El .Sh ENVIRONMENT The behavior of the .Nm utility is affected by the following environemnt variables: .Bl -tag .It Ev ISAPATH Specifies a colon-separated set of directories tp be used when searching for instruction specifications. .El .Sh FILES .Bl -tag -width indent .It Pa /usr/share/isa/ The default location for instruction set specifications. .El .Sh EXAMPLES To check the instruction specifications in file .Pa spec.isa , use: .D1 isa -n "spec.isa" .Pp To expand instruction decoding templates in the file .Pa a.m , assuming a generic .Tn AVR CPU, and generating a C source file, use: .D1 isa -a avr -D < a.m > a.c .Sh SEE ALSO .Xr elf 3 , .Xr elf 5 , .Xr isa 5 .Sh HISTORY The .Nm utility is scheduled to appear in a future release from the Elftoolchain project. .\" TODO Reword the above when the target release is finalized. .Sh AUTHORS The .Xr isa 1 utility was written by -.An Joseph Koshy -.Aq jkoshy@users.sourceforge.net . +.An Joseph Koshy Aq Mt jkoshy@users.sourceforge.net . .Sh BUGS The .Nm utility is wildly unstable at this point of time. If you intend to use this utility, please get in touch with the project's developers at .Aq elftoolchain-developers@lists.sourceforge.net . Index: vendor/elftoolchain/dist/isa/isa.5 =================================================================== --- vendor/elftoolchain/dist/isa/isa.5 (revision 282910) +++ vendor/elftoolchain/dist/isa/isa.5 (revision 282911) @@ -1,366 +1,365 @@ .\" 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 AND 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: isa.5 2900 2013-01-16 12:27:01Z jkoshy $ +.\" $Id: isa.5 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd January 16, 2013 .Os .Dt ISA 1 .Sh NAME .Nm isa .Nd input file format for the isa utility .Sh DESCRIPTION The .Nm utility is used to generate instruction stream encoders and decoders from a textual description of a machine instruction set. This manual page documents the form of the textual description accepted by the .Nm utility. .Ss Basic Concepts A machine instruction is composed of one .Em tokens , each kind of token having a defined width. Simple RISC-like instruction sets have instructions that use 1 or 2 tokens, typically an instruction word and an optional immediate field. More complex CISC instruction sets may use many more kinds of tokens. .Pp Each token is made up of .Em fields , for example, an instruction token could be made up of an opcode field, additional fields naming registers, fields containing flags, immediate values and so on. Fields may be named using the .Cm let directive, or can be unnamed. The bitslice operator .Pq Li \&[] can be used to denote specific portions of a token. .Pp Non-overlapping fields are grouped together into .Em fragments . Fragments may be composed using the .Dq "&" operator. The textual form of a fragment may be specified using the .Li names directive. .Pp A set of fragments that fully specifies each bit in a token is said to be .Sq complete . Only complete fragment sets can be emitted. .Pp .Ss Input Syntax The semicolon .Dq "\&;" introduces a comment. All text from the semicolon to the end of the line is ignored. .Pp The language uses indentation to specify scope (i.e., it uses the offside rule), as in the .Ic Python and .Ic Haskell programming languages. .Ss Operators .Bl -tag .It "Composing Fragments" The .Dq Li \&& operator is used to join fragments, forming a larger fragment. For example, to specify a fragment that is comprised of two previously named fragments .Ar Rtop and .Ar Rbottom , use: .Bd -literal -offset indent Rtop & Rbottom .Ed .It "Generators" A generator expression has the form .Li [ Ar expr1 Ns Li \&| Ns Ar expr2 Ns \&... Ns Li ] and denotes a sequence of values .Va expr1 , where the additional expressions .Va expr2 serve to define the range of values generated. Any .Dq Li \&% Ns -escapes in .Va expr1 are expanded. For example, .Dl [ R%n | n = 0..31 ] generates the sequence .Li R0 , .Li R1 , \&... , .Li R31 . .It "Numeric Ranges" The notation .Dq \&.. denotes a numeric range. For example, .Dl 0..(2^16-1) represents the numbers 0 to 65535, inclusive. .It Sequences Sequences of items are bracketed by square brackets .Dq "\&[" and .Dq "\&]" . For example, .Dl "let n = [ a b c d ]" Sequences can be given a local name using the .Va name .Li @ .Va sequence syntax, for example: .Dl bar@[ 1 2 3 ] defines .Va bar as a local name for the expression [ 1 2 3 ]. .Pp The .Dq Li \&++ operator is used to concatenate sequences. These sequences must be of the same type. .It "Sequencing Tokens" The .Dq Li \&<+> operator separates tokens in sequence. For example, to specify an instruction that has two tokens T1 and T2 in sequence, use: .Bd -literal -offset indent \&..the definition of T1.. <+> \&..the definition of T2.. .Ed .It Slices Slices may be specified using the slice notation, namely .Ar name Ns .Li \&[ Ns .Ar highbit Ns .Li \&: Ns .Ar lowbit Ns .Li \&] , where .Ar highbit and .Ar lowbit are inclusive zero-based indices and .Ar name is the name of a token. .Bd -literal -offset indent let Rsrc = instruction[3:0] .Ed .Pp Sparse slices may be specified by separating slice expressions using commas, for example bit 7 and 5 of the .Va ifield token may be specified using: .Dl ifield[7,5] .It "Specifying Assembly Formats" The .Dq Li \&<=> infix operator is used to specify assembly language syntax and its mapping to sequences of fragments defined earlier, see the section .Sx "Defining Assembly Syntax" . .Pp The .Dq Li \&&* operator indicates that all the named fragments in the LHS (the assembly syntax side) of the .Dq Li \&<=> operator should be treated as being present on the RHS. This operator allows instructions that have a simple one-to-one mapping between their assembly language definition and instruction encoding to be described succinctly. For example: .Bd -literal -offset indent muls %Rd, %Rs <=> i[15:8] = 0b00000010 &* .Ed .El .Ss Language Constructs The input language has the following constructs: .Bl -tag -width indent .It Li arch Ar string Specifies the name of the instruction set architecture being processed. .Bd -literal -offset indent arch myarch .Ed .It Li cpus Starts a block naming CPU identifiers. Specific instructions or groups of instructions may be flagged as being supported on sets of the CPUs so declared. .Bd -literal -offset indent cpus basic = [ CPU1 CPU2 ] advanced = basic ++ [ CPU3 ] .Ed .It Li token Ar name "(" Ar width ")" Defines a token with name .Ar name and width .Ar width . For example, to define a 16 bit named .Ar i (short for .Dq instruction ) , and a 8 bit offset token named .Ar o , use: .Bd -literal -offset indent token i(16) ; a comment here o(8) .Ed .It Li let Ar name [ Ar params ] "=" Ar expression Declare .Ar name as being the equivalent of .Ar expression . .It Li names Ar generator-expression Defines the textual representation for a fragment. For example, .Bd -literal -offset indent -compact let Rsrc = i[3:0] names [ R%n | n = 0..7 ] .Ed specifies that a value of 0 for fragment .Va Rsrc should be shown as .Li R0 , and so on. Conversely, when assembing text, the string .Dq R15 would be translated to a fragment value of 15. .It Li where Ar name [ Ar params ] = Ar expression Like the .Li let statement, a .Li where statement introduces local definitions, except that the scope of these definitions is the statement preceding the .Li where keyword. Example: .Bd -literal -offset indent let Kimm6 = Kimm6high & Kimm6low where Kimm6[5:4] = Kimm6high Kimm6[3:0] = Kimm6low .Ed .It Li with Ar fragment-definition Defines fragment assignments that hold for statements in the scope of the .Li with statement. For example, .Bd -literal -offset indent with i[15:8] = 0b00000011 fmulsu %Rd, %Rs <=> i[7,3] = [1,1] &* .Ed .El .Ss Defining Assembly Syntax Assembly syntax is described using the .Li \&<=> operator. The form of the operator is .Bd -ragged -offset indent assembler-text .Li \&<=> .Va fragment .Li \&& .Va fragment .Li & \&... .Ed .Pp The RHS of the .Li \&<=> operator must specify a .Sq complete fragment set, i.e., no bits should be unspecified in any of the tokens used in the RHS. The LHS of the .Li \&<=> operator consists of literal text interspersed by fragment names. Fragment names are prefixed by the .Sq \&% character. These fragment names in the LHS may refer to fragment names defined earlier, or may be new names that are local to the current definition. .Pp For example, the following definition defines an instruction with mnemonic .Dq Li rjmp . .Bd -literal -offset indent let reloffset = i[11:0] reljmpcall = i[12] in with i[15:13] = 0b110 rjmp %label <=> reljmpcall = 0 & reloffset = (label - . - 1) .Ed .Pp In this definition, the field .Va label is a local fragment, one that is used to compute the value of the .Va reloffset field in the instruction. In the RHS, the .Va reljmpcall bit is defined as being 0. The rest of the bits in the token .Va i are specified by the enclosing .Li with statement. .Sh SEE ALSO .Xr elf 3 , .Xr elf 5 , .Xr isa 1 .Sh HISTORY The .Nm utility is scheduled to appear in a future release from the Elftoolchain project. .\" TODO Reword the above when the target release is finalized. .Sh AUTHORS The .Xr isa 1 utility was written by -.An Joseph Koshy -.Aq jkoshy@users.sourceforge.net . +.An Joseph Koshy Aq Mt jkoshy@users.sourceforge.net . .Sh BUGS The .Nm utility is .Ud The input format documented in this manual is likely to change in the future. If you intend to use this utility, please get in touch with the project's developers at .Aq elftoolchain-developers@lists.sourceforge.net . Index: vendor/elftoolchain/dist/libdwarf/dwarf.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf.3 (revision 282911) @@ -1,753 +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 3130 2014-12-21 20:06:29Z jkoshy $ +.\" $Id: dwarf.3 3195 2015-05-12 17:22:19Z emaste $ .\" .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 +.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 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 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_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 , Fn dwarf_offdie_b Retrieve a debugging information entry given an offset. .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 +Retrieve 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 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 .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 +.An John Birrell Aq Mt jb@FreeBSD.org for the FreeBSD project. The implementation was subsequently revised and completed by -.An "Kai Wang" Aq kaiwang27@users.sourceforge.net . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . .Pp Manual pages for this implementation were written by -.An "Joseph Koshy" Aq jkoshy@users.sourceforge.net +.An Joseph Koshy Aq Mt jkoshy@users.sourceforge.net and -.An "Kai Wang" Aq kaiwang27@users.sourceforge.net . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: vendor/elftoolchain/dist/libdwarf/dwarf_add_line_entry.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_add_line_entry.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_add_line_entry.3 (revision 282911) @@ -1,163 +1,164 @@ .\" 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_add_line_entry.3 2953 2013-06-30 20:21:38Z kaiwang27 $ +.\" $Id: dwarf_add_line_entry.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd June 30, 2013 .Os .Dt DWARF_ADD_LINE_ENTRY 3 .Sh NAME .Nm dwarf_add_line_entry .Nd add a line number information entry to a producer instance .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft "Dwarf_Unsigned" .Fo dwarf_add_line_entry .Fa "Dwarf_P_Debug dbg" .Fa "Dwarf_Unsigned filendx" .Fa "Dwarf_Addr off" .Fa "Dwarf_Unsigned lineno" .Fa "Dwarf_Signed column" .Fa "Dwarf_Bool is_stmt" .Fa "Dwarf_Bool basic_block" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_add_line_entry adds a line number information entry to a DWARF producer instance. .Pp Argument .Ar dbg should reference a DWARF producer instance allocated using .Xr dwarf_producer_init 3 or .Xr dwarf_producer_init_b 3 . .Pp Argument .Ar filendx specifies the index of the source file that contains the source line in question. Valid source file indices are those returned by the function .Xr dwarf_add_file_decl 3 . .Pp Argument .Ar off -specifies a relocatable program address. The ELF symbol to be used +specifies a relocatable program address. +The ELF symbol to be used for relocation is set by a prior call to the function .Xr dwarf_lne_set_address 3 . .Pp Argument .Ar lineno specifies the line number of the source line. .Pp Argument .Ar column specifies the column number within the source line. .Pp If the argument .Ar is_stmt is set to true, it indicates that the instruction at the address specified by argument .Ar off is a recommended breakpoint location, i.e., the first instruction in the instruction sequence generated by the source line. .Pp If the argument .Ar basic_block is set to true, it indicates that the instruction at the address specified by argument .Ar off is the first instruction of a basic block. .Pp If argument .Ar err is not NULL, it will be used to store error information in case of an error. .Sh RETURN VALUES On success, function .Fn dwarf_add_line_entry returns .Dv DW_DLV_OK . In case of an error, function .Fn dwarf_add_line_entry returns .Dv DW_DLV_NOCOUNT and sets the argument .Ar err . .Sh ERRORS Function .Fn dwarf_add_line_entry can fail with: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Argument .Ar dbg was NULL. .It Bq Er DW_DLE_ARGUMENT The function .Xr dwarf_lne_set_address 3 was not called before calling this function. .It Bq Er DW_DLE_MEMORY An out of memory condition was encountered during the execution of the function. .El .Sh EXAMPLE To add line number information to the producer instance, use: .Bd -literal -offset indent Dwarf_P_Debug dbg; Dwarf_Error de; Dwarf_Unsigned dir, filendx; /* ... assume dbg refers to a DWARF producer instance ... */ dir = dwarf_add_directory_decl(dbg, "/home/foo", &de); if (dir == DW_DLV_NOCOUNT) errx(EXIT_FAILURE, "dwarf_add_directory_decl failed: %s", dwarf_errmsg(-1)); filendx = dwarf_add_file_decl(dbg, "bar.c", dir, 0, 1234, &de); if (filendx == DW_DLV_NOCOUNT) errx(EXIT_FAILURE, "dwarf_add_file_decl failed: %s", dwarf_errmsg(-1)); if (dwarf_lne_set_address(dbg, 0x4012b0, 12, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_lne_set_address failed: %s", dwarf_errmsg(-1)); if (dwarf_add_line_entry(dbg, filendx, 10, 258, 0, 1, 1, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_add_line_entry failed: %s", dwarf_errmsg(-1)); .Ed .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_add_directory_decl 3 , .Xr dwarf_add_file_decl 3 , .Xr dwarf_lne_end_sequence 3 , .Xr dwarf_lne_set_address 3 , .Xr dwarf_producer_init 3 , .Xr dwarf_producer_init_b 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_def_macro.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_def_macro.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_def_macro.3 (revision 282911) @@ -1,129 +1,129 @@ .\" 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_def_macro.3 2122 2011-11-09 15:35:14Z jkoshy $ +.\" $Id: dwarf_def_macro.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd November 9, 2011 .Os .Dt DWARF_DEF_MACRO 3 .Sh NAME .Nm dwarf_def_macro .Nd add a macro definition to a DWARF producer instance .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft "int" .Fo dwarf_def_macro .Fa "Dwarf_P_Debug dbg" .Fa "Dwarf_Unsigned lineno" .Fa "char *name" .Fa "char *value" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_def_macro adds a macro definition to a DWARF producer instance. .Pp Argument .Ar dbg should reference a DWARF producer instance allocated using .Xr dwarf_producer_init 3 or .Xr dwarf_producer_init_b 3 . .Pp Argument .Ar lineno specifies the line number of the source line where the macro is defined. A line number of zero is used for macros that are defined before any source file is read. .Pp Argument .Ar name should point to a NUL-terminated string containing the name of the macro. For function-like macros this parameter should also include parentheses and parameter names if any. .Pp Argument .Ar value should point to a NUL-terminated string containing the value of the macro. -If the macro doesn't have a value, argument +If the macro does not have a value, argument .Ar value should be set to NULL. .Pp If argument .Ar err is not NULL, it will be used to store error information in case of an error. .Sh RETURN VALUES On success, function .Fn dwarf_def_macro returns .Dv DW_DLV_OK . In case of an error, function .Fn dwarf_def_macro returns .Dv DW_DLV_ERROR and sets the argument .Ar err . .Sh EXAMPLE To record the fact that a macro named .Dv _STDIO_H_ was defined at line 20 of the current macro file, use: .Bd -literal -offset indent Dwarf_P_Debug dbg; Dwarf_Error de; /* ... Assume 'dbg' refers to a DWARF producer instance... */ if (dwarf_def_macro(dbg, 20, "_STDIO_H_", NULL, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_def_macro failed: %s", dwarf_errmsg(-1)); .Ed .Sh ERRORS Function .Fn dwarf_def_macro can fail with: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Either arguments .Ar dbg or .Ar name was NULL. .It Bq Er DW_DLE_MEMORY An out of memory condition was encountered during the execution of the function. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_end_macro_file 3 , .Xr dwarf_producer_init 3 , .Xr dwarf_producer_init_b 3 , .Xr dwarf_start_macro_file 3 , .Xr dwarf_undef_macro 3 , .Xr dwarf_vendor_ext 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_expand_frame_instructions.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_expand_frame_instructions.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_expand_frame_instructions.3 (revision 282911) @@ -1,182 +1,182 @@ .\" 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_expand_frame_instructions.3 2122 2011-11-09 15:35:14Z jkoshy $ +.\" $Id: dwarf_expand_frame_instructions.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd November 9, 2011 .Os .Dt DWARF_EXPAND_FRAME_INSTRUCTIONS 3 .Sh NAME .Nm dwarf_expand_frame_instructions -.Nd expand frame instructions +.Nd expand frame instructions .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_expand_frame_instructions .Fa "Dwarf_Cie cie" .Fa "Dwarf_Ptr instructions" .Fa "Dwarf_Unsigned len" .Fa "Dwarf_Frame_Op **ret_ops" .Fa "Dwarf_Signed *ret_opcnt" .Fa "Dwarf_Error *error" .Fc .Sh DESCRIPTION Function .Fn dwarf_expand_frame_instructions translates DWARF frame instruction bytes into an array of .Vt Dwarf_Frame_Op descriptors. .Pp Argument .Ar cie should reference the CIE descriptor associated with the instructions to be translated. .Pp Arugment .Ar instructions should point to an array of frame instruction bytes, as returned by the functions .Xr dwarf_get_cie_info 3 or .Xr dwarf_get_fde_instr_bytes 3 . .Pp Argument .Ar len should specify the number of the frame instruction bytes to be translated. .Pp Argument .Ar ret_ops should point to a location that will be set to a pointer to an array of translated .Vt Dwarf_Frame_Op descriptors. .Pp Argument .Ar ret_opcnt should point to a location that will hold the total number of the returned descriptors. .Pp If argument .Ar err is not NULL, it will be used to store error information in case of an error. .Ss Memory Management The memory area used for the descriptor array returned in argument .Ar ret_ops is allocated by .Lb libdwarf . Application code should use function .Xr dwarf_dealloc 3 with type .Dv DW_DLA_FRAME_BLOCK to free the memory area when the descriptor array is no longer needed. .Sh RETURN VALUES Function .Fn dwarf_expand_frame_instructions returns .Dv DW_DLV_OK when it succeeds. In case of an error, it returns .Dv DW_DLV_ERROR and sets the argument .Ar err . .Sh ERRORS Function .Fn dwarf_expand_frame_instructions can fail with: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT One of the arguments .Ar cie , .Ar instructions , .Ar ret_ops or .Ar ret_opcnt was NULL. .It Bq Er DW_DLE_ARGUMENT Argument .Ar len was 0. .It Bq Er DW_DLE_MEMORY An out of memory condition was encountered during the execution of this function. .It Bq Er DW_DLE_FRAME_INSTR_EXEC_ERROR An unknown instruction was found in the instruction bytes provided in argument .Ar instructions . .El .Sh EXAMPLE To retrieve and expand the frame instructions for a given FDE descriptor, use: .Bd -literal -offset indent Dwarf_Dbg dbg; Dwarf_Cie cie; Dwarf_Fde fde; Dwarf_Ptr fde_inst; Dwarf_Unsigned fde_instlen; Dwarf_Frame_Op *ops; Dwarf_Signed opcnt; Dwarf_Error de; /* ... assuming `dbg` references a valid DWARF debugging context, `fde` references a valid FDE descriptor and `cie` holds the CIE descriptor associated with the FDE descriptor ... */ if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_instlen, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_get_fde_instr_bytes failed: %s", dwarf_errmsg(de)); if (dwarf_expand_frame_instructions(cie, fde_inst, fde_instlen, &ops, &opcnt, &de) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_expand_frame_instructions failed: %s", dwarf_errmsg(de)); for (i = 0; i < opcnt; i++) { /* ... use ops[i] ... */ } /* Free the memory area when no longer needed. */ dwarf_dealloc(dbg, ops, DW_DLA_FRAME_BLOCK); .Ed .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_frame_instructions_dealloc 3 , .Xr dwarf_get_cie_info 3 , .Xr dwarf_get_cie_index 3 , .Xr dwarf_get_cie_of_fde , .Xr dwarf_get_fde_at_pc 3 , .Xr dwarf_get_fde_info_for_all_regs 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_reg 3 , .Xr dwarf_get_fde_info_for_reg3 3 , .Xr dwarf_get_fde_instr_bytes 3 , .Xr dwarf_get_fde_list 3 , .Xr dwarf_get_fde_list_eh 3 , .Xr dwarf_get_fde_n 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_formblock.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_formblock.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_formblock.3 (revision 282911) @@ -1,109 +1,109 @@ .\" 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: dwarf_formblock.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_formblock.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd July 23, 2010 .Os .Dt DWARF_FORMBLOCK 3 .Sh NAME .Nm dwarf_formblock .Nd return the value of a BLOCK attribute .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_formblock .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Block **ret" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_formblock sets the location pointed to by argument .Ar ret to a pointer to a .Vt Dwarf_Block structure containing the value of the attribute referenced by argument .Ar attr . The form of argument .Ar attr must be one of .Dv DW_FORM_block , .Dv DW_FORM_block1 , .Dv DW_FORM_block2 or .Dv DW_FORM_block4 . .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case of an error. .Ss Memory Management The memory area referenced by the returned pointer is managed by the DWARF(3) library. The application should not attempt to free this memory area. Portable code may indicate that the memory area is to be freed by -by using +using .Xr dwarf_dealloc 3 . .Sh RETURN VALUES Function .Fn dwarf_formblock returns .Dv DW_DLV_OK on success. In case of an error, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . .Sh ERRORS Function .Fn dwarf_formblock may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ATTR_FORM_BAD" .It Bq Er DW_DLE_ARGUMENT Either of arguments .Ar attr or .Ar ret was NULL. .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute referenced by argument .Ar attr was not of a permitted kind. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_formflag 3 , .Xr dwarf_formref 3 , .Xr dwarf_formsdata 3 , .Xr dwarf_formsig8 3 , .Xr dwarf_formstring 3 , .Xr dwarf_formudata 3 , .Xr dwarf_hasattr 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_formflag.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_formflag.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_formflag.3 (revision 282911) @@ -1,97 +1,97 @@ .\" 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: dwarf_formflag.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_formflag.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd June 21, 2010 .Os .Dt DWARF_FORMFLAG 3 .Sh NAME .Nm dwarf_formflag .Nd return the value of a BOOLEAN class attribute .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_formflag .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Bool *ret" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_formflag sets the location pointed to by argument .Ar ret to 1 if the attribute referenced by argument .Ar attr has a non-zero value, or 0 otherwise. The form of argument .Ar attr must be one of .Dv DW_FORM_flag or .Dv DW_FORM_flag_present . .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Sh RETURN VALUES Function .Fn dwarf_formflag returns .Dv DW_DLV_OK on success. In case of an error, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . .Sh ERRORS Function .Fn dwarf_formflag may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ATTR_FORM_BAD" .It Bq Er DW_DLE_ARGUMENT Either of arguments .Ar attr or .Ar ret was NULL. .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute referenced by argument .Ar attr was not of a permitted kind. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_formblock 3 , .Xr dwarf_formref 3 , .Xr dwarf_formsdata 3 , .Xr dwarf_formsig8 3 , .Xr dwarf_formstring 3 , .Xr dwarf_formudata 3 , .Xr dwarf_hasattr 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_formref.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_formref.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_formref.3 (revision 282911) @@ -1,136 +1,136 @@ .\" 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: dwarf_formref.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_formref.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd June 21, 2010 .Os .Dt DWARF_FORMREF 3 .Sh NAME .Nm dwarf_formref , .Nm dwarf_global_formref .Nd retrieve offsets for REFERENCE class attributes .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_formref .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Off *retoffset" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_global_formref .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Off *retoffset" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION These functions return the offsets associated with a DWARF attribute descriptor. .Pp Function .Fn dwarf_formref returns the compilation unit relative offset of the descriptor referenced by argument .Ar attr in the location pointed to by argument .Ar retoffset . Argument .Ar attr must be a reference that is local to a compilation unit. Permitted forms for argument .Ar attr are .Dv DW_FORM_ref1 , .Dv DW_FORM_ref2 , .Dv DW_FORM_ref4 , .Dv DW_FORM_ref8 and .Dv DW_FORM_ref_udata . .Pp Function .Fn dwarf_global_formref returns the section-relative offset of the descriptor referenced by argument .Ar attr in the location pointed to by argument .Ar retoffset . Argument .Ar attr should be a legal .Sy REFERENCE class form. Permitted forms for argument .Ar attr are: .Dv DW_FORM_ref_addr , .Dv DW_FORM_ref_udata , .Dv DW_FORM_ref1 , .Dv DW_FORM_ref2 , .Dv DW_FORM_ref4 , .Dv DW_FORM_ref8 and .Dv DW_FORM_sec_offset . The returned offset is relative to the start of the .Dq .debug_info ELF section. .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Sh RETURN VALUES These functions return .Dv DW_DLV_OK on success. In case of an error, these functions return .Dv DW_DLV_ERROR and sets argument .Ar err . .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 arguments .Ar attr or .Ar retoffset was NULL. .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute referenced by argument .Ar attr was not of a permitted kind. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_formblock 3 , .Xr dwarf_formflag 3 , .Xr dwarf_formsdata 3 , .Xr dwarf_formsig8 3 , .Xr dwarf_formstring 3 , .Xr dwarf_formudata 3 , .Xr dwarf_hasattr 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_formsig8.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_formsig8.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_formsig8.3 (revision 282911) @@ -1,96 +1,96 @@ .\" 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: dwarf_formsig8.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_formsig8.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd July 24, 2010 .Os .Dt DWARF_FORMSIG8 3 .Sh NAME .Nm dwarf_formsig8 .Nd return the 64-bit type signature for a DWARF type .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_formsig8 .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Sig8 *ret" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_formsig8 sets the location pointed to by argument .Ar ret to the 64-bit type signature that is the value of the attribute referenced by argument .Ar attr . The form of argument .Ar attr must be .Dv DW_FORM_ref_sig8 . .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Sh RETURN VALUES Function .Fn dwarf_formsig8 returns .Dv DW_DLV_OK on success. In case of an error, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . .Sh ERRORS Function .Fn dwarf_formsig8 may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ATTR_FORM_BAD" .It Bq Er DW_DLE_ARGUMENT Either of arguments .Ar attr or .Ar ret was NULL. .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute referenced by argument .Ar attr was not of a permitted kind. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_formflag 3 , .Xr dwarf_formref 3 , .Xr dwarf_formsdata 3 , .Xr dwarf_formstring 3 , .Xr dwarf_formudata 3 , .Xr dwarf_hasattr 3 .Sh HISTORY Type signatures were added in version 4 of the DWARF specification. Index: vendor/elftoolchain/dist/libdwarf/dwarf_formudata.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_formudata.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_formudata.3 (revision 282911) @@ -1,122 +1,122 @@ .\" 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: dwarf_formudata.3 2073 2011-10-27 03:30:47Z jkoshy $ +.\" $Id: dwarf_formudata.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd June 21, 2010 .Os .Dt DWARF_FORMUDATA 3 .Sh NAME .Nm dwarf_formudata , .Nm dwarf_formsdata .Nd return the value of a CONSTANT class attribute .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_formudata .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Unsigned *ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_formsdata .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Signed *ret" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION These functions return the value associated with a DWARF attribute describing a constant. .Pp Function .Fn dwarf_formudata sets the location pointed to by argument .Ar ret to the value of the attribute referenced by argument .Ar attr , treating the value as an unsigned quantity. Argument .Ar attr must have one of the following forms: .Dv DW_FORM_data1 , .Dv DW_FORM_data2 , .Dv DW_FORM_data4 , .Dv DW_FORM_data8 and .Dv DW_FORM_udata . .Pp Function .Fn dwarf_formsdata sets the location pointed to by argument .Ar ret to the value of the attribute referenced by argument .Ar attr , appropriately sign extended. Argument .Ar attr must have one of the following forms: .Dv DW_FORM_data1 , .Dv DW_FORM_data2 , .Dv DW_FORM_data4 , .Dv DW_FORM_data8 and .Dv DW_FORM_sdata . .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Sh RETURN VALUES These functions return .Dv DW_DLV_OK on success. In case of an error, they return .Dv DW_DLV_ERROR and set argument .Ar err . .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 arguments .Ar attr or .Ar ret was NULL. .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute referenced by argument .Ar attr was not of a permitted kind. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_formblock 3 , .Xr dwarf_formflag 3 , .Xr dwarf_formref 3 , .Xr dwarf_formsig8 3 , .Xr dwarf_formstring 3 , .Xr dwarf_hasattr 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_get_fde_info_for_all_regs.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_get_fde_info_for_all_regs.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_get_fde_info_for_all_regs.3 (revision 282911) @@ -1,155 +1,156 @@ .\" 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_get_fde_info_for_all_regs.3 2071 2011-10-27 03:20:00Z jkoshy $ +.\" $Id: dwarf_get_fde_info_for_all_regs.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd June 4, 2011 .Os .Dt DWARF_GET_FDE_INFO_FOR_ALL_REGS 3 .Sh NAME .Nm dwarf_get_fde_info_for_all_regs .Nd retrieve register rule row .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_get_fde_info_for_all_regs .Fa "Dwarf_Fde fde" .Fa "Dwarf_Addr pc" .Fa "Dwarf_Regtable *reg_table" .Fa "Dwarf_Addr *row_pc" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_get_fde_info_for_all_regs retrieves a row from the register rule table associated with the given FDE descriptor. .Pp Argument .Ar fde should reference a valid DWARF FDE descriptor. .Pp Argument .Ar pc should hold the program counter address to be used to locate the desired table row. .Pp Argument .Ar reg_table should point to a .Vt Dwarf_Regtable descriptor which will hold the returned table row of register rules. .Pp Argument .Ar row_pc should point to a location which will be set to the lowest program counter address associated with the table row. .Pp If argument .Ar err is not NULL, it will be used to store error information in case of an error. .Pp The .Vt Dwarf_Regtable descriptor is defined in the header file .In libdwarf.h : .Bd -literal -offset indent typedef struct { struct { Dwarf_Small dw_offset_relevant; Dwarf_Half dw_regnum; Dwarf_Addr dw_offset; } rules[DW_REG_TABLE_SIZE]; } Dwarf_Regtable; .Ed .Pp For each of the register rules returned, the .Va dw_offset_relevant -field is set to 1 if the register rule has a offset value. The +field is set to 1 if the register rule has a offset value. +The .Va dw_regnum field is set to the register number associated with the regsiter rule. The .Va dw_offset field is set to the offset value associated with the register rule. .Pp The number of register columns returned is either the constant value .Dv DW_REG_TABLE_SIZE as defined in the header file .In libdwarf.h , or the value set by function .Xr dwarf_set_frame_rule_table_size 3 , whichever is smaller. .Ss COMPATIBILITY Function .Fn dwarf_get_fde_info_for_all_regs is deprecated since it only supports DWARF2 frame sections. Applications should instead use function .Xr dwarf_get_fde_info_for_all_regs3 3 which supports both DWARF2 and DWARF3 frame sections. .Sh RETURN VALUES Function .Fn dwarf_get_fde_info_for_all_regs returns .Dv DW_DLV_OK when it succeeds. In case of an error, it returns .Dv DW_DLV_ERROR and sets the argument .Ar err . .Sh ERRORS Function .Fn dwarf_get_fde_info_for_all_regs can fail with: .Bl -tag -width ".Bq Er DW_DLE_PC_NOT_IN_FDE_RANGE" .It Bq Er DW_DLE_ARGUMENT One of the arguments .Ar fde , .Ar reg_table or .Ar row_pc was NULL. .It Bq Er DW_DLE_PC_NOT_IN_FDE_RANGE The program counter value provided in argument .Ar pc did not fall in the range covered by argument .Ar fde . .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_get_fde_at_pc 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_reg 3 , .Xr dwarf_get_fde_info_for_reg3 3 , .Xr dwarf_get_fde_n 3 , .Xr dwarf_set_frame_cfa_value 3 , .Xr dwarf_set_frame_rule_table_size 3 , .Xr dwarf_set_frame_rule_initial_value 3 , .Xr dwarf_set_frame_same_value 3 , .Xr dwarf_set_frame_undefined_value 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_get_fde_info_for_reg.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_get_fde_info_for_reg.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_get_fde_info_for_reg.3 (revision 282911) @@ -1,156 +1,156 @@ .\" 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_get_fde_info_for_reg.3 2071 2011-10-27 03:20:00Z jkoshy $ +.\" $Id: dwarf_get_fde_info_for_reg.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd June 4, 2011 .Os .Dt DWARF_GET_FDE_INFO_FOR_REG 3 .Sh NAME .Nm dwarf_get_fde_info_for_reg .Nd retrieve register rule .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_get_fde_info_for_reg .Fa "Dwarf_Fde fde" .Fa "Dwarf_Half table_column" .Fa "Dwarf_Addr pc" .Fa "Dwarf_Signed *offset_relevant" .Fa "Dwarf_Signed *register_num" .Fa "Dwarf_Signed *offset" .Fa "Dwarf_Addr *row_pc" .Fa "Dwarf_Error *error" .Fc .Sh DESCRIPTION Function .Fn dwarf_get_fde_info_for_reg retrieves a register rule from the register rule table associated with a given FDE descriptor, given a program counter address and rule column number. .Pp Argument .Ar fde should reference a valid DWARF FDE descriptor. .Pp Arugment .Ar table_column should hold the column number of the register rule desired. .Pp Argument .Ar pc should hold the program counter address to be used to locate the desired register rule row. .Pp On successful execution, .Fn dwarf_get_fde_info_for_reg stores information about the register rule found into the locations pointed to by the arguments .Ar offset_relevant , .Ar register_num , .Ar offset and .Ar row_pc . .Pp If there is an offset value associated with the register rule, the location pointed to by argument .Ar offset_relevant will be set to 1. .Pp Argument .Ar register_num should point to a location which will hold the register number associated with the register rule. .Pp Argument .Ar offset should point to a location which will be set to the offset value associated with the register rule, or to 0 if the register rule does not have an offset value. .Pp Argument .Ar row_pc should point to a location which will be set to the lowest program counter address associated with the register rule found. .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Ss COMPATIBILITY Function .Fn dwarf_get_fde_info_for_reg is deprecated since it only supports DWARF2 frame sections. Applications should instead use function .Xr dwarf_get_fde_info_for_reg3 3 which supports both DWARF2 and DWARF3 frame sections. .Sh RETURN VALUES Function .Fn dwarf_get_fde_info_for_reg returns .Dv DW_DLV_OK when it succeeds. In case of an error, it returns .Dv DW_DLV_ERROR and sets the argument .Ar err . .Sh ERRORS Function .Fn dwarf_get_fde_info_for_reg can fail with: .Bl -tag -width ".Bq Er DW_DLE_FRAME_TABLE_COL_BAD" .It Bq Er DW_DLE_ARGUMENT One of the arguments .Ar fde , .Ar offset_relevant , .Ar register_num , .Ar offset or .Ar row_pc was NULL. .It Bq Er DW_DLE_FRAME_TABLE_COL_BAD The column number provided in argument .Ar table_column was too large. .It Bq Er DW_DLE_PC_NOT_IN_FDE_RANGE The program counter value provided in argument .Ar pc did not fall in the range covered by argument .Ar fde . .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_get_fde_at_pc 3 , .Xr dwarf_get_fde_info_for_all_regs 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_fde_n 3 , .Xr dwarf_set_frame_cfa_value 3 , .Xr dwarf_set_frame_rule_table_size 3 , .Xr dwarf_set_frame_rule_initial_value 3 , .Xr dwarf_set_frame_same_value 3 , .Xr dwarf_set_frame_undefined_value 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_get_ranges.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_get_ranges.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_get_ranges.3 (revision 282911) @@ -1,258 +1,258 @@ .\" 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_get_ranges.3 2122 2011-11-09 15:35:14Z jkoshy $ +.\" $Id: dwarf_get_ranges.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd November 9, 2011 .Os .Dt DWARF_GET_RANGES 3 .Sh NAME .Nm dwarf_get_ranges .Nd retrieve non-contiguous address ranges .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_get_ranges .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Off offset" .Fa "Dwarf_Ranges **ranges" .Fa "Dwarf_Signed *cnt" .Fa "Dwarf_Unsigned *byte_cnt" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_get_ranges_a .Fa "Dwarf_Debug dbg" .Fa "Dwarf_Off offset" .Fa "Dwarf_Die die" .Fa "Dwarf_Ranges **ranges" .Fa "Dwarf_Signed *cnt" .Fa "Dwarf_Unsigned *byte_cnt" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_get_ranges retrieves information about the non-contiguous address ranges associated with a DWARF debugging information entry. Information about address ranges is returned as an array of descriptors of type .Vt Dwarf_Ranges , with each .Vt Dwarf_Ranges descriptor describing one address range entry. .Pp Argument .Ar dbg should reference a DWARF debug context allocated using .Xr dwarf_init 3 . .Pp Argument .Ar offset is an offset, relative to the .Dq ".debug_ranges" section, to the start of the desired list of address ranges. The offset of an address ranges list is indicated by the .Dv DW_AT_ranges attribute of a debugging information entry. .Pp Argument .Ar die (function .Fn dwarf_get_ranges_a only) is ignored in this implementation; see the section .Sx "Compatibility Notes" below. .Pp Argument .Ar ranges should point to a location that will be set to a pointer to an array of .Vt Dwarf_Ranges descriptors. .Pp Argument .Ar cnt should point to a location that will be set to the number of entries returned. If argument .Ar byte_cnt is not NULL, it will be set to the number of bytes occupied by the returned entries in the .Dq ".debug_ranges" section. .Pp If argument .Ar err is not NULL, it will be used to store error information in case of an error. .Pp .Vt Dwarf_Ranges descriptors are defined in the header file .In libdwarf.h , and consists of the following fields: .Bl -tag -width ".Va dwr_addr1" .It Va dwr_addr1 The first address offset, whose meaning depends on the type of the entry. .It Va dwr_addr2 The second address offset, whose meaning depends on the type of the entry. .It Va dwr_type The type of this address range entry: .Bl -tag -width ".Dv DW_RANGES_ENTRY" -compact .It Dv DW_RANGES_ENTRY A range list entry. For this type of entry, the fields .Va dwr_addr1 and .Va dwr_addr2 hold the beginning and ending offsets of the address range, respectively. .It Dv DW_RANGES_ADDRESS_SELECTION A base address selection entry. For this type of entry, the field .Va dwr_addr1 is the value of the largest representable address offset, and .Va dwr_addr2 -is a base address for the begining and ending address offsets of +is a base address for the beginning and ending address offsets of subsequent address range entries in the list. .It Dv DW_RANGES_END An end of list mark. Both .Va dwr_addr1 and .Va dwr_addr2 are set to 0. .El .El .Ss Memory Management The memory area used for the array of .Vt Dwarf_Ranges descriptors returned in argument .Ar ranges is owned by the .Lb libdwarf . The application should not attempt to directly free this pointer. Portable code should instead use .Fn dwarf_ranges_dealloc to indicate that the memory may be freed. .Sh COMPATIBILITY Function .Fn dwarf_get_ranges_a is identical to .Fn dwarf_get_ranges , except that it requires one additional argument .Ar die denoting the debugging information entry associated with the address range list. In this implementation of the .Lb libdwarf , the argument .Ar die is ignored, and function .Fn dwarf_get_ranges_a is only provided for compatibility with other implementations of the DWARF(3) API. .Sh RETURN VALUES These functions return .Dv DW_DLV_OK when they succeed. They return .Dv DW_DLV_NO_ENTRY if there is no address range list at the specified offset .Ar offset . In case of an error, they return .Dv DW_DLV_ERROR and set the argument .Ar err . .Sh ERRORS These function can fail with: .Bl -tag -width ".Bq Er DW_DLE_NO_ENTRY" .It Bq Er DW_DLE_ARGUMENT One of the arguments .Ar dbg , .Ar ranges or .Ar cnt was NULL. .It Bq Er DW_DLE_NO_ENTRY There is no address range list at the specified offset .Ar offset . .El .Sh EXAMPLE To retrieve the address range list associated with a debugging information entry, use: .Bd -literal -offset indent Dwarf_Debug dbg; Dwarf_Die die; Dwarf_Error de; Dwarf_Addr base; Dwarf_Attribute *attr_list; Dwarf_Ranges *ranges; Dwarf_Signed cnt; Dwarf_Unsigned off, attr_count, bytecnt; int i, j; if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) != DW_DLV_OK) errx(EXIT_FAILURE, "dwarf_attrlist failed: %s", dwarf_errmsg(de)); for (i = 0; (Dwarf_Unsigned) 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(dbg, (Dwarf_Off) off, &ranges, &cnt, &bytecnt, &de) != DW_DLV_OK) continue; for (j = 0; j < cnt; j++) { if (ranges[j].dwr_type == DW_RANGES_END) break; else if (ranges[j].dwr_type == DW_RANGES_ADDRESS_SELECTION) base = ranges[j].dwr_addr2; else { /* * DW_RANGES_ENTRY entry. * .. Use dwr_addr1 and dwr_addr2 .. */ } } } .Ed .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_ranges_dealloc 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_hasattr.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_hasattr.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_hasattr.3 (revision 282911) @@ -1,92 +1,92 @@ .\" 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_hasattr.3 3142 2015-01-29 23:11:14Z jkoshy $ +.\" $Id: dwarf_hasattr.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd April 17, 2010 .Os .Dt DWARF_HASATTR 3 .Sh NAME .Nm dwarf_hasattr .Nd check for the presence of an attribute .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_hasattr .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Bool *ret_bool" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_hasattr tests whether the debugging information entry referenced in argument .Ar die contains the attribute named by argument .Ar attr . Legal values for argument .Ar attr are those denoted by the .Dv DW_AT_* constants in the DWARF specification. .Pp If the named attribute is present in the debugging information entry, function .Fn dwarf_hasattr returns a non-zero value in the location pointed to by argument .Ar ret_bool . If the named attribute is not present, a zero is written instead. .Pp If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Sh RETURN VALUES On success, function .Fn dwarf_hasattr returns .Dv DW_DLV_OK . In case of an error, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . .Sh ERRORS Function .Fn dwarf_hasattr can fail with the following error: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Either of argument .Va die or .Va ret_bool was NULL. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_whatattr 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_next_cu_header.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_next_cu_header.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_next_cu_header.3 (revision 282911) @@ -1,289 +1,288 @@ .\" 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 3128 2014-12-21 20:06:22Z jkoshy $ +.\" $Id: dwarf_next_cu_header.3 3182 2015-04-10 16:08:10Z emaste $ .\" .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_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 or type units associated with a DWARF debug context, optionally returning information about the unit. .Pp Function .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 or type unit. Argument .Ar cu_version should point to a location that will be set to the 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 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 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 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 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 +an internal pointer associated with the context will point to the first .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 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 Index: vendor/elftoolchain/dist/libdwarf/dwarf_producer_init.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_producer_init.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_producer_init.3 (revision 282911) @@ -1,297 +1,297 @@ .\" 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_producer_init.3 2074 2011-10-27 03:34:33Z jkoshy $ +.\" $Id: dwarf_producer_init.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd August 20, 2011 .Os .Dt DWARF_PRODUCER_INIT 3 .Sh NAME .Nm dwarf_producer_init .Nm dwarf_producer_init_b .Nd allocate a DWARF producer descriptor .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft Dwarf_P_Debug .Fo dwarf_producer_init .Fa "Dwarf_Unsigned flags" .Fa "Dwarf_Callback_Func func" .Fa "Dwarf_Handler errhand" .Fa "Dwarf_Ptr errarg" .Fa "Dwarf_Error *err" .Fc .Ft Dwarf_P_Debug .Fo dwarf_producer_init_b .Fa "Dwarf_Unsigned flags" .Fa "Dwarf_Callback_Func_b func" .Fa "Dwarf_Handler errhand" .Fa "Dwarf_Ptr errarg" .Fa "Dwarf_Error *error" .Fc .Sh DESCRIPTION These functions allocate and return a .Vt Dwarf_P_Debug descriptor representing a DWARF producer instance. .Pp The argument .Ar errhand -should contain the adddress of a function to be called in case of an +should contain the address of a function to be called in case of an error. If this argument is .Dv NULL , the default error handling scheme is used, see .Xr dwarf 3 . .Pp The argument .Ar errarg will be passed to the error handler function when it is invoked. .Pp The argument .Ar err references a memory location that would hold a .Vt Dwarf_Error descriptor in case of an error. .Pp The argument .Ar flags specifies additional characteristics of the DWARF producer instance. The following flags are recognized: .Pp .Bl -tag -width "Dv DW_DLC_ISA_MIPS" .It Dv DW_DLC_ISA_IA64 .Pq Deprecated The target instruction set architecture is IA64. This flag is deprecated. Application code should use the .Xr dwarf_producer_set_isa 3 function to specify target instruction set architecture. .It Dv DW_DLC_ISA_MIPS .Pq Deprecated The target instruction set architecture is MIPS. This flag is deprecated. Application code should use the .Xr dwarf_producer_set_isa 3 function to specify target instruction set architecture. .It Dv DW_DLC_SIZE_32 .Pq Default The target address size is 32-bit. .It Dv DW_DLC_SIZE_64 The target address size is 64-bit. .It Dv DW_DLC_STREAM_RELOCATIONS .Pq Default Generate stream relocations. .It Dv DW_DLC_SYMBOLIC_RELOCATIONS Generate symbolic relocations. .It Dv DW_DLC_TARGET_BIGENDIAN The target is big endian. .It Dv DW_DLC_TARGET_LITTLEENDIAN The target is little endian. .It Dv DW_DLC_WRITE .Pq Required Permit writing of DWARF information. .El .Pp The following flags are mutually exclusive. .Bl -bullet -compact .It Flags .Dv DW_DLC_ISA_IA64 and .Dv DW_DLC_ISA_MIPS . .It Flags .Dv DW_DLC_SIZE_32 and .Dv DW_DLC_SIZE_64 . .It Flags .Dv DW_DLC_STREAM_RELOCATIONS and .Dv DW_DLC_SYMBOLIC_RELOCATIONS . .It Flags .Dv DW_DLC_TARGET_BIGENDIAN and .Dv DW_DLC_TARGET_LITTLEENDIAN . .El If neither of the flags .Dv DW_DLC_TARGET_BIGENDIAN and .Dv DW_DLC_TARGET_LITTLEENDIAN is set, the target's endianness is assumed to be the same as the host's endianness. .Pp Argument .Ar func should point to an application-provided callback function of type .Vt Dwarf_Callback_Func_b . The type .Vt Dwarf_Callback_Func_b is defined in the header file .In libdwarf.h as: .Bd -literal -offset indent 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); .Ed .Pp This function is called by the .Lb libdwarf once for each section in the object file that the library needs to create. The arguments to this callback function specify the values in the ELF section header for the section being created: .Pp .Bl -tag -width indent -compact -offset indent .It Ar name The name of the section being created. .It Ar size The .Va sh_size value in the section header. .It Ar type The .Va sh_type value in the section header. .It Ar flags The .Va sh_flags value in the section header. .It Ar link The .Va sh_link value in the section header. .It Ar info The .Va sh_info value in the section header. .El .Pp On success, the callback function should return the section index value of the created section, and set the location pointed to by argument .Ar index to the symbol table index of the symbol that associated with the newly created section. This symbol table index will be used in relocation entries referring to the created section. .Pp In case of failure, the callback function should return -1 and set the location pointed to by argument .Ar error to an application-defined error code. This application returned error code is currently ignored by the library. .Pp Function .Fn dwarf_producer_init is deprecated. Function .Fn dwarf_producer_init is identical to function .Fn dwarf_producer_init_b except that the callback function it expects can not properly handle arbitrary section symbol index values. .Ss Memory Management The .Vt Dwarf_P_Debug instance returned by these functions should be freed using the function .Fn dwarf_producer_finish . .Sh RETURN VALUES On success, these functions return the created DWARF producer descriptor. In case of an error, they return .Dv DW_DLV_BADADDR and set the argument .Ar err . .Sh ERRORS These functions can fail with: .Bl -tag -width ".Bq Er DW_DLE_NO_ENTRY" .It Bq Er DW_DLE_ARGUMENT Argument .Ar func was NULL. .It Bq Er DW_DLE_ARGUMENT The flag .Dv DW_DLC_WRITE was not set in argument .Ar flags . .It Bq Er DW_DLE_ARGUMENT The flags .Dv DW_DLC_SIZE_32 and .Dv DW_DLC_SIZE_64 were both set in argument .Ar flags . .It Bq Er DW_DLE_ARGUMENT The flags .Dv DW_DLC_ISA_IA64 and .Dv DW_DLC_ISA_MIPS were both set in argument .Ar flags . .It Bq Er DW_DLE_ARGUMENT The flags .Dv DW_DLC_TARGET_BIGENDIAN and .Dv DW_DLC_TARGET_LITTLEENDIAN were both set in argument .Ar flags . .It Bq Er DW_DLE_ARGUMENT The flags .Dv DW_DLC_STREAM_RELOCATIONS and .Dv DW_DLC_SYMBOLIC_RELOCATIONS were both set in argument .Ar flags . .It Bq Er DW_DLE_MEMORY An out of memory condition was encountered. .El .Sh EXAMPLES To initialize a .Vt Dwarf_P_Debug instance for a MIPS32 big endian object, use: .Bd -literal -offset indent Dwarf_P_Debug dbg; Dwarf_Unsigned flags; Dwarf_Error de; /* ... assume cb_func points to the callback function ... */ flags = DW_DLC_WRITE | DW_DLC_SIZE_32 | DW_DLC_ISA_MIPS | DW_DLC_STREAM_RELOCATIONS | DW_DLC_TARGET_BIGENDIAN; if ((dbg = dwarf_producer_init(flags, cb_func, NULL, NULL, &de)) == DW_DLV_BADADDR) warnx("dwarf_producer_init failed: %s", dwarf_errmsg(-1)); .Ed .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_errmsg 3 , .Xr dwarf_producer_finish 3 , .Xr dwarf_producer_set_isa 3 , .Xr dwarf_transform_to_disk_form 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_whatattr.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_whatattr.3 (revision 282910) +++ vendor/elftoolchain/dist/libdwarf/dwarf_whatattr.3 (revision 282911) @@ -1,79 +1,79 @@ .\" 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: dwarf_whatattr.3 3142 2015-01-29 23:11:14Z jkoshy $ +.\" $Id: dwarf_whatattr.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd May 22, 2010 .Os .Dt DWARF_WHATATTR 3 .Sh NAME .Nm dwarf_whatattr .Nd retrieve the attribute code for a DWARF attribute .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_whatattr .Fa "Dwarf_Attribute attr" .Fa "Dwarf_Half *retcode" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION Function .Fn dwarf_whatattr retrieves the attribute code for the DWARF attribute referenced by argument .Ar attr , and writes it to the location pointed to by argument .Ar retcode . If argument .Ar err is not NULL, it will be used to return an error descriptor in case -of an error. +of an error. .Sh RETURN VALUES On success, function .Fn dwarf_whatattr returns .Dv DW_DLV_OK . In case of an error, it returns .Dv DW_DLV_ERROR and sets argument .Ar err . .Sh ERRORS Function .Fn dwarf_whatattr can fail with the following error: .Bl -tag -width ".Bq Er DW_DLE_ARGUMENT" .It Bq Er DW_DLE_ARGUMENT Either of argument .Va attr or .Va retcode was NULL. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_hasattr 3 Index: vendor/elftoolchain/dist/libelf/elf.3 =================================================================== --- vendor/elftoolchain/dist/libelf/elf.3 (revision 282910) +++ vendor/elftoolchain/dist/libelf/elf.3 (revision 282911) @@ -1,612 +1,611 @@ .\" 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 3142 2015-01-29 23:11:14Z jkoshy $ +.\" $Id: elf.3 3195 2015-05-12 17:22:19Z emaste $ .\" .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_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 . .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 +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 . +.An Joseph Koshy Aq Mt jkoshy@FreeBSD.org . Index: vendor/elftoolchain/dist/libelf/elf_begin.3 =================================================================== --- vendor/elftoolchain/dist/libelf/elf_begin.3 (revision 282910) +++ vendor/elftoolchain/dist/libelf/elf_begin.3 (revision 282911) @@ -1,315 +1,315 @@ .\" 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_begin.3 2313 2011-12-11 06:19:24Z jkoshy $ +.\" $Id: elf_begin.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd December 11, 2011 .Os .Dt ELF_BEGIN 3 .Sh NAME .Nm elf_begin .Nd open an ELF file or ar(1) archive .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Ft "Elf *" .Fn elf_begin "int fd" "Elf_Cmd cmd" "Elf *elf" .Sh DESCRIPTION Function .Fn elf_begin is used to open ELF files and .Xr ar 1 archives for further processing by other APIs in the .Xr elf 3 library. It is also used to access individual ELF members of an .Xr ar 1 archive in combination with the .Xr elf_next 3 and .Xr elf_rand 3 APIs. .Pp Argument .Ar fd is an open file descriptor returned from an .Xr open 2 system call. Function .Fn elf_begin uses argument .Ar fd for reading or writing depending on the value of argument .Ar cmd . Argument .Ar elf is primarily used for iterating through archives. .Pp The argument .Ar cmd can have the following values: .Bl -tag -width "ELF_C_WRITE" .It ELF_C_NULL Causes .Fn elf_begin to return NULL. Arguments .Ar fd and .Ar elf are ignored, and no additional error is signalled. .It ELF_C_READ This value is to be when the application wishes to examine (but not modify) the contents of the file specified by the arguments .Ar fd and .Ar elf . It can be used for both .Xr ar 1 archives and for ELF objects. .Pp If argument .Ar elf is NULL, the library will allocate a new ELF descriptor for the file being processed. The argument .Ar fd should have been opened for reading. .Pp If argument .Ar elf is not NULL, and references a regular ELF file previously opened with .Fn elf_begin , then the activation count for the descriptor referenced by argument .Ar elf is incremented. The value in argument .Ar fd should match that used to open the descriptor argument .Ar elf . .Pp If argument .Ar elf is not NULL, and references a descriptor for an .Xr ar 1 archive opened earlier with .Fn elf_begin , a descriptor for an element in the archive is returned as described in the section .Sx "Processing ar(1) archives" below. The value for argument .Ar fd should match that used to open the archive earlier. .Pp If argument .Ar elf is not NULL, and references an .Xr ar 1 archive opened earlier with .Fn elf_memory , then the value of the argument .Ar fd is ignored. .It Dv ELF_C_RDWR This command is used to prepare an ELF file for reading and writing. This command is not supported for .Xr ar 1 archives. .Pp Argument .Ar fd should have been opened for reading and writing. If argument .Ar elf is NULL, the library will allocate a new ELF descriptor for the file being processed. If the argument .Ar elf is non-null, it should point to a descriptor previously allocated with .Fn elf_begin with the same values for arguments .Ar fd and .Ar cmd ; in this case the library will increment the activation count for descriptor .Ar elf and return the same descriptor. .Pp Changes to the in-memory image of the ELF file may be written back to disk using the .Xr elf_update 3 function. .It Dv ELF_C_WRITE This command is used when the application wishes to create a new ELF file. Argument .Ar fd should have been opened for writing. Argument .Ar elf is ignored, and the previous contents of file referenced by argument .Ar fd are overwritten. .El .Ss Processing ar(1) archives An .Xr ar 1 archive may be opened in read mode (with argument .Ar cmd set to .Dv ELF_C_READ ) using .Fn elf_begin or .Fn elf_memory . The returned ELF descriptor can be passed into to subsequent calls to .Fn elf_begin to access individual members of the archive. .Pp Random access within an opened archive is possible using the .Xr elf_next 3 and .Xr elf_rand 3 functions. .Pp The symbol table of the archive may be retrieved using .Xr elf_getarsym 3 . .Sh RETURN VALUES The function returns a pointer to a ELF descriptor if successful, or NULL if an error occurred. .Sh EXAMPLES To iterate through the members of an .Xr ar 1 archive, use: .Bd -literal -offset indent Elf_Cmd c; Elf *ar_e, *elf_e; \&... c = ELF_C_READ; if ((ar_e = elf_begin(fd, c, (Elf *) 0)) == 0) { \&... handle error in opening the archive ... } while ((elf_e = elf_begin(fd, c, ar_e)) != 0) { \&... process member referenced by elf_e here ... c = elf_next(elf_e); elf_end(elf_e); } .Ed .Pp To create a new ELF file, use: .Bd -literal -offset indent int fd; Elf *e; \&... if ((fd = open("filename", O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) { \&... handle the error from open(2) ... } if ((e = elf_begin(fd, ELF_C_WRITE, (Elf *) 0)) == 0) { \&... handle the error from elf_begin() ... } \&... create the ELF image using other elf(3) APIs ... elf_update(e, ELF_C_WRITE); elf_end(e); .Ed .Sh ERRORS Function .Fn elf_begin can fail with the following errors: .Bl -tag -width "[ELF_E_RESOURCE]" .It Bq Er ELF_E_ARCHIVE The archive denoted by argument .Ar elf could not be parsed. .It Bq Er ELF_E_ARGUMENT The value in argument .Ar cmd was unrecognized. .It Bq Er ELF_E_ARGUMENT A non-null value for argument .Ar elf was specified when .Ar cmd was set to .Dv ELF_C_RDWR . .It Bq Er ELF_E_ARGUMENT The value of argument .Ar fd differs from the one the ELF descriptor .Ar elf was created with. .It Bq Er ELF_E_ARGUMENT Argument .Ar cmd differs from the value specified when ELF descriptor .Ar elf was created. .It Bq Er ELF_E_ARGUMENT An .Xr ar 1 -archive was opened with with +archive was opened with .Ar cmd set to .Dv ELF_C_RDWR . .It Bq Er ELF_E_ARGUMENT The file referenced by argument .Ar fd was empty. .It Bq Er ELF_E_ARGUMENT The underlying file for argument .Ar fd was of an unsupported type. .It Bq Er ELF_E_IO The file descriptor in argument .Ar fd was invalid. .It Bq Er ELF_E_IO The file descriptor in argument .Ar fd could not be read or written to. .It Bq Er ELF_E_RESOURCE An out of memory condition was encountered. .It Bq Er ELF_E_SEQUENCE Function .Fn elf_begin was called before a working version was established with .Xr elf_version 3 . .It Bq Er ELF_E_VERSION The ELF object referenced by argument .Ar fd was of an unsupported ELF version. .El .Sh SEE ALSO .Xr elf 3 , .Xr elf_end 3 , .Xr elf_errno 3 , .Xr elf_memory 3 , .Xr elf_next 3 , .Xr elf_rand 3 , .Xr elf_update 3 , .Xr gelf 3 Index: vendor/elftoolchain/dist/libelf/elf_cntl.3 =================================================================== --- vendor/elftoolchain/dist/libelf/elf_cntl.3 (revision 282910) +++ vendor/elftoolchain/dist/libelf/elf_cntl.3 (revision 282911) @@ -1,111 +1,111 @@ .\" 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 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_cntl.3 289 2009-01-08 08:26:08Z jkoshy $ +.\" $Id: elf_cntl.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd August 9, 2006 .Os .Dt ELF_CNTL 3 .Sh NAME .Nm elf_cntl .Nd control an elf file descriptor .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Ft int .Fn elf_cntl "Elf *elf" "Elf_Cmd cmd" .Sh DESCRIPTION Function .Fn elf_cntl controls the ELF library's subsequent use of the file descriptor used to create ELF descriptor .Ar elf . .Pp Argument .Ar cmd informs the library of the action to be taken: .Bl -tag -width "ELF_C_FDDONE" .It Dv ELF_C_FDDONE This value instructs the ELF library not to perform any further I/O on the file descriptor associated with argument .Ar elf . For ELF descriptors opened with mode .Ar ELF_C_WRITE or .Ar ELF_C_RDWR subsequent .Fn elf_update operations on the descriptor will fail. .It Dv ELF_C_FDREAD This value instructs the ELF library to read in all necessary data associated with ELF descriptor .Ar elf into memory so that the underlying file descriptor can be safely closed with command .Dv ELF_C_FDDONE . .El .Pp Argument .Ar elf must be an ELF descriptor associated with a file system object (e.g., an .Xr ar 1 archive, an ELF file, or other data file). .Sh IMPLEMENTATION NOTES Due to use of .Xr mmap 2 internally, this function is a no-op for ELF objects opened in .Dv ELF_C_READ mode. .Sh RETURN VALUES Function .Fn elf_cntl returns 0 on success, or -1 if an error was detected. .Sh ERRORS .Bl -tag -width "[ELF_E_RESOURCE]" .It Bq Er ELF_E_ARCHIVE Argument .Ar elf is a descriptor for an archive member. .It Bq Er ELF_E_ARGUMENT Argument .Ar elf was NULL. .It Bq Er ELF_E_ARGUMENT Argument .Ar cmd was not recognized. .It Bq Er ELF_E_MODE An .Dv ELF_C_FDREAD operation was requested on an ELF descriptor opened for writing. .El .Sh SEE ALSO .Xr elf 3 , .Xr elf_begin 3 , .Xr elf_end 3 , .Xr elf_next 3 , .Xr elf_update 3 , .Xr gelf 3 Index: vendor/elftoolchain/dist/libelf/elf_getdata.3 =================================================================== --- vendor/elftoolchain/dist/libelf/elf_getdata.3 (revision 282910) +++ vendor/elftoolchain/dist/libelf/elf_getdata.3 (revision 282911) @@ -1,229 +1,229 @@ .\" Copyright (c) 2006,2008,2010-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_getdata.3 1766 2011-08-22 06:01:03Z jkoshy $ +.\" $Id: elf_getdata.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd January 26, 2011 .Os .Dt ELF_GETDATA 3 .Sh NAME .Nm elf_getdata , .Nm elf_newdata , .Nm elf_rawdata .Nd iterate through or allocate section data .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Ft "Elf_Data *" .Fn elf_getdata "Elf_Scn *scn" "Elf_Data *data" .Ft "Elf_Data *" .Fn elf_newdata "Elf_Scn *scn" .Ft "Elf_Data *" .Fn elf_rawdata "Elf_Scn *scn" "Elf_Data *data" .Sh DESCRIPTION These functions are used to access and manipulate data descriptors associated with section descriptors. Data descriptors used by the ELF library are described in .Xr elf 3 . .Pp Function .Fn elf_getdata will return the next data descriptor associated with section descriptor .Ar scn . The returned data descriptor will be setup to contain translated data. Argument .Ar data may be NULL, in which case the function returns the first data descriptor associated with section .Ar scn . If argument .Ar data is not NULL, it must be a pointer to a data descriptor associated with section descriptor .Ar scn , and function .Fn elf_getdata will return a pointer to the next data descriptor for the section, or NULL when the end of the section's descriptor list is reached. .Pp Function .Fn elf_newdata will allocate a new data descriptor and append it to the list of data descriptors associated with section descriptor .Ar scn . The new data descriptor will be initialized as follows: .Bl -tag -width "d_version" -compact -offset indent .It Va d_align Set to 1. .It Va d_buf Initialized to NULL. .It Va d_off Set to (off_t) -1. This field is under application control if the .Dv ELF_F_LAYOUT flag was set on the ELF descriptor. .It Va d_size Set to zero. .It Va d_type Initialized to .Dv ELF_T_BYTE . .It Va d_version Set to the current working version of the library, as set by .Xr elf_version 3 . .El The application must set these values as appropriate before calling .Xr elf_update 3 . Section .Ar scn must be associated with an ELF file opened for writing. If the application has not requested full control of layout by setting the .Dv ELF_F_LAYOUT flag on descriptor .Ar elf , then the data referenced by the returned descriptor will be positioned after the existing content of the section, honoring the file alignment specified in member .Va d_align . On successful completion of a call to .Fn elf_newdata , the ELF library will mark the section .Ar scn as .Dq dirty . .Pp Function .Fn elf_rawdata is used to step through the data descriptors associated with section .Ar scn . In contrast to function .Fn elf_getdata , this function returns untranslated data. If argument .Ar data is NULL, the first data descriptor associated with section .Ar scn is returned. If argument .Ar data is not NULL, is must be a data descriptor associated with section .Ar scn , and function .Fn elf_rawdata will return the next data descriptor in the list, or NULL if no further descriptors are present. Function .Fn elf_rawdata always returns .Vt Elf_Data structures of type .Dv ELF_T_BYTE . .Ss Special handling of zero-sized and SHT_NOBITS sections For sections of type .Dv SHT_NOBITS, and for zero-sized sections, the functions .Fn elf_getdata and .Fn elf_rawdata return a pointer to a valid .Vt Elf_Data structure that has its .Va d_buf member set to NULL and its .Va d_size member set to the size of the section. .Pp If an application wishes to create a section of type .Dv SHT_NOBITS , it should add a data buffer to the section using function .Fn elf_newdata . It should then set the .Va d_buf and .Va d_size members of the returned .Vt Elf_Data structure to NULL and the desired size of the section respectively. .Sh RETURN VALUES These functions return a valid pointer to a data descriptor if successful, or NULL if an error occurs. .Sh ERRORS These functions may fail with the following errors: -.Bl -tag -width "[ELF_E_RESOURCE]" +.Bl -tag -width "[ELF_E_RESOURCE]" .It Bq Er ELF_E_ARGUMENT Either of the arguments .Ar scn or .Ar data was NULL. .It Bq Er ELF_E_ARGUMENT The data descriptor referenced by argument .Ar data is not associated with section descriptor .Ar scn . .It Bq Er ELF_E_ARGUMENT The section denoted by argument .Ar scn had no data associated with it. .It Bq Er ELF_E_DATA Retrieval of data from the underlying object failed. .It Bq Er ELF_E_RESOURCE An out of memory condition was detected. .It Bq Er ELF_E_SECTION Section .Ar scn had type .Dv SHT_NULL . .It Bq Er ELF_E_SECTION The type of the section .Ar scn was not recognized by the library. .It Bq Er ELF_E_SECTION The size of the section .Ar scn is not a multiple of the file size for its section type. .It Bq Er ELF_E_SECTION The file offset for section .Ar scn is incorrect. .It Bq Er ELF_E_UNIMPL The section type associated with section .Ar scn is currently unsupported by the library. .El .Sh SEE ALSO .Xr elf 3 , .Xr elf_flagdata 3 , .Xr elf_flagscn 3 , .Xr elf_getscn 3 , .Xr elf_getshdr 3 , .Xr elf_newscn 3 , .Xr elf_rawfile 3 , .Xr elf_update 3 , .Xr elf_version 3 , .Xr gelf 3 Index: vendor/elftoolchain/dist/libelf/elf_open.3 =================================================================== --- vendor/elftoolchain/dist/libelf/elf_open.3 (revision 282910) +++ vendor/elftoolchain/dist/libelf/elf_open.3 (revision 282911) @@ -1,121 +1,121 @@ .\" Copyright (c) 2012 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_open.3 2512 2012-05-31 06:15:57Z jkoshy $ +.\" $Id: elf_open.3 3181 2015-04-10 13:22:51Z emaste $ .\" .Dd May 31, 2012 .Os -.Dt ELF_OPEN 3 +.Dt ELF_OPEN 3 .Sh NAME .Nm elf_open .Nd open ELF objects and ar(1) archives .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Ft "Elf *" .Fn elf_open "int fd" .Ft "Elf *" .Fn elf_openmemory "char *image" "size_t sz" .Sh DESCRIPTION .Em Important : The functions .Fn elf_open and .Fn elf_openmemory are extensions to the ELF(3) API, for the internal use of the Elftoolchain project. Portable applications should not use these functions. .Pp The function .Fn elf_open returns an Elf descriptor opened with mode .Dv ELF_C_READ for the ELF object or .Xr ar 1 archive referenced by the file descriptor in argument .Ar fd . .Pp The function .Fn elf_openmemory returns an ELF descriptor opened with mode .Dv ELF_C_READ for the ELF object or .Xr ar 1 archive contained in the memory area pointed to by the argument .Ar image . The argument .Ar sz specifies the size of the memory area in bytes. .Sh COMPATIBILITY These functions are non-standard extensions to the ELF(3) API set. .Pp The behavior of these functions differs from their counterparts .Xr elf_begin 3 and .Xr elf_memory 3 in that these functions will successfully open malformed ELF objects and .Xr ar 1 archives, returning an Elf descriptor of type .Dv ELF_K_NONE . .Sh RETURN VALUES The function returns a pointer to a ELF descriptor if successful, or NULL if an error occurred. .Sh ERRORS These functions can fail with the following errors: .Bl -tag -width "[ELF_E_RESOURCE]" .It Bq Er ELF_E_ARGUMENT The argument .Ar fd was of an unsupported file type. .It Bq Er ELF_E_ARGUMENT The argument .Ar sz was zero, or the argument .Ar image was NULL. .It Bq Er ELF_E_IO The file descriptor in argument .Ar fd was invalid. .It Bq Er ELF_E_IO The file descriptor in argument .Ar fd could not be read. .It Bq Er ELF_E_RESOURCE An out of memory condition was encountered. .It Bq Er ELF_E_SEQUENCE Functions .Fn elf_open or .Fn elf_openmemory was called before a working version was established with .Xr elf_version 3 . .El .Sh SEE ALSO .Xr elf 3 , .Xr elf_begin 3 , .Xr elf_errno 3 , .Xr elf_memory 3 , .Xr gelf 3 Index: vendor/elftoolchain/dist/libelf/elf_update.c =================================================================== --- vendor/elftoolchain/dist/libelf/elf_update.c (revision 282910) +++ vendor/elftoolchain/dist/libelf/elf_update.c (revision 282911) @@ -1,1213 +1,1215 @@ /*- * 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 3013 2014-03-23 06:16:59Z jkoshy $"); +ELFTC_VCSID("$Id: elf_update.c 3190 2015-05-04 15:23:08Z 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) { Elf_Data *d; size_t fsz, msz; int ec, elftype; uint32_t sh_type; uint64_t d_align; Elf32_Shdr *shdr32; Elf64_Shdr *shdr64; 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, (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) { + if (scn_alignment > sh_align || + sh_offset % sh_align || + sh_size < scn_size || + sh_offset % _libelf_falign(elftype, ec)) { 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((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 = (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 = (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 = (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] = (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 += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); 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 % (off_t) align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } } else phoff = roundup(rc, (off_t) align); rc = phoff + (off_t) fsz; phdr = _libelf_getphdr(e, ec); 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 % (off_t) align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); } } else shoff = roundup(rc, (off_t) align); if (shoff + (off_t) fsz > rc) rc = shoff + (off_t) fsz; 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 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; assert(ex->ex_type == ELF_EXTENT_SECTION); s = ex->ex_desc; 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), (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, (size_t) 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), (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_version == e->e_version); assert(d->d_size % msz == 0); 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 += (off_t) fsz; } return (rc); } /* * Write out an ELF Executable Header. */ static off_t _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, 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 ((off_t) (phoff + fsz)); } /* * Write out an ELF section header table. */ static off_t _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 ((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; 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), (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 = (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); } Index: vendor/elftoolchain/dist/libelf/gelf.3 =================================================================== --- vendor/elftoolchain/dist/libelf/gelf.3 (revision 282910) +++ vendor/elftoolchain/dist/libelf/gelf.3 (revision 282911) @@ -1,201 +1,200 @@ .\" 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 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: gelf.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" $Id: gelf.3 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd September 1, 2006 .Os .Dt GELF 3 .Sh NAME .Nm GElf .Nd class-independent API for ELF manipulation .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In gelf.h .Sh DESCRIPTION This manual page describes a class independent API for manipulating ELF objects. This API allows an application to operate on ELF descriptors without needing to the know the ELF class of the descriptor. .Pp The GElf API may be used alongside the ELF API without restriction. .Ss GElf Data Structures The GElf API defines the following class-independent data structures: .Bl -tag -width GElf_Sxword .It Vt GElf_Addr A representation of ELF addresses. .It Vt GElf_Dyn A class-independent representation of ELF .Sy .dynamic section entries. .It Vt GElf_Ehdr A class-independent representation of an ELF Executable Header. .It Vt GElf_Half An unsigned 16 bit quantity. .It Vt GElf_Off A class-independent representation of a ELF offset. .It Vt GElf_Phdr A class-independent representation of an ELF Program Header Table entry. .It Vt GElf_Rel A class-independent representation of an ELF relocation entry. .It Vt GElf_Rela A class-independent representation of an ELF relocation entry with addend. .It Vt GElf_Shdr A class-independent representation of an ELF Section Header Table entry. .It Vt GElf_Sword A signed 32 bit quantity. .It Vt GElf_Sxword A signed 64 bit quantity. .It Vt GElf_Sym A class-independent representation of an ELF symbol table entry. .It Vt GElf_Word An unsigned 32 bit quantity. .It Vt GElf_Xword An unsigned 64 bit quantity. .El .Pp These data structures are sized to be compatible with the corresponding 64 bit ELF structures, and have the same internal structure as their 64 bit class-dependent counterparts. Class-dependent ELF structures are described in .Xr elf 5 . .Ss GElf Programming Model GElf functions always return a .Em copy of the underlying (class-dependent) ELF data structure. The programming model with GElf is as follows: .Bl -enum .It An application will retrieve data from an ELF descriptor using a .Fn gelf_get_* function. This will copy out data into a private .Vt GElf_* data structure. .It The application will work with its private copy of the GElf structure. .It Once done, the application copies the new values back to the underlying ELF data structure using the .Fn gelf_update_* functions. .It The application will then use the .Fn elf_flag* APIs to indicate to the ELF library that an ELF data structure is dirty. .El .Pp When updating an underlying 32 bit ELF data structure, the GElf routines will signal an error if a GElf value is out of range for the underlying ELF data type. .Ss Namespace use The GElf interface uses the following symbols: .Bl -tag .It GElf_* Class-independent data types. .It gelf_* For functions defined in the API set. .El .Ss GElf Programming APIs This section provides an overview of the GElf programming APIs. Further information is provided in the manual page of each function listed here. .Bl -tag .It "Allocating ELF Data Structures" .Bl -tag -compact .It Fn gelf_newehdr Allocate a new ELF Executable Header. .It Fn gelf_newphdr Allocate a new ELF Program Header Table. .El .It "Data Translation" .Bl -tag -compact .It Fn gelf_xlatetof Translate the native representation of an ELF data structure to its file representation. .It Fn gelf_xlatetom Translate from the file representation of an ELF data structure to a native representation. .El .It "Retrieving ELF Data" .Bl -tag -compact .It Fn gelf_getdyn Retrieve an ELF .Sy .dynamic table entry. .It Fn gelf_getehdr Retrieve an ELF Executable Header from the underlying ELF descriptor. .It Fn gelf_getphdr Retrieve an ELF Program Header Table entry from the underlying ELF descriptor. .It Fn gelf_getrel Retrieve an ELF relocation entry. .It Fn gelf_getrela Retrieve an ELF relocation entry with addend. .It Fn gelf_getshdr Retrieve an ELF Section Header Table entry from the underlying ELF descriptor. .It Fn gelf_getsym Retrieve an ELF symbol table entry. .El .It Queries .Bl -tag -compact .It Fn gelf_checksum Retrieves the ELF checksum for an ELF descriptor. .It Fn gelf_fsize Retrieves the size of the file representation of an ELF type. .It Fn gelf_getclass Retrieves the ELF class of an ELF descriptor. .El .It "Updating ELF Data" .Bl -tag -compact -width ".Fn gelf_update_shdr" .It Fn gelf_update_dyn Copy back an ELF .Sy .dynamic Table entry. .It Fn gelf_update_phdr Copy back an ELF Program Header Table entry. .It Fn gelf_update_rel Copy back an ELF relocation entry. .It Fn gelf_update_rela Copy back an ELF relocation with addend entry. .It Fn gelf_update_shdr Copy back an ELF Section Header Table entry. .It Fn gelf_update_sym Copy back an ELF symbol table entry. .El .El .Sh SEE ALSO .Xr elf 3 , .Xr elf 5 .Sh HISTORY The GELF(3) API first appeared in System V Release 4. This implementation of the API first appeared in .Fx 7.0 . .Sh AUTHORS The GElf API was implemented by -.An "Joseph Koshy" -.Aq jkoshy@FreeBSD.org . +.An Joseph Koshy Aq Mt jkoshy@FreeBSD.org . Index: vendor/elftoolchain/dist/libelftc/elftc_demangle.3 =================================================================== --- vendor/elftoolchain/dist/libelftc/elftc_demangle.3 (revision 282910) +++ vendor/elftoolchain/dist/libelftc/elftc_demangle.3 (revision 282911) @@ -1,116 +1,116 @@ .\" 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. .\" 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: elftc_demangle.3 2065 2011-10-26 15:24:47Z jkoshy $ +.\" $Id: elftc_demangle.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd August 24, 2011 .Os .Dt ELFTC_DEMANGLE 3 .Sh NAME .Nm elftc_demangle .Nd demangle a C++ name .Sh LIBRARY .Lb libelftc .Sh SYNOPSIS .In libelftc.h .Ft int .Fo elftc_demangle .Fa "const char *encodedname" .Fa "char *buffer" .Fa "size_t bufsize" .Fa "unsigned int flags" .Fc .Sh DESCRIPTION Function .Fn elftc_demangle decodes a symbol name encoded according to the type encoding rules for the C++ language and returns a string denoting an equivalent C++ prototype. .Pp Argument .Ar encodedname specifies the encoded symbol name. Argument .Ar buffer denotes a programmer-specified area to place the prototype string in. Argument .Ar bufsize specifies the size of the programmer-specified area. Argument .Ar flags specifies the encoding style in use for argument .Ar encodedname . Supported encoding styles are: .Bl -tag -width ".Dv ELFTC_DEM_GNU3" .It Dv ELFTC_DEM_ARM The encoding style used by compilers adhering to the conventions of the C++ Annotated Reference Manual. .It Dv ELFTC_DEM_GNU2 The encoding style by GNU C++ version 2. .It Dv ELFTC_DEM_GNU3 The encoding style by GNU C++ version 3 and later. .El .Pp Argument .Ar flags may be zero, in which case the function will attempt to guess the encoding scheme from the contents of .Ar encodedname . .Sh RETURN VALUE Function .Fn elftc_demangle returns 0 on success. In case of an error it returns -1 and sets the .Va errno variable. .Sh EXAMPLES To decode a name that uses an unknown encoding style use: .Bd -literal -offset indent char buffer[1024]; const char *funcname; - + funcname = ...; /* points to string to be demangled */ if (elftc_demangle(funcname, buffer, sizeof(buffer), 0) == 0) printf("Demangled name: %\\n", buffer); else perror("Cannot demangle %s", funcname); .Ed .Sh ERRORS Function .Fn elftc_demangle may fail with the following errors: .Bl -tag -width ".Bq Er ENAMETOOLONG" .It Bq Er EINVAL Argument .Ar encodedname was not a valid encoded name. .It Bq Er ENAMETOOLONG The output buffer specified by arguments .Ar buffer and .Ar bufsize was too small to hold the decoded function prototype. .El .Sh SEE ALSO .Xr elf 3 , .Xr elf_strptr 3 Index: vendor/elftoolchain/dist/libelftc/elftc_symbol_table_create.3 =================================================================== --- vendor/elftoolchain/dist/libelftc/elftc_symbol_table_create.3 (revision 282910) +++ vendor/elftoolchain/dist/libelftc/elftc_symbol_table_create.3 (revision 282911) @@ -1,529 +1,529 @@ .\" Copyright (c) 2012 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: elftc_symbol_table_create.3 2825 2012-12-29 14:25:33Z jkoshy $ +.\" $Id: elftc_symbol_table_create.3 3182 2015-04-10 16:08:10Z emaste $ .\" .Dd December 29, 2012 .Os .Dt ELFTC_SYMBOL_TABLE_CREATE 3 .Sh NAME .Nm elftc_elf_symbol_table_from_section , .Nm elftc_symbol_table_count , .Nm elftc_symbol_table_create , .Nm elftc_symbol_table_create_nested , .Nm elftc_symbol_table_delete_name , .Nm elftc_symbol_table_delete_entry , .Nm elftc_symbol_table_destroy , .Nm elftc_symbol_table_insert , .Nm elftc_symbol_table_iterate , .Nm elftc_symbol_table_lookup , .Nm elftc_symbol_table_lookup_value , .Nm elftc_symbol_table_replace , .Nm elftc_symbol_table_sort , .Nm elftc_symbol_table_step .Nd symbol table management routines .Sh SYNOPSIS .In libelftc.h .Bd -literal typedef struct _Elftc_Symbol_Table Elftc_Symbol_Table; typedef struct _Elftc_Symbol { ... library private fields ... const char *sym_name; uintptr_t sym_value; } Elftc_Symbol; .Ed .Ft size_t .Fn elftc_symbol_table_count "Elftc_Symbol_Table *table" .Ft "Elftc_Symbol_Table *" .Fo elftc_symbol_table_create .Fa "size_t entrysize" .Fa "int sizehint" .Fc .Ft "Elftc_Symbol_Table *" .Fo elftc_symbol_table_create_nested .Fa "Elftc_Symbol_Table *table" .Fa "int sizehint" .Fc .Ft int .Fo elftc_symbol_table_delete_name .Fa "Elftc_Symbol_Table *table" .Fa "const char *name" .Fc .Ft int .Fo elftc_symbol_table_delete_entry .Fa "Elftc_Symbol_Table *table" .Fa "Elftc_Symbol *entry" .Fc .Ft int .Fn elftc_symbol_table_destroy "Elftc_Symbol_Table *table" .Ft "Elftc_Symbol *entry" .Fo elftc_symbol_table_insert .Fa "Elftc_Symbol_Table *table" .Fa "const char *symbolname" .Fa "int *status" .Fc .Ft int .Fo elftc_symbol_table_iterate .Fa "Elftc_Symbol_Table *table" .Fa "int (*iterfn)(Elftc_Symbol *entry, void *cookie)" .Fa "void *cookie" .Fc .Ft "Elftc_Symbol *" .Fo elftc_symbol_table_lookup .Fa "Elftc_Symbol_Table *table" .Fa "const char *symbolname" .Fc .Ft "Elftc_Elf_Symbol *" .Fo elftc_symbol_table_lookup_value .Fa "Elftc_Symbol_Table *table" .Fa "uintptr_t value" .Fa "int searchflags" .Fc .Ft int .Fo elftc_symbol_table_replace .Fa "Elftc_Symbol_Table *table" .Fa "Elftc_Symbol *sym1" .Fa "Elftc_Symbol *sym2" .Fc .Ft int .Fo elftc_symbol_table_sort .Fa "Elftc_Symbol_Table *table" .Fa "int (*cmpfn)(Elftc_Symbol *s1, Elftc_Symbol *s2)" .Fc .Ft "Elftc_Symbol *" .Fo elftc_symbol_table_step .Fa "Elftc_Symbol_Table *table" .Fa "Elftc_Symbol *cursym" .Fa "int direction" .Fc .Bd -literal typedef struct _Elftc_Elf_Symbol { ... library private fields ... const char *sym_name; Gelf_Sym sym_elf; } Elftc_Elf_Symbol; .Ed .Ft "Elftc_Symbol_Table *" .Fo elftc_elf_symbol_table_from_section .Fa "Elf_Scn *symscn" .Fa "Elf_Scn *strscn" .Fc .Sh DESCRIPTION This manual page documents convenience routines for handling symbol tables. Two flavors of symbol tables are supported: .Bl -bullet -compact .It .Dq Regular symbol tables supporting insertion, deletion and lookup of entries by name or by value, sorting of entries, and stepping through entries in the table's current traversal order. .It .Dq ELF-centric symbol tables support additional operations for conversions to and from the symbol table format understood by .Lb libelf . .El The default traversal order for a symbol table is the order in which entries were inserted into it. This traversal order may be changed using function .Fn elftc_symbol_table_sort . .Ss Operations on Regular Symbol Tables Regular symbol tables use symbols that are subtypes of .Vt Elftc_Symbol , as described in the section .Sx "Structure of a Symbol Table Entry" below. .Pp Function .Fn elftc_symbol_table_count returns the number of entries currently in the symbol table. .Pp Function .Fn elftc_symbol_table_create creates a new, empty symbol table. The argument .Ar entrysize specifies the size of each symbol table entry, as described in the section .Sx "Structure of a Symbol Table Entry" below. The argument .Ar sizehint specifies the expected number of symbol table entries. If .Ar sizehint is zero, an implementation-defined default will be used. .Pp Function .Fn elftc_symbol_table_create_nested creates a symbol table whose search scope nests inside that of a parent symbol table. The argument .Ar parent specifies the parent symbol table to nest under. The argument .Ar sizehint specifies the expected number of symbol table entries. If .Ar sizehint is zero, an implementation-defined default will be used instead. .Pp The function .Fn elftc_symbol_table_delete_name removes the symbol entry named by the argument .Ar name from the symbol table specified by argument .Ar table , according to the rules described in section .Sx "Symbol Search Rules" . .Pp The function .Fn elftc_symbol_table_delete_entry removes the symbol table entry specified by argument .Ar entry from the symbol table specified by argument .Ar table . .Pp Function .Fn elftc_symbol_table_destroy is used to destroy a symbol table and free up its internal resources. .Pp The function .Fn elftc_symbol_table_insert inserts a symbol entry for the name specified by argument .Ar symbolname into the symbol table specified by argument .Ar table , returning a pointer to a symbol table entry. The argument .Ar status should point to a location that will be updated with one of the following values: .Bl -tag -width indent -compact -offset indent .It Dv ELFTC_INSERT_ERROR -An error occured during insertion of the symbol. +An error occurred during insertion of the symbol. .It Dv ELFTC_INSERT_EXISTING The name in argument .Ar symbolname was already in the symbol table, and a pointer to the existing symbol table entry is being returned. .It Dv ELFTC_INSERT_NEW A new symbol table entry was allocated for the symbol name in .Ar symbolname . The application will need to initialize the application-specific fields of the symbol table entry. .El Insertion obeys the scoping rules described in section .Sx "Symbol Search Rules" . .Pp The function .Fn elftc_symbol_table_iterate iterates over the symbol table specifed by argument .Ar table , applying the function pointed to by argument .Ar iterfn to each symbol table entry. The return value from the function .Ar iterfn controls progress of the iteration: .Bl -tag -width indent -compact -offset indent .It Dv ELFTC_ITERATE_ABORT Terminates the iteration. .It Dv ELFTC_ITERATE_CONTINUE Iteration will continue on to the next element in the symbol table. .El Argument .Ar cookie will be passed to each invocation of .Ar iterfn , and may be used to track persistent state. The ordering of symbol table entries presented to function .Ar iterfn is not defined. The behavior of the iteration is undefined if .Ar iterfn adds or deletes symbol entries from a symbol table that currently being iterated through. .Pp Function .Fn elftc_symbol_table_lookup returns the symbol entry corresponding to the name of the symbol in argument .Ar symbolname . .Pp Function .Fn elftc_symbol_table_lookup_value returns the symbol entry that has a .Va sym_value field that is closest to the value specified in argument .Ar value . The argument .Ar table should point to a symbol table, that has been sorted by a prior call to .Fn elftc_symbol_table_sort . The argument .Ar searchflags can be a combination of the following flags: .Bl -tag -width indent -compact -offset indent .It Dv ELFTC_SEARCH_FORWARD Find the symbol entry with the next higher value in its .Va sym_value field. .It Dv ELFTC_SEARCH_BACKWARD Find the symbol entry with next lower value in its .Va sym_value field. .El If both .Dv ELFTC_SEARCH_FORWARD and .Dv ELFTC_SEARCH_BACKWARD are specified, then this function will return the symbol that is closest to the argument .Ar value . .Pp Function .Fn elftc_symbol_table_replace moves the symbol table entry pointed to by argument .Ar sym2 into the traversal position for the entry pointed to by .Ar sym1 , and implicitly deletes the entry pointed to by argument .Ar sym1 . Argument .Ar table should point to a valid symbol table. .Pp Function .Fn elftc_symbol_table_sort is used to define an ordering of symbol entries in a symbol table. This ordering will be associated with the symbol table till the next call to function .Fn elftc_symbol_table_insert , .Fn elftc_symbol_table_delete_name or .Fn elftc_symbol_table_delete_entry . The argument .Ar cmpfn should point to a function that compares two symbol entries pointed to by .Ar s1 and .Ar s2 and returns -1, 0, or 1, depending whether .Ar s1 is less, equal to, or greater than .Ar s2 respectively. .Pp Function .Fn elftc_symbol_table_step is used to step to the next symbol in a sorted symbol table. Argument .Ar table should point to a symbol table. The argument .Ar cursym specifies the current symbol. The argument .Ar direction specifies the direction to step: .Bl -tag -width indent -compact -offset ident .It Dv ELFTC_STEP_NEXT Return the symbol which follows the argument .Ar cursym in the current traversal order. If argument .Ar cursym is NULL, return the first symbol in the current traversal order. .It Dv ELFTC_STEP_PREVIOUS Return the symbol which precedes the argument .Ar cursym in the current traversal order. If argument .Ar cursym is NULL, return the last symbol in the current traversal order. .El .Ss Operations on ELF-centric symbol tables ELF-centric symbol tables use symbols that are subtypes of .Vt Elftc_Elf_Symbol , as described in the section .Sx "Structure of a Symbol Table Entry" below. .Pp In addition to the operations on regular symbol tables listed above, these symbol tables may be used with the following additional functions. .Pp The function .Fn elftc_elf_symbol_table_from_section builds a symbol table from the contents of an ELF section. The argument .Ar symscn should reference an ELF section of type .Dv SHT_SYMTAB or .Dv SHT_DYNSYM . The argument .Ar strscn should reference an ELF section of type .Dv SHT_STRTAB containing the string table associated wit section .Ar symscn . .Ss Structure of a Symbol Table Entry The symbol tables managed by .Lb libelftc are collections of symbol table entries. Each entry should be a subtype of one of the .Vt Elftc_Symbol or .Vt Elftc_Elf_Symbol types. In other words, each entry should have an .Vt Elftc_Symbol or .Vt Elftc_Elf_Symbol structure as its first member, before any application specific fields. For example: .Bd -literal -offset indent struct _MySymbol { Elftc_Symbol sym_base; ... other application-specific fields ... }; .Ed .Pp The size of the combined entry is indicated to the library at the time of creating a new symbol table. Applications may then cast the returned pointers from these routines to the appropriate type: .Bd -literal -offset indent struct _MySymbol *mysym; mysym = (struct _MySymbol *) elftc_symbol_table_lookup(table, name); .Ed .Pp The .Vt Elftc_Symbol type has two public fields: .Bl -tag -width ".Va sym_value" -compact -offset indent .It Va sym_name Points to a NUL-terminated string containing the symbol's name. The application should not change the value of this field. .It Va sym_value The value associated with this symbol. This field is entirely under the application's control. .El .Pp The .Vt Elftc_Elf_Symbol type has two public fields: .Bl -tag -width ".Va sym_value" -compact -offset indent .It Va sym_name Points to a NUL-terminated string containing the symbol's name. The application should not change the value of this field. .It Va sym_elf A structure of type .Vt Gelf_Sym containing ELF symbol information. This field is entirely under the application's control. .El .Ss Symbol Search Rules During lookups, symbols are looked up first in the symbol table passed in to the .Fn elftc_symbol_table_lookup function. If the specified symbol is not found, and if the symbol table has a parent, then the search continues recursively up the chain of parent symbol tables till either a matching symbol is found or till there are no more parent symbol tables to search in. .Pp Insertions and deletion only work on the specified symbol table and do not recurse into parent symbol tables. .Ss Memory Management The .Lb libelftc manages its memory allocations. Applications should not free the pointers returned by the API documented in this manual page. .Sh RETURN VALUES Function .Fn elftc_symbol_table_count returns a count of the number of symbol table entries as an unsigned value. .Pp Functions .Fn elftc_symbol_table_create , .Fn elftc_symbol_table_create_nested and .Fn elftc_symbol_table_from_section return a pointer to an opaque structure of type .Vt Elftc_Symbol_Table on success, or return NULL in case of an error. .Pp Functions .Fn elftc_symbol_table_delete_name , .Fn elftc_symbol_table_delete_name .Fn elftc_symbol_table_destroy , .Fn elftc_symbol_table_replace and .Fn elftc_symbol_table_sort return a non-zero value on success, or return zero in case of an error. .Pp Functions .Fn elftc_symbol_table_insert , .Fn elftc_symbol_table_lookup and .Fn elftc_symbol_table_lookup_value return a pointer to a structure that is a subtype of .Vt Elftc_Symbol on success, or return NULL in case of an error. .Pp The function .Fn elftc_symbol_table_step return a pointer to a structure that is a subtype of .Vt Elftc_Symbol on success. The function returns NULL if there are no more elements in the specified traversal direction. .Pp The function .Fn elftc_symbol_table_iterate returns .Dv ELFTC_ITERATE_SUCCESS if the symbol table was successfully traversed, or .Dv ELFTC_ITERATE_ABORT in case the iteration function aborted the traversal. .Sh SEE ALSO .Xr dwarf 3 , .Xr elf 3 , .Xr elftc 3 Index: vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu3.c =================================================================== --- vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu3.c (revision 282910) +++ vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu3.c (revision 282911) @@ -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 3123 2014-12-21 05:46:19Z kaiwang27 $"); +ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3194 2015-05-05 17:55:16Z emaste $"); /** * @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); 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); + 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); } Index: vendor/elftoolchain/dist/nm/nm.1 =================================================================== --- vendor/elftoolchain/dist/nm/nm.1 (revision 282910) +++ vendor/elftoolchain/dist/nm/nm.1 (revision 282911) @@ -1,338 +1,338 @@ .\" 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. .\" -.\" $Id: nm.1 3145 2015-02-15 18:04:37Z emaste $ +.\" $Id: nm.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd February 15, 2015 .Os .Dt NM 1 .Sh NAME .Nm nm .Nd display symbolic information in object files .Sh SYNOPSIS .Nm .Op Fl -debug-syms .Op Fl -defined-only .Op Fl -demangle Ns Op = Ns style .Op Fl -dynamic .Op Fl -extern-only .Op Fl -help .Op Fl -line-numbers .Op Fl -no-demangle .Op Fl -no-sort .Op Fl -numeric-sort .Op Fl -print-armap .Op Fl -print-file-name .Op Fl -print-size .Op Fl -radix= Ns Ar format .Op Fl -reverse-sort .Op Fl -size-sort .Op Fl -undefined-only .Op Fl -version .Op Fl A .Op Fl B .Op Fl C Op Ar style .Op Fl D .Op Fl P .Op Fl V .Op Fl a .Op Fl e .Op Fl g .Op Fl h .Op Fl l .Op Fl n .Op Fl o .Op Fl p .Op Fl r .Op Fl S .Op Fl s .Op Fl t Ar format .Op Fl u .Op Fl x .Ar .Sh DESCRIPTION The .Nm utility displays symbolic information in the object files, executables, and object library files named by its arguments. Lack of symbolic information in an otherwise valid input file, is not considered to be an error. If no files are specified on the command line, .Nm will attempt to read .Pa a.out . .Pp The .Nm utility recognizes the following options: .Bl -tag -width ".Fl d Ar argument" .It Fl -debug-syms Display all symbols, including debugger-only symbols. .It Fl -defined-only Display only defined symbols. .It Fl -demangle Ns Op = Ns Ar style Decode (demangle) low-level symbol names into human-readable names. Supported values for argument .Ar style are .Sq auto , .Sq gnu-v2 , .Sq gnu-v3 and .Sq arm. If argument .Ar style is not specified, it is taken to be .Sq auto . .It Fl -dynamic Only display dynamic symbols. This option is only meaningful for shared libraries. .It Fl -extern-only Only display information about global (external) symbols. .It Fl -help Display a help message and exit. .It Fl -format Ns = Ns Ar format Display output in the format specified by argument .Ar format . Supported values for the format argument are .Sq bsd , .Sq sysv , and .Sq posix . The default output format is .Sq bsd . .It Fl -line-numbers Display the filename and line number associated a symbol using any debugging information present in the input file. For defined symbols, look up the line number associated with the address of the symbol. For undefined symbols, look up the line number associated with a relocation entry that refers to the symbol. If line number information can be determined, it is displayed after other symbol information. .It Fl -no-demangle Do not demangle symbol names (default). .It Fl -no-sort Do not sort symbols. .It Fl -numeric-sort Sort symbols numerically by address instead of alphabetically by name. .It Fl -print-armap For .Xr ar 1 archives, include the index of the archive's members. .It Fl -print-file-name Write the full pathname or library name of an object on each line, before the rest of the information for a symbol. If this option is not specified, .Nm will only identify an input file once, before its symbols are listed. .It Fl -print-size Print the size of each symbol instead of its value. .It Fl -radix Ns = Ns Ar radix Print numeric values using the specified radix. Supported values for argument .Ar radix are .Sq d for decimal, .Sq o for octal, and .Sq x for hexadecimal. .It Fl -reverse-sort Reverse the order of the sort. .It Fl -size-sort Sort symbols by size instead of alphabetically by name. .It Fl -undefined-only Display only undefined symbols. .It Fl -version Display the version identifier for .Nm and exit. .It Fl A Equivalent to specifying option .Fl -print-file-name . .It Fl B Equivalent to specifying option .Fl -format= Ns Ar bsd . .It Fl C Op Ar style Equivalent to specifying option .Fl -demangle Ns Op = Ns Ar style . .It Fl D Equivalent to specifying option .Fl -dynamic . .It Fl F Ar format Equivalent to specifying option .Fl -format Ns = Ns Ar format . .It Fl P Equivalent to specifying option .Fl -format Ns = Ns Ar posix . .It Fl S Equivalent to specifying option .Fl -print-size . .It Fl V Equivalent to specifying option .Fl -version . .It Fl a Equivalent to specifying option .Fl -debug-syms . .It Fl e Only display information for global and static symbols. .It Fl f Produce full output (default). .It Fl g Equivalent to specifying option .Fl -extern-only . .It Fl h Equivalent to specifying option .Fl -help . .It Fl l Equivalent to specifying option .Fl -line-numbers . .It Fl n Equivalent to specifying option .Fl -numeric-sort . .It Fl o If POSIX output was specified using the .Fl F Ar posix or .Fl P options, this option is equivalent to specifying .Fl -radix Ns = Ns Sq Ar o . If POSIX output was not specified, this option acts as a synonym for the .Fl -print-file-name option. .It Fl p Equivalent to specifying option .Fl -no-sort . .It Fl v Equivalent to option .Fl n . .It Fl r Equivalent to specifying option .Fl -reverse-sort .It Fl s Equivalent to specifying option .Fl -print-armap . .It Fl t Ar radix Equivalent to specifying option .Fl -radix= Ns Ar radix . .It Fl u Equivalent to specifying option .Fl -undefined-only . .It Fl x Write numeric values in hexadecimal (equivalent to -t x). .El .Sh OUTPUT FORMAT .Pp The .Nm utility can present its information in a number of formats, numeric radices and sort orders. By default .Nm uses BSD style output, a hexadecimal radix, without output sorted alphabetically by name and without demangling of names. .Pp For each symbol listed, .Nm presents the following information: .Bl -bullet -compact .It The library or object name, if options .Fl A or .Fl -print-file-name were specified. .It The symbol name. .It The type of the symbol denoted by a single character as below: .Bl -tag -compact -width indent .It A A global, absolute symbol. .It B A global .Dq bss (uninitialized data) symbol. .It C A .Dq common symbol, representing uninitialized data. .It D A global symbol naming initialized data. .It N A debugger symbol. .It R A read-only data symbol. .It T A global text symbol. .It U An undefined symbol. .It V A weak object. .It W A weak reference. .It a A local absolute symbol. .It b A local .Dq bss (uninitialized data) symbol. .It d A local data symbol. .It t A local text symbol. .It v A weak object that is undefined. .It w A weak symbol that is undefined. .It ? None of the above. .El .It The value of the symbol. .It The size of the symbol if applicable. .It Line number information, if available and if options .Fl l or .Fl -line-numbers were specified. .El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr ar 1 , .Xr objdump 1 , .Xr ranlib 1 , .Xr elf 3 .Sh AUTHORS The .Nm utility and this manual page were written by -.An Hyogeol Lee Aq hyogeollee@gmail.com . +.An Hyogeol Lee Aq Mt hyogeollee@gmail.com . Index: vendor/elftoolchain/dist/readelf/readelf.1 =================================================================== --- vendor/elftoolchain/dist/readelf/readelf.1 (revision 282910) +++ vendor/elftoolchain/dist/readelf/readelf.1 (revision 282911) @@ -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 3059 2014-06-02 00:42:32Z kaiwang27 $ +.\" $Id: readelf.1 3195 2015-05-12 17:22:19Z emaste $ .\" .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 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 . +.An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: vendor/elftoolchain/dist/readelf/readelf.c =================================================================== --- vendor/elftoolchain/dist/readelf/readelf.c (revision 282910) +++ vendor/elftoolchain/dist/readelf/readelf.c (revision 282911) @@ -1,7468 +1,7480 @@ /*- * 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 3178 2015-03-30 18:29:13Z emaste $"); +ELFTC_VCSID("$Id: readelf.c 3189 2015-04-20 17:02:01Z emaste $"); /* * 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 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(const char *note_name, unsigned int et, unsigned int nt); static const char *note_type_freebsd(unsigned int nt); static const char *note_type_freebsd_core(unsigned int nt); static const char *note_type_linux_core(unsigned int nt); static const char *note_type_gnu(unsigned int nt); static const char *note_type_netbsd(unsigned int nt); static const char *note_type_openbsd(unsigned int nt); static const char *note_type_unknown(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: return "FEATURE"; 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 1028: return "R_AARCH64_TLS_DTPREL64"; case 1029: return "R_AARCH64_TLS_DTPMOD64"; case 1030: return "R_AARCH64_TLS_TPREL64"; case 1031: return "R_AARCH64_TLSDESC"; case 1032: return "R_AARCH64_IRELATIVE"; 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"; case 24: return "R_X86_64_PC64"; case 25: return "R_X86_64_GOTOFF64"; case 26: return "R_X86_64_GOTPC32"; case 27: return "R_X86_64_GOT64"; case 28: return "R_X86_64_GOTPCREL64"; case 29: return "R_X86_64_GOTPC64"; case 30: return "R_X86_64_GOTPLT64"; case 31: return "R_X86_64_PLTOFF64"; case 32: return "R_X86_64_SIZE32"; case 33: return "R_X86_64_SIZE64"; case 34: return "R_X86_64_GOTPC32_TLSDESC"; case 35: return "R_X86_64_TLSDESC_CALL"; case 36: return "R_X86_64_TLSDESC"; case 37: return "R_X86_64_IRELATIVE"; default: return ""; } default: return ""; } } static const char * note_type(const char *name, unsigned int et, unsigned int nt) { if ((strcmp(name, "CORE") == 0 || strcmp(name, "LINUX") == 0) && et == ET_CORE) return note_type_linux_core(nt); else if (strcmp(name, "FreeBSD") == 0) if (et == ET_CORE) return note_type_freebsd_core(nt); else return note_type_freebsd(nt); else if (strcmp(name, "GNU") == 0 && et != ET_CORE) return note_type_gnu(nt); else if (strcmp(name, "NetBSD") == 0 && et != ET_CORE) return note_type_netbsd(nt); else if (strcmp(name, "OpenBSD") == 0 && et != ET_CORE) return note_type_openbsd(nt); return note_type_unknown(nt); } static const char * note_type_freebsd(unsigned int nt) { switch (nt) { case 1: return "NT_FREEBSD_ABI_TAG"; case 2: return "NT_FREEBSD_NOINIT_TAG"; case 3: return "NT_FREEBSD_ARCH_TAG"; default: return (note_type_unknown(nt)); } } static const char * note_type_freebsd_core(unsigned int nt) { switch (nt) { case 1: return "NT_PRSTATUS"; case 2: return "NT_FPREGSET"; case 3: return "NT_PRPSINFO"; case 7: return "NT_THRMISC"; case 8: return "NT_PROCSTAT_PROC"; case 9: return "NT_PROCSTAT_FILES"; case 10: return "NT_PROCSTAT_VMMAP"; case 11: return "NT_PROCSTAT_GROUPS"; case 12: return "NT_PROCSTAT_UMASK"; case 13: return "NT_PROCSTAT_RLIMIT"; case 14: return "NT_PROCSTAT_OSREL"; case 15: return "NT_PROCSTAT_PSSTRINGS"; case 16: return "NT_PROCSTAT_AUXV"; case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)"; default: return (note_type_unknown(nt)); } } static const char * note_type_linux_core(unsigned int nt) { switch (nt) { case 1: return "NT_PRSTATUS (Process status)"; case 2: return "NT_FPREGSET (Floating point information)"; case 3: return "NT_PRPSINFO (Process information)"; case 4: return "NT_TASKSTRUCT (Task structure)"; case 6: return "NT_AUXV (Auxiliary vector)"; case 10: return "NT_PSTATUS (Linux process status)"; case 12: return "NT_FPREGS (Linux floating point regset)"; case 13: return "NT_PSINFO (Linux process information)"; case 16: return "NT_LWPSTATUS (Linux lwpstatus_t type)"; case 17: return "NT_LWPSINFO (Linux lwpinfo_t type)"; case 18: return "NT_WIN32PSTATUS (win32_pstatus structure)"; case 0x100: return "NT_PPC_VMX (ppc Altivec registers)"; case 0x102: return "NT_PPC_VSX (ppc VSX registers)"; case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)"; case 0x300: return "NT_S390_HIGH_GPRS (s390 upper register halves)"; case 0x301: return "NT_S390_TIMER (s390 timer register)"; case 0x302: return "NT_S390_TODCMP (s390 TOD comparator register)"; case 0x303: return "NT_S390_TODPREG (s390 TOD programmable register)"; case 0x304: return "NT_S390_CTRS (s390 control registers)"; case 0x305: return "NT_S390_PREFIX (s390 prefix register)"; case 0x400: return "NT_ARM_VFP (arm VFP registers)"; case 0x46494c45UL: return "NT_FILE (mapped files)"; case 0x46E62B7FUL: return "NT_PRXFPREG (Linux user_xfpregs structure)"; case 0x53494749UL: return "NT_SIGINFO (siginfo_t data)"; default: return (note_type_unknown(nt)); } } static const char * note_type_gnu(unsigned int nt) { switch (nt) { case 1: return "NT_GNU_ABI_TAG"; case 2: return "NT_GNU_HWCAP (Hardware capabilities)"; case 3: return "NT_GNU_BUILD_ID (Build id set by ld(1))"; case 4: return "NT_GNU_GOLD_VERSION (GNU gold version)"; default: return (note_type_unknown(nt)); } } static const char * note_type_netbsd(unsigned int nt) { switch (nt) { case 1: return "NT_NETBSD_IDENT"; default: return (note_type_unknown(nt)); } } static const char * note_type_openbsd(unsigned int nt) { switch (nt) { case 1: return "NT_OPENBSD_IDENT"; default: return (note_type_unknown(nt)); } } static const char * note_type_unknown(unsigned int nt) { static char s_nt[32]; snprintf(s_nt, sizeof(s_nt), nt >= 0x100 ? "" : "", 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; + size_t phnum, size; 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) { + if ((rawfile = elf_rawfile(re->elf, &size)) == NULL) { warnx("elf_rawfile failed: %s", elf_errmsg(-1)); continue; } + if (phdr.p_offset >= size) { + warnx("invalid program header offset"); + 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; } if (s->link >= re->shnum) { warnx("invalid section link index %u", s->link); 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; } if (s->link >= re->shnum) { warnx("invalid section link index %u", s->link); 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; 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]; 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, *name; 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) { if (buf + sizeof(*note) > end) { warnx("invalid note header"); return; } note = (Elf_Note *)(uintptr_t) buf; name = (char *)(uintptr_t)(note + 1); /* * The name field is required to be nul-terminated, and * n_namesz includes the terminating nul in observed * implementations (contrary to the ELF-64 spec). A special * case is needed for cores generated by some older Linux * versions, which write a note named "CORE" without a nul * terminator and n_namesz = 4. */ if (note->n_namesz == 0) name = ""; else if (note->n_namesz == 4 && strncmp(name, "CORE", 4) == 0) name = "CORE"; else if (strnlen(name, note->n_namesz) >= note->n_namesz) name = ""; printf(" %-13s %#010jx", name, (uintmax_t) note->n_descsz); printf(" %s\n", note_type(name, re->ehdr.e_type, note->n_type)); buf += sizeof(Elf_Note) + roundup2(note->n_namesz, 4) + roundup2(note->n_descsz, 4); } } /* * 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) { if (len < 4) { warnx("truncated attribute section length"); break; } seclen = re->dw_decode(&p, 4); if (seclen > len) { warnx("invalid attribute section length"); break; } len -= seclen; nlen = strlen((char *) p) + 1; if (nlen + 4 > seclen) { warnx("invalid attribute section name"); break; } printf("Attribute Section: %s\n", (char *) p); 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) { + if (pe - p < 8) { + warnx("Truncated MIPS option header"); + return; + } kind = re->dw_decode(&p, 1); size = re->dw_decode(&p, 1); sndx = re->dw_decode(&p, 2); info = re->dw_decode(&p, 4); + if (size < 8 || size - 8 > pe - p) { + warnx("Malformed MIPS option header"); + return; + } + size -= 8; switch (kind) { case ODK_REGINFO: - dump_mips_odk_reginfo(re, p, size - 8); + dump_mips_odk_reginfo(re, p, size); 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; + p += size; } } 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 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; \ } 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++; 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: 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: 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: printf(" Set prologue end flag\n"); break; case DW_LNS_set_epilogue_begin: 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); 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, 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, is_info; Dwarf_Sig8 v_sig8; Dwarf_Error de; 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, *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); 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) { 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) { 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(" <%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; } 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("<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; } 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:", (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) 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. */ 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 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, off_size; Dwarf_Off cu_offset, cu_length; Dwarf_Off aboff; Dwarf_Unsigned typeoff; Dwarf_Sig8 sig8; Dwarf_Unsigned sig; uint8_t *p; const char *sn; int i, ret; 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, sn)) break; } if ((size_t) i >= re->shnum) 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; } 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; sig = 0; if (!is_info) { p = (uint8_t *)(uintptr_t) &sig8.signature[0]; sig = re->dw_decode(&p, 8); } 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) { 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) { 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) { 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) { 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(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) { 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 (%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 (%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 (%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 (%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 (%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(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), "%s%+jd", dwarf_regname(re, reg), (intmax_t) off); return (rs); } static int 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 *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 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(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(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(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(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(re, cie, fde_inst, fde_instlen, cie_caf, cie_daf, low_pc, re->dbg); else 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) { 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_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, version, pointer_size, off_size; Dwarf_Error de; struct loc_at *la; int i, j, ret; printf("\nContents of section .debug_loc:\n"); /* 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) 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++) { dump_dwarf_loc(re, &llbuf[i]->ld_s[j]); if (j < llbuf[i]->ld_cents - 1) 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) 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, 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}, {"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); - } + for (i = 0; i < argc; i++) { + re->filename = argv[i]; + dump_object(re); + } exit(EXIT_SUCCESS); } Index: vendor/elftoolchain/dist/size/size.1 =================================================================== --- vendor/elftoolchain/dist/size/size.1 (revision 282910) +++ vendor/elftoolchain/dist/size/size.1 (revision 282911) @@ -1,257 +1,257 @@ .\" Copyright (c) 2007 S.Sam Arun Raj .\" Copyright (c) 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: size.1 2043 2011-10-23 14:49:16Z jkoshy $ +.\" $Id: size.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd August 25, 2011 .Dt SIZE 1 .Os .Sh NAME .Nm size .Nd "display section sizes and total size of ELF objects" .Sh SYNOPSIS .Nm .Op Fl -format= Ns Ar format .Op Fl -help .Op Fl -radix= Ns Ar radix .Op Fl -totals .Op Fl -version .Op Fl ABVdhotx .Op Ar .Sh DESCRIPTION The .Nm utility lists the sizes of ELF sections, and optionally the total size, for each input .Ar file specified on the command line. The .Nm utility can operate on ELF objects, on .Xr ar 1 archives containing ELF objects, and on core dumps. If no file name is specified on the command-line, .Pa a.out is assumed. .Pp The .Nm utility recognized the following options: .Bl -tag -width indent .It Fl -format= Ns Ar format Display output using the format specified by argument .Ar format . Supported values for this argument are: .Sq berkeley and .Sq sysv . The default output format is .Sq berkeley . See .Sx Display Formats below for more information. .It Fl -help Display a help message and exit. .It Fl -radix= Ns Ar radix Display numeric values using the radix specified by argument .Ar radix . Supported values for .Ar radix are 8, 10 and 16. The default radix is 10. .It Fl -totals Shows cumulative totals of section sizes from all objects. This option is ignored for System V style output. .It Fl -version Display a version identifier and exit. .It Fl A Equivalent to specifying option .Fl -format= Ns Ar sysv . .It Fl B Equivalent to specifying option .Fl -format= Ns Ar berkeley . .It Fl V Equivalent to specifying option .Fl -version . .It Fl d Equivalent to specifying option .Fl -radix= Ns Ar 10 . .It Fl h Equivalent to specifying option .Fl -help . .It Fl o Equivalent to specifying option .Fl -radix= Ns Ar 8 . .It Fl t Equivalent to specifying option .Fl -totals . .It Fl x Equivalent to specifying option .Fl -radix= Ns Ar 16 . .El .Sh DISPLAY FORMATS .Ss Berkeley Style Output If .Sq berkeley style output is in effect, an initial header line naming fields will be output, followed by one line of output for each ELF object specified on the command line or found in an archive. .Pp Each line will contain the following whitespace separated fields in order: .Bl -enum -compact .It The size of the text segment in the object. .It The size of the data segment in the object. .It The size of the .Sq bss segment in the object. .It The total size of the object in either decimal or octal. Decimal output is used if the specified output radix for numeric values is 10 or 16. Octal output is used if the radix being used for numeric values is 8. .It The total size of the object in hexadecimal. .It The file name of the object. .El .Pp If option .Fl -totals was specified, an additional line in the same format as above will be output at the end containing the sum of the respective fields. The file name field for the line will contain the string .Sq (TOTALS) . .Ss System V Style Output If System V style output is selected, .Nm will output the following information for each object: .Bl -enum -compact .It The name of the object followed by a colon. .It A header line containing the names of fields of subsequent lines. .It One line per section present in the object. Each line has three fields: .Bl -enum -compact .It The name of the section. .It Its size, in the selected radix for numeric values. .It The address associated with the section, in the selected numeric radix. .El .It A line whose section name field contains the string .Sq Total and whose size field contains the sum of all reported section sizes. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES To display the section sizes for .Pa /bin/ls use: .Bd -literal $ size /bin/ls text data bss dec hex filename 20975 540 392 21907 5593 /bin/ls .Ed .Pp To display sizes and total for .Pa /bin/ls and .Pa /bin/dd in hexadecimal, use: .Bd -literal $ size -tx /bin/ls /bin/dd text data bss dec hex filename 0x51ef 0x21c 0x188 21907 5593 /bin/ls 0x3df5 0x170 0x200 16741 4165 /bin/dd 0x8fe4 0x38c 0x388 38648 96f8 (TOTALS) .Ed .Pp To display section sizes for .Pa /bin/ls in System V format use: .Bd -literal $ size -A /bin/ls /bin/ls : section size addr \&.interp 21 4194704 \&.note.ABI-tag 24 4194728 \&.hash 624 4194752 \&.dynsym 2088 4195376 \&.dynstr 810 4197464 \&.rela.dyn 120 4198280 \&.rela.plt 1656 4198400 \&.init 19 4200056 \&.plt 1120 4200076 \&.text 15224 4201200 \&.fini 14 4216424 \&.rodata 1472 4216448 \&.data 80 5267456 \&.eh_frame 1624 5267536 \&.dynamic 384 5269160 \&.ctors 16 5269544 \&.dtors 16 5269560 \&.jcr 8 5269576 \&.got 576 5269584 \&.bss 528 5270176 \&.comment 686 0 Total 27110 .Ed .Sh SEE ALSO .Xr ar 1 , .Xr nm 1 , .Xr objdump 1 , .Xr readelf 1 , .Xr strings 1 , .Xr elf 3 , .Xr gelf 3 .Rs .%A "AT&T Unix Systems Labs" .%T "System V Application Binary Interface" .%O http://www.sco.com/developers/gabi/ .Re .Sh HISTORY The .Nm utility first appeared in .At v6 . .Sh AUTHORS .An -nosplit The .Nm utility was re-written by -.An S. Sam Arun Raj Aq samarunraj@gmail.com +.An S. Sam Arun Raj Aq Mt samarunraj@gmail.com This manual page was written by -.An S. Sam Arun Raj Aq samarunraj@gmail.com +.An S. Sam Arun Raj Aq Mt samarunraj@gmail.com Index: vendor/elftoolchain/dist/size/size.c =================================================================== --- vendor/elftoolchain/dist/size/size.c (revision 282910) +++ vendor/elftoolchain/dist/size/size.c (revision 282911) @@ -1,913 +1,913 @@ /*- * 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 "_elftc.h" -ELFTC_VCSID("$Id: size.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: size.c 3183 2015-04-10 16:18:42Z emaste $"); #define BUF_SIZE 1024 #define ELF_ALIGN(val,x) (((val)+(x)-1) & ~((x)-1)) #define SIZE_VERSION_STRING "size 1.0" enum return_code { RETURN_OK, RETURN_NOINPUT, RETURN_DATAERR, RETURN_USAGE }; enum output_style { STYLE_BERKELEY, STYLE_SYSV }; enum radix_style { RADIX_OCTAL, RADIX_DECIMAL, RADIX_HEX }; static uint64_t bss_size, data_size, text_size, total_size; static uint64_t bss_size_total, data_size_total, text_size_total; static int show_totals; static int size_option; static enum radix_style radix = RADIX_DECIMAL; static enum output_style style = STYLE_BERKELEY; static const char *default_args[2] = { "a.out", NULL }; static struct { int row; int col; int *width; char ***tbl; } *tb; enum { OPT_FORMAT, OPT_RADIX }; static struct option size_longopts[] = { { "format", required_argument, &size_option, OPT_FORMAT }, { "help", no_argument, NULL, 'h' }, { "radix", required_argument, &size_option, OPT_RADIX }, { "totals", no_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; static void berkeley_calc(GElf_Shdr *); static void berkeley_footer(const char *, const char *, const char *); static void berkeley_header(void); static void berkeley_totals(void); static int handle_core(char const *, Elf *elf, GElf_Ehdr *); static void handle_core_note(Elf *, GElf_Ehdr *, GElf_Phdr *, char **); static int handle_elf(char const *); static void handle_phdr(Elf *, GElf_Ehdr *, GElf_Phdr *, uint32_t, const char *); static void show_version(void); static void sysv_header(const char *, Elf_Arhdr *); static void sysv_footer(void); static void sysv_calc(Elf *, GElf_Ehdr *, GElf_Shdr *); static void usage(void); static void tbl_new(int); static void tbl_print(const char *, int); static void tbl_print_num(uint64_t, enum radix_style, int); static void tbl_append(void); static void tbl_flush(void); /* * size utility using elf(3) and gelf(3) API to list section sizes and * total in elf files. Supports only elf files (core dumps in elf * included) that can be opened by libelf, other formats are not supported. */ int main(int argc, char **argv) { int ch, r, rc; const char **files, *fn; rc = RETURN_OK; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); while ((ch = getopt_long(argc, argv, "ABVdhotx", size_longopts, NULL)) != -1) switch((char)ch) { case 'A': style = STYLE_SYSV; break; case 'B': style = STYLE_BERKELEY; break; case 'V': show_version(); break; case 'd': radix = RADIX_DECIMAL; break; case 'o': radix = RADIX_OCTAL; break; case 't': show_totals = 1; break; case 'x': radix = RADIX_HEX; break; case 0: switch (size_option) { case OPT_FORMAT: if (*optarg == 's' || *optarg == 'S') style = STYLE_SYSV; else if (*optarg == 'b' || *optarg == 'B') style = STYLE_BERKELEY; else { warnx("unrecognized format \"%s\".", optarg); usage(); } break; case OPT_RADIX: r = strtol(optarg, NULL, 10); if (r == 8) radix = RADIX_OCTAL; else if (r == 10) radix = RADIX_DECIMAL; else if (r == 16) radix = RADIX_HEX; else { warnx("unsupported radix \"%s\".", optarg); usage(); } break; default: err(EXIT_FAILURE, "Error in option handling."); /*NOTREACHED*/ } break; case 'h': case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; files = (argc == 0) ? default_args : (void *) argv; while ((fn = *files) != NULL) { rc = handle_elf(fn); if (rc != RETURN_OK) warnx(rc == RETURN_NOINPUT ? "'%s': No such file" : "%s: File format not recognized", fn); files++; } if (style == STYLE_BERKELEY) { if (show_totals) berkeley_totals(); tbl_flush(); } return (rc); } static Elf_Data * xlatetom(Elf *elf, GElf_Ehdr *elfhdr, void *_src, void *_dst, Elf_Type type, size_t size) { Elf_Data src, dst; src.d_buf = _src; src.d_type = type; src.d_version = elfhdr->e_version; src.d_size = size; dst.d_buf = _dst; dst.d_version = elfhdr->e_version; dst.d_size = size; return (gelf_xlatetom(elf, &dst, &src, elfhdr->e_ident[EI_DATA])); } #define NOTE_OFFSET_32(nhdr, namesz, offset) \ ((char *)nhdr + sizeof(Elf32_Nhdr) + \ ELF_ALIGN((int32_t)namesz, 4) + offset) #define NOTE_OFFSET_64(nhdr, namesz, offset) \ ((char *)nhdr + sizeof(Elf32_Nhdr) + \ ELF_ALIGN((int32_t)namesz, 8) + offset) #define PID32(nhdr, namesz, offset) \ (pid_t)*((int *)((uintptr_t)NOTE_OFFSET_32(nhdr, \ namesz, offset))); #define PID64(nhdr, namesz, offset) \ (pid_t)*((int *)((uintptr_t)NOTE_OFFSET_64(nhdr, \ namesz, offset))); #define NEXT_NOTE(elfhdr, descsz, namesz, offset) do { \ if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { \ offset += ELF_ALIGN((int32_t)descsz, 4) + \ sizeof(Elf32_Nhdr) + \ ELF_ALIGN((int32_t)namesz, 4); \ } else { \ offset += ELF_ALIGN((int32_t)descsz, 8) + \ sizeof(Elf32_Nhdr) + \ ELF_ALIGN((int32_t)namesz, 8); \ } \ } while (0) /* * Parse individual note entries inside a PT_NOTE segment. */ static void handle_core_note(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, char **cmd_line) { size_t max_size; uint64_t raw_size; GElf_Off offset; static pid_t pid; uintptr_t ver; Elf32_Nhdr *nhdr, nhdr_l; static int reg_pseudo = 0, reg2_pseudo = 0, regxfp_pseudo = 0; char buf[BUF_SIZE], *data, *name; if (elf == NULL || elfhdr == NULL || phdr == NULL) return; data = elf_rawfile(elf, &max_size); offset = phdr->p_offset; while (data != NULL && offset < phdr->p_offset + phdr->p_filesz) { nhdr = (Elf32_Nhdr *)(uintptr_t)((char*)data + offset); memset(&nhdr_l, 0, sizeof(Elf32_Nhdr)); if (!xlatetom(elf, elfhdr, &nhdr->n_type, &nhdr_l.n_type, ELF_T_WORD, sizeof(Elf32_Word)) || !xlatetom(elf, elfhdr, &nhdr->n_descsz, &nhdr_l.n_descsz, ELF_T_WORD, sizeof(Elf32_Word)) || !xlatetom(elf, elfhdr, &nhdr->n_namesz, &nhdr_l.n_namesz, ELF_T_WORD, sizeof(Elf32_Word))) break; name = (char *)((char *)nhdr + sizeof(Elf32_Nhdr)); switch (nhdr_l.n_type) { case NT_PRSTATUS: { raw_size = 0; if (elfhdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD && nhdr_l.n_namesz == 0x8 && !strcmp(name,"FreeBSD")) { if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { raw_size = (uint64_t)*((uint32_t *) (uintptr_t)(name + ELF_ALIGN((int32_t) nhdr_l.n_namesz, 4) + 8)); ver = (uintptr_t)NOTE_OFFSET_32(nhdr, nhdr_l.n_namesz,0); if (*((int *)ver) == 1) pid = PID32(nhdr, nhdr_l.n_namesz, 24); } else { raw_size = *((uint64_t *)(uintptr_t) (name + ELF_ALIGN((int32_t) nhdr_l.n_namesz, 8) + 16)); ver = (uintptr_t)NOTE_OFFSET_64(nhdr, nhdr_l.n_namesz,0); if (*((int *)ver) == 1) pid = PID64(nhdr, nhdr_l.n_namesz, 40); } xlatetom(elf, elfhdr, &raw_size, &raw_size, ELF_T_WORD, sizeof(uint64_t)); xlatetom(elf, elfhdr, &pid, &pid, ELF_T_WORD, sizeof(pid_t)); } if (raw_size != 0 && style == STYLE_SYSV) { (void) snprintf(buf, BUF_SIZE, "%s/%d", ".reg", pid); tbl_append(); tbl_print(buf, 0); tbl_print_num(raw_size, radix, 1); tbl_print_num(0, radix, 2); if (!reg_pseudo) { tbl_append(); tbl_print(".reg", 0); tbl_print_num(raw_size, radix, 1); tbl_print_num(0, radix, 2); reg_pseudo = 1; text_size_total += raw_size; } text_size_total += raw_size; } } break; case NT_FPREGSET: /* same as NT_PRFPREG */ if (style == STYLE_SYSV) { (void) snprintf(buf, BUF_SIZE, "%s/%d", ".reg2", pid); tbl_append(); tbl_print(buf, 0); tbl_print_num(nhdr_l.n_descsz, radix, 1); tbl_print_num(0, radix, 2); if (!reg2_pseudo) { tbl_append(); tbl_print(".reg2", 0); tbl_print_num(nhdr_l.n_descsz, radix, 1); tbl_print_num(0, radix, 2); reg2_pseudo = 1; text_size_total += nhdr_l.n_descsz; } text_size_total += nhdr_l.n_descsz; } break; case NT_AUXV: if (style == STYLE_SYSV) { tbl_append(); tbl_print(".auxv", 0); tbl_print_num(nhdr_l.n_descsz, radix, 1); tbl_print_num(0, radix, 2); text_size_total += nhdr_l.n_descsz; } break; case NT_PRXFPREG: if (style == STYLE_SYSV) { (void) snprintf(buf, BUF_SIZE, "%s/%d", ".reg-xfp", pid); tbl_append(); tbl_print(buf, 0); tbl_print_num(nhdr_l.n_descsz, radix, 1); tbl_print_num(0, radix, 2); if (!regxfp_pseudo) { tbl_append(); tbl_print(".reg-xfp", 0); tbl_print_num(nhdr_l.n_descsz, radix, 1); tbl_print_num(0, radix, 2); regxfp_pseudo = 1; text_size_total += nhdr_l.n_descsz; } text_size_total += nhdr_l.n_descsz; } break; case NT_PSINFO: case NT_PRPSINFO: { /* FreeBSD 64-bit */ if (nhdr_l.n_descsz == 0x78 && !strcmp(name,"FreeBSD")) { *cmd_line = strdup(NOTE_OFFSET_64(nhdr, nhdr_l.n_namesz, 33)); /* FreeBSD 32-bit */ } else if (nhdr_l.n_descsz == 0x6c && !strcmp(name,"FreeBSD")) { *cmd_line = strdup(NOTE_OFFSET_32(nhdr, nhdr_l.n_namesz, 25)); } /* Strip any trailing spaces */ if (*cmd_line != NULL) { char *s; s = *cmd_line + strlen(*cmd_line); while (s > *cmd_line) { if (*(s-1) != 0x20) break; s--; } *s = 0; } break; } case NT_PSTATUS: case NT_LWPSTATUS: default: break; } NEXT_NOTE(elfhdr, nhdr_l.n_descsz, nhdr_l.n_namesz, offset); } } /* * Handles program headers except for PT_NOTE, when sysv output stlye is * choosen, prints out the segment name and length. For berkely output * style only PT_LOAD segments are handled, and text, * data, bss size is calculated for them. */ static void handle_phdr(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr, uint32_t idx, const char *name) { uint64_t addr, size; int split; char buf[BUF_SIZE]; if (elf == NULL || elfhdr == NULL || phdr == NULL) return; size = addr = 0; split = (phdr->p_memsz > 0) && (phdr->p_filesz > 0) && (phdr->p_memsz > phdr->p_filesz); if (style == STYLE_SYSV) { (void) snprintf(buf, BUF_SIZE, "%s%d%s", name, idx, (split ? "a" : "")); tbl_append(); tbl_print(buf, 0); tbl_print_num(phdr->p_filesz, radix, 1); tbl_print_num(phdr->p_vaddr, radix, 2); text_size_total += phdr->p_filesz; if (split) { size = phdr->p_memsz - phdr->p_filesz; addr = phdr->p_vaddr + phdr->p_filesz; (void) snprintf(buf, BUF_SIZE, "%s%d%s", name, idx, "b"); text_size_total += phdr->p_memsz - phdr->p_filesz; tbl_append(); tbl_print(buf, 0); tbl_print_num(size, radix, 1); tbl_print_num(addr, radix, 2); } } else { if (phdr->p_type != PT_LOAD) return; if ((phdr->p_flags & PF_W) && !(phdr->p_flags & PF_X)) { data_size += phdr->p_filesz; if (split) data_size += phdr->p_memsz - phdr->p_filesz; } else { text_size += phdr->p_filesz; if (split) text_size += phdr->p_memsz - phdr->p_filesz; } } } /* * Given a core dump file, this function maps program headers to segments. */ static int handle_core(char const *name, Elf *elf, GElf_Ehdr *elfhdr) { GElf_Phdr phdr; uint32_t i; char *core_cmdline; const char *seg_name; if (name == NULL || elf == NULL || elfhdr == NULL) return (RETURN_DATAERR); if (elfhdr->e_shnum != 0 || elfhdr->e_type != ET_CORE) return (RETURN_DATAERR); seg_name = core_cmdline = NULL; if (style == STYLE_SYSV) sysv_header(name, NULL); else berkeley_header(); for (i = 0; i < elfhdr->e_phnum; i++) { if (gelf_getphdr(elf, i, &phdr) != NULL) { if (phdr.p_type == PT_NOTE) { handle_phdr(elf, elfhdr, &phdr, i, "note"); handle_core_note(elf, elfhdr, &phdr, &core_cmdline); } else { switch(phdr.p_type) { case PT_NULL: seg_name = "null"; break; case PT_LOAD: seg_name = "load"; break; case PT_DYNAMIC: seg_name = "dynamic"; break; case PT_INTERP: seg_name = "interp"; break; case PT_SHLIB: seg_name = "shlib"; break; case PT_PHDR: seg_name = "phdr"; break; case PT_GNU_EH_FRAME: seg_name = "eh_frame_hdr"; break; case PT_GNU_STACK: seg_name = "stack"; break; default: seg_name = "segment"; } handle_phdr(elf, elfhdr, &phdr, i, seg_name); } } } if (style == STYLE_BERKELEY) { if (core_cmdline != NULL) { berkeley_footer(core_cmdline, name, "core file invoked as"); } else { berkeley_footer(core_cmdline, name, "core file"); } } else { sysv_footer(); if (core_cmdline != NULL) { (void) printf(" (core file invoked as %s)\n\n", core_cmdline); } else { (void) printf(" (core file)\n\n"); } } free(core_cmdline); return (RETURN_OK); } /* * Given an elf object,ar(1) filename, and based on the output style * and radix format the various sections and their length will be printed * or the size of the text, data, bss sections will be printed out. */ static int handle_elf(char const *name) { GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf *elf, *elf1; Elf_Arhdr *arhdr; Elf_Scn *scn; Elf_Cmd elf_cmd; int exit_code, fd; if (name == NULL) return (RETURN_NOINPUT); if ((fd = open(name, O_RDONLY, 0)) < 0) return (RETURN_NOINPUT); elf_cmd = ELF_C_READ; elf1 = elf_begin(fd, elf_cmd, NULL); while ((elf = elf_begin(fd, elf_cmd, elf1)) != NULL) { arhdr = elf_getarhdr(elf); if (elf_kind(elf) == ELF_K_NONE && arhdr == NULL) { (void) elf_end(elf); (void) elf_end(elf1); (void) close(fd); return (RETURN_DATAERR); } if (elf_kind(elf) != ELF_K_ELF || (gelf_getehdr(elf, &elfhdr) == NULL)) { elf_cmd = elf_next(elf); (void) elf_end(elf); warnx("%s: File format not recognized", arhdr->ar_name); continue; } - /* Core dumps are handled seperately */ + /* Core dumps are handled separately */ if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { exit_code = handle_core(name, elf, &elfhdr); (void) elf_end(elf); (void) elf_end(elf1); (void) close(fd); return (exit_code); } else { scn = NULL; if (style == STYLE_BERKELEY) { berkeley_header(); while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != NULL) berkeley_calc(&shdr); } } else { sysv_header(name, arhdr); scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != NULL) sysv_calc(elf, &elfhdr, &shdr); } } if (style == STYLE_BERKELEY) { if (arhdr != NULL) { berkeley_footer(name, arhdr->ar_name, "ex"); } else { berkeley_footer(name, NULL, "ex"); } } else { sysv_footer(); } } elf_cmd = elf_next(elf); (void) elf_end(elf); } (void) elf_end(elf1); (void) close(fd); return (RETURN_OK); } /* * Sysv formatting helper functions. */ static void sysv_header(const char *name, Elf_Arhdr *arhdr) { text_size_total = 0; if (arhdr != NULL) (void) printf("%s (ex %s):\n", arhdr->ar_name, name); else (void) printf("%s :\n", name); tbl_new(3); tbl_append(); tbl_print("section", 0); tbl_print("size", 1); tbl_print("addr", 2); } static void sysv_calc(Elf *elf, GElf_Ehdr *elfhdr, GElf_Shdr *shdr) { char *section_name; section_name = elf_strptr(elf, elfhdr->e_shstrndx, (size_t) shdr->sh_name); if ((shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_STRTAB || shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) && shdr->sh_addr == 0) return; tbl_append(); tbl_print(section_name, 0); tbl_print_num(shdr->sh_size, radix, 1); tbl_print_num(shdr->sh_addr, radix, 2); text_size_total += shdr->sh_size; } static void sysv_footer(void) { tbl_append(); tbl_print("Total", 0); tbl_print_num(text_size_total, radix, 1); tbl_flush(); putchar('\n'); } /* * berkeley style output formatting helper functions. */ static void berkeley_header(void) { static int printed; text_size = data_size = bss_size = 0; if (!printed) { tbl_new(6); tbl_append(); tbl_print("text", 0); tbl_print("data", 1); tbl_print("bss", 2); if (radix == RADIX_OCTAL) tbl_print("oct", 3); else tbl_print("dec", 3); tbl_print("hex", 4); tbl_print("filename", 5); printed = 1; } } static void berkeley_calc(GElf_Shdr *shdr) { if (shdr != NULL) { if (!(shdr->sh_flags & SHF_ALLOC)) return; if ((shdr->sh_flags & SHF_ALLOC) && ((shdr->sh_flags & SHF_EXECINSTR) || !(shdr->sh_flags & SHF_WRITE))) text_size += shdr->sh_size; else if ((shdr->sh_flags & SHF_ALLOC) && (shdr->sh_flags & SHF_WRITE) && (shdr->sh_type != SHT_NOBITS)) data_size += shdr->sh_size; else bss_size += shdr->sh_size; } } static void berkeley_totals(void) { long unsigned int grand_total; grand_total = text_size_total + data_size_total + bss_size_total; tbl_append(); tbl_print_num(text_size_total, radix, 0); tbl_print_num(data_size_total, radix, 1); tbl_print_num(bss_size_total, radix, 2); if (radix == RADIX_OCTAL) tbl_print_num(grand_total, RADIX_OCTAL, 3); else tbl_print_num(grand_total, RADIX_DECIMAL, 3); tbl_print_num(grand_total, RADIX_HEX, 4); } static void berkeley_footer(const char *name, const char *ar_name, const char *msg) { char buf[BUF_SIZE]; total_size = text_size + data_size + bss_size; if (show_totals) { text_size_total += text_size; bss_size_total += bss_size; data_size_total += data_size; } tbl_append(); tbl_print_num(text_size, radix, 0); tbl_print_num(data_size, radix, 1); tbl_print_num(bss_size, radix, 2); if (radix == RADIX_OCTAL) tbl_print_num(total_size, RADIX_OCTAL, 3); else tbl_print_num(total_size, RADIX_DECIMAL, 3); tbl_print_num(total_size, RADIX_HEX, 4); if (ar_name != NULL && name != NULL) (void) snprintf(buf, BUF_SIZE, "%s (%s %s)", ar_name, msg, name); else if (ar_name != NULL && name == NULL) (void) snprintf(buf, BUF_SIZE, "%s (%s)", ar_name, msg); else (void) snprintf(buf, BUF_SIZE, "%s", name); tbl_print(buf, 5); } static void tbl_new(int col) { assert(tb == NULL); assert(col > 0); if ((tb = calloc(1, sizeof(*tb))) == NULL) err(EXIT_FAILURE, "calloc"); if ((tb->tbl = calloc(col, sizeof(*tb->tbl))) == NULL) err(EXIT_FAILURE, "calloc"); if ((tb->width = calloc(col, sizeof(*tb->width))) == NULL) err(EXIT_FAILURE, "calloc"); tb->col = col; tb->row = 0; } static void tbl_print(const char *s, int col) { int len; assert(tb != NULL && tb->col > 0 && tb->row > 0 && col < tb->col); assert(s != NULL && tb->tbl[col][tb->row - 1] == NULL); if ((tb->tbl[col][tb->row - 1] = strdup(s)) == NULL) err(EXIT_FAILURE, "strdup"); len = strlen(s); if (len > tb->width[col]) tb->width[col] = len; } static void tbl_print_num(uint64_t num, enum radix_style rad, int col) { char buf[BUF_SIZE]; (void) snprintf(buf, BUF_SIZE, (rad == RADIX_DECIMAL ? "%ju" : ((rad == RADIX_OCTAL) ? "0%jo" : "0x%jx")), (uintmax_t) num); tbl_print(buf, col); } static void tbl_append(void) { int i; assert(tb != NULL && tb->col > 0); tb->row++; for (i = 0; i < tb->col; i++) { tb->tbl[i] = realloc(tb->tbl[i], sizeof(*tb->tbl[i]) * tb->row); if (tb->tbl[i] == NULL) err(EXIT_FAILURE, "realloc"); tb->tbl[i][tb->row - 1] = NULL; } } static void tbl_flush(void) { const char *str; int i, j; if (tb == NULL) return; assert(tb->col > 0); for (i = 0; i < tb->row; i++) { if (style == STYLE_BERKELEY) printf(" "); for (j = 0; j < tb->col; j++) { str = (tb->tbl[j][i] != NULL ? tb->tbl[j][i] : ""); if (style == STYLE_SYSV && j == 0) printf("%-*s", tb->width[j], str); else if (style == STYLE_BERKELEY && j == tb->col - 1) printf("%s", str); else printf("%*s", tb->width[j], str); if (j == tb->col -1) putchar('\n'); else printf(" "); } } for (i = 0; i < tb->col; i++) { for (j = 0; j < tb->row; j++) { if (tb->tbl[i][j]) free(tb->tbl[i][j]); } free(tb->tbl[i]); } free(tb->tbl); free(tb->width); free(tb); tb = NULL; } #define USAGE_MESSAGE "\ Usage: %s [options] file ...\n\ Display sizes of ELF sections.\n\n\ Options:\n\ --format=format Display output in specified format. Supported\n\ values are `berkeley' and `sysv'.\n\ --help Display this help message and exit.\n\ --radix=radix Display numeric values in the specified radix.\n\ Supported values are: 8, 10 and 16.\n\ --totals Show cumulative totals of section sizes.\n\ --version Display a version identifier and exit.\n\ -A Equivalent to `--format=sysv'.\n\ -B Equivalent to `--format=berkeley'.\n\ -V Equivalent to `--version'.\n\ -d Equivalent to `--radix=10'.\n\ -h Same as option --help.\n\ -o Equivalent to `--radix=8'.\n\ -t Equivalent to option --totals.\n\ -x Equivalent to `--radix=16'.\n" static void usage(void) { (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } static void show_version(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } Index: vendor/elftoolchain/dist/strings/strings.1 =================================================================== --- vendor/elftoolchain/dist/strings/strings.1 (revision 282910) +++ vendor/elftoolchain/dist/strings/strings.1 (revision 282911) @@ -1,162 +1,162 @@ .\" 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. .\" -.\" $Id: strings.1 2352 2011-12-19 11:21:10Z jkoshy $ +.\" $Id: strings.1 3195 2015-05-12 17:22:19Z emaste $ .\" .Dd December 19, 2011 .Dt STRINGS 1 .Os .Sh NAME .Nm strings .Nd "print the strings of printable characters in files" .Sh SYNOPSIS .Nm .Op Fl a | Fl -all .Op Fl e Ar encoding | Fl -encoding= Ns Ar encoding .Op Fl f | Fl -print-file-name .Op Fl h | Fl -help .Op Fl n Ar number | Fl -bytes= Ns Ar number | Fl Ar number .Op Fl o .Op Fl t Ar radix | Fl -radix= Ns Ar radix .Op Fl v | Fl -version .Op Ar .Sh DESCRIPTION For each .Ar file specified, the .Nm utility prints contiguous sequences of printable characters that are at least .Va n characters long and are followed by an unprintable character. The default value of .Va n is 4. By default, the .Nm utility only scans the initialized and loaded sections of ELF objects; for other file types, the entire file is scanned. The .Nm utility is mainly used for determining the contents of non-text files. .Pp If no file name is specified as an argument, standard input is read. .Pp The following options are available: .Bl -tag -width indent .It Fl a | Fl -all For ELF objects, scan the entire file for printable strings. .It Fl e Ar encoding | Fl -encoding= Ns Ar encoding Select the character encoding to be used while searching for strings. Valid values for argument .Ar encoding are: .Bl -tag -width indent -compact .It Ar s for single 7-bit-byte characters (ASCII, ISO 8859). .It Ar S for single 8-bit-byte characters. .It Ar l for 16-bit little-endian. .It Ar b for 16-bit big-endian. .It Ar L for 32-bit little-endian. .It Ar B for 32-bit big-endian. .El The default is to assume that characters are encoded using a single 7-bit byte. .It Fl f | Fl -print-file-name Print the name of the file before each string. .It Fl h | Fl -help Print a usage summary and exit. .It Xo .Fl n Ar number | .Fl -bytes= Ns Ar number | .Fl Ar number .Xc Print the contiguous character sequence of at least .Ar number characters long, instead of the default of 4 characters. .It Fl o Equivalent to specifying .Fl t Ar o . .It Fl t Ar radix | Fl -radix= Ns Ar radix Print the offset from the start of the file before each string using the specified radix. Valid values for argument .Ar radix are: .Bl -tag -width indent -compact .It Ar d for decimal .It Ar o for octal .It Ar x for hexadecimal .El .It Fl v | Fl -version Display a version identifier and exit. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES To display strings in .Pa /bin/ls use: .Dl "$ strings /bin/ls" .Pp To display strings in all sections of .Pa /bin/ln use: .Dl "$ strings -a /bin/ln" .Pp To display strings in all sections of .Pa /bin/cat prefixed with the filename and the offset within the file use: .Dl "$ strings -a -f -t x /bin/cat" .Sh SEE ALSO .Xr ar 1 , .Xr nm 1 , .Xr objdump 1 , .Xr ranlib , .Xr readelf 1 , .Xr size 1 .Sh HISTORY The first FreeBSD .Nm utility appeared in .Fx v3. It was later discontinued in .Fx v5 , when i386-only a.out format was dropped in favor of ELF. .Sh AUTHORS .An -nosplit The .Nm utility was re-written by -.An S.Sam Arun Raj Aq samarunraj@gmail.com . +.An S.Sam Arun Raj Aq Mt samarunraj@gmail.com . This manual page was written by -.An S.Sam Arun Raj Aq samarunraj@gmail.com . +.An S.Sam Arun Raj Aq Mt samarunraj@gmail.com . Index: vendor/elftoolchain/dist/test/ar/plugin/Makefile =================================================================== --- vendor/elftoolchain/dist/test/ar/plugin/Makefile (revision 282910) +++ vendor/elftoolchain/dist/test/ar/plugin/Makefile (revision 282911) @@ -1,15 +1,17 @@ -# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ +# $Id: Makefile 3192 2015-05-04 17:20:15Z jkoshy $ PLUGINS= ardiff teraser all: ${PLUGINS} ${PLUGINS}: .for plugin in ${.TARGET} ${MAKE} -f Makefile.${plugin} .endfor -clean cleandepend depend: +test: .PHONY + +clean cleandepend depend: .PHONY .for plugin in ${PLUGINS} ${MAKE} -f Makefile.${plugin} ${.TARGET} .endfor Index: vendor/elftoolchain/dist/test/elfcopy/plugin/Makefile =================================================================== --- vendor/elftoolchain/dist/test/elfcopy/plugin/Makefile (revision 282910) +++ vendor/elftoolchain/dist/test/elfcopy/plugin/Makefile (revision 282911) @@ -1,15 +1,17 @@ -# $Id: Makefile 3025 2014-04-18 16:20:25Z jkoshy $ +# $Id: Makefile 3192 2015-05-04 17:20:15Z jkoshy $ PLUGINS= ardiff teraser all: ${PLUGINS} ${PLUGINS}: .for plugin in ${.TARGET} ${MAKE} -f Makefile.${plugin} .endfor -clean cleandepend depend: +test: .PHONY + +clean cleandepend depend: .PHONY .for plugin in ${PLUGINS} ${MAKE} -f Makefile.${plugin} ${.TARGET} .endfor