Index: vendor/elftoolchain/dist/addr2line/addr2line.c =================================================================== --- vendor/elftoolchain/dist/addr2line/addr2line.c (revision 317072) +++ vendor/elftoolchain/dist/addr2line/addr2line.c (revision 317073) @@ -1,734 +1,734 @@ /*- * 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 "uthash.h" #include "_elftc.h" -ELFTC_VCSID("$Id: addr2line.c 3446 2016-05-03 01:31:17Z emaste $"); +ELFTC_VCSID("$Id: addr2line.c 3499 2016-11-25 16:06:29Z emaste $"); struct Func { char *name; Dwarf_Unsigned lopc; Dwarf_Unsigned hipc; Dwarf_Unsigned call_file; Dwarf_Unsigned call_line; Dwarf_Ranges *ranges; Dwarf_Signed ranges_cnt; struct Func *inlined_caller; STAILQ_ENTRY(Func) next; }; struct CU { Dwarf_Off off; Dwarf_Unsigned lopc; Dwarf_Unsigned hipc; char **srcfiles; Dwarf_Signed nsrcfiles; STAILQ_HEAD(, Func) funclist; UT_hash_handle hh; }; static struct option longopts[] = { {"addresses", no_argument, NULL, 'a'}, {"target" , required_argument, NULL, 'b'}, {"demangle", no_argument, NULL, 'C'}, {"exe", required_argument, NULL, 'e'}, {"functions", no_argument, NULL, 'f'}, {"inlines", no_argument, NULL, 'i'}, {"section", required_argument, NULL, 'j'}, {"pretty-print", no_argument, NULL, 'p'}, {"basename", no_argument, NULL, 's'}, {"help", no_argument, NULL, 'H'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; static int demangle, func, base, inlines, print_addr, pretty_print; static char unknown[] = { '?', '?', '\0' }; static Dwarf_Addr section_base; static struct CU *culist; #define USAGE_MESSAGE "\ Usage: %s [options] hexaddress...\n\ Map program addresses to source file names and line numbers.\n\n\ Options:\n\ -a | --addresses Display address prior to line number info.\n\ -b TGT | --target=TGT (Accepted but ignored).\n\ -e EXE | --exe=EXE Use program \"EXE\" to translate addresses.\n\ -f | --functions Display function names.\n\ -i | --inlines Display caller info for inlined functions.\n\ -j NAME | --section=NAME Values are offsets into section \"NAME\".\n\ -p | --pretty-print Display line number info and function name\n\ in human readable manner.\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 struct Func * search_func(struct CU *cu, Dwarf_Unsigned addr) { struct Func *f, *f0; Dwarf_Unsigned lopc, hipc, addr_base; int i; f0 = NULL; STAILQ_FOREACH(f, &cu->funclist, next) { if (f->ranges != NULL) { addr_base = 0; for (i = 0; i < f->ranges_cnt; i++) { if (f->ranges[i].dwr_type == DW_RANGES_END) break; if (f->ranges[i].dwr_type == DW_RANGES_ADDRESS_SELECTION) { addr_base = f->ranges[i].dwr_addr2; continue; } /* DW_RANGES_ENTRY */ lopc = f->ranges[i].dwr_addr1 + addr_base; hipc = f->ranges[i].dwr_addr2 + addr_base; if (addr >= lopc && addr < hipc) { if (f0 == NULL || (lopc >= f0->lopc && hipc <= f0->hipc)) { f0 = f; f0->lopc = lopc; f0->hipc = hipc; break; } } } } else if (addr >= f->lopc && addr < f->hipc) { if (f0 == NULL || (f->lopc >= f0->lopc && f->hipc <= f0->hipc)) f0 = f; } } return (f0); } static void collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct CU *cu) { Dwarf_Die ret_die, abst_die, spec_die; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned lopc, hipc, ranges_off; Dwarf_Signed ranges_cnt; Dwarf_Off ref; Dwarf_Attribute abst_at, spec_at; Dwarf_Ranges *ranges; const char *funcname; struct Func *f; int found_ranges, ret; f = NULL; abst_die = spec_die = NULL; if (dwarf_tag(die, &tag, &de)) { warnx("dwarf_tag: %s", dwarf_errmsg(de)); goto cont_search; } if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || tag == DW_TAG_inlined_subroutine) { /* * Function address range can be specified by either * a DW_AT_ranges attribute which points to a range list or * by a pair of DW_AT_low_pc and DW_AT_high_pc attributes. */ ranges = NULL; ranges_cnt = 0; found_ranges = 0; if (dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, &de) == DW_DLV_OK && dwarf_get_ranges(dbg, (Dwarf_Off) ranges_off, &ranges, &ranges_cnt, NULL, &de) == DW_DLV_OK) { if (ranges != NULL && ranges_cnt > 0) { found_ranges = 1; goto get_func_name; } } /* * Search for DW_AT_low_pc/DW_AT_high_pc if ranges pointer * not found. */ 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; get_func_name: /* * Most common case the function name is stored in DW_AT_name * attribute. */ if (dwarf_attrval_string(die, DW_AT_name, &funcname, &de) == DW_DLV_OK) goto add_func; /* * For inlined function, the actual name is probably in the DIE * referenced by DW_AT_abstract_origin. (if present) */ if (dwarf_attr(die, DW_AT_abstract_origin, &abst_at, &de) == DW_DLV_OK && dwarf_global_formref(abst_at, &ref, &de) == DW_DLV_OK && dwarf_offdie(dbg, ref, &abst_die, &de) == DW_DLV_OK && dwarf_attrval_string(abst_die, DW_AT_name, &funcname, &de) == DW_DLV_OK) goto add_func; /* * 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) == DW_DLV_OK && dwarf_global_formref(spec_at, &ref, &de) == DW_DLV_OK && dwarf_offdie(dbg, ref, &spec_die, &de) == DW_DLV_OK && dwarf_attrval_string(spec_die, DW_AT_name, &funcname, &de) == DW_DLV_OK) goto add_func; /* Skip if no name associated with this DIE. */ goto cont_search; add_func: if ((f = calloc(1, sizeof(*f))) == NULL) err(EXIT_FAILURE, "calloc"); if ((f->name = strdup(funcname)) == NULL) err(EXIT_FAILURE, "strdup"); if (found_ranges) { f->ranges = ranges; f->ranges_cnt = ranges_cnt; } else { f->lopc = lopc; f->hipc = hipc; } if (tag == DW_TAG_inlined_subroutine) { f->inlined_caller = parent; dwarf_attrval_unsigned(die, DW_AT_call_file, &f->call_file, &de); dwarf_attrval_unsigned(die, DW_AT_call_line, &f->call_line, &de); } STAILQ_INSERT_TAIL(&cu->funclist, f, 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) { if (f != NULL) collect_func(dbg, ret_die, f, cu); else collect_func(dbg, ret_die, parent, cu); } /* Search sibling. */ ret = dwarf_siblingof(dbg, die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) collect_func(dbg, ret_die, parent, cu); /* Cleanup */ dwarf_dealloc(dbg, die, DW_DLA_DIE); if (abst_die != NULL) dwarf_dealloc(dbg, abst_die, DW_DLA_DIE); if (spec_die != NULL) dwarf_dealloc(dbg, spec_die, DW_DLA_DIE); } static void print_inlines(struct CU *cu, struct Func *f, Dwarf_Unsigned call_file, Dwarf_Unsigned call_line) { char demangled[1024]; char *file; if (call_file > 0 && (Dwarf_Signed) call_file <= cu->nsrcfiles) file = cu->srcfiles[call_file - 1]; else file = unknown; if (pretty_print) printf(" (inlined by) "); if (func) { if (demangle && !elftc_demangle(f->name, demangled, sizeof(demangled), 0)) { if (pretty_print) printf("%s at ", demangled); else printf("%s\n", demangled); } else { if (pretty_print) printf("%s at ", f->name); else printf("%s\n", f->name); } } (void) printf("%s:%ju\n", base ? basename(file) : file, (uintmax_t) call_line); if (f->inlined_caller != NULL) print_inlines(cu, f->inlined_caller, f->call_file, f->call_line); } static void translate(Dwarf_Debug dbg, Elf *e, const char* addrstr) { Dwarf_Die die, ret_die; Dwarf_Line *lbuf; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned lopc, hipc, addr, lineno, plineno; Dwarf_Signed lcount; Dwarf_Addr lineaddr, plineaddr; Dwarf_Off off; struct CU *cu; struct Func *f; const char *funcname; char *file, *file0, *pfile; char demangled[1024]; int ec, i, ret; addr = strtoull(addrstr, NULL, 16); addr += section_base; lineno = 0; file = unknown; cu = NULL; die = NULL; while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { die = NULL; while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) { if (die != NULL) dwarf_dealloc(dbg, die, DW_DLA_DIE); die = ret_die; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); goto next_cu; } /* XXX: What about DW_TAG_partial_unit? */ if (tag == DW_TAG_compile_unit) break; } if (ret_die == NULL) { warnx("could not find DW_TAG_compile_unit die"); goto next_cu; } if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) == DW_DLV_OK) { if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de) == DW_DLV_OK) { /* * Check if the address falls into the PC * range of this CU. */ if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) goto out; } else { /* Assume ~0ULL if DW_AT_high_pc not present */ hipc = ~0ULL; } /* * Record the CU in the hash table for faster lookup * later. */ if (dwarf_dieoffset(die, &off, &de) != DW_DLV_OK) { warnx("dwarf_dieoffset failed: %s", dwarf_errmsg(de)); goto out; } HASH_FIND(hh, culist, &off, sizeof(off), cu); if (cu == NULL) { if ((cu = calloc(1, sizeof(*cu))) == NULL) err(EXIT_FAILURE, "calloc"); cu->off = off; cu->lopc = lopc; cu->hipc = hipc; STAILQ_INIT(&cu->funclist); HASH_ADD(hh, culist, off, sizeof(off), cu); } if (addr >= lopc && addr < hipc) break; } next_cu: if (die != NULL) { dwarf_dealloc(dbg, die, DW_DLA_DIE); die = NULL; } } if (ret != DW_DLV_OK || die == NULL) goto out; switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { case DW_DLV_OK: break; case DW_DLV_NO_ENTRY: /* If a CU lacks debug info, just skip it. */ goto out; default: 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: f = NULL; funcname = NULL; if (ret == DW_DLV_OK && (func || inlines) && cu != NULL) { if (cu->srcfiles == NULL) if (dwarf_srcfiles(die, &cu->srcfiles, &cu->nsrcfiles, &de)) warnx("dwarf_srcfiles: %s", dwarf_errmsg(de)); if (STAILQ_EMPTY(&cu->funclist)) { collect_func(dbg, die, NULL, cu); die = NULL; } f = search_func(cu, addr); if (f != NULL) funcname = f->name; } if (print_addr) { if ((ec = gelf_getclass(e)) == ELFCLASSNONE) { warnx("gelf_getclass failed: %s", elf_errmsg(-1)); ec = ELFCLASS64; } if (ec == ELFCLASS32) { if (pretty_print) printf("0x%08jx: ", (uintmax_t) addr); else printf("0x%08jx\n", (uintmax_t) addr); } else { if (pretty_print) printf("0x%016jx: ", (uintmax_t) addr); else printf("0x%016jx\n", (uintmax_t) addr); } } if (func) { if (funcname == NULL) funcname = unknown; if (demangle && !elftc_demangle(funcname, demangled, sizeof(demangled), 0)) { if (pretty_print) printf("%s at ", demangled); else printf("%s\n", demangled); } else { if (pretty_print) printf("%s at ", funcname); else printf("%s\n", funcname); } } (void) printf("%s:%ju\n", base ? basename(file) : file, (uintmax_t) lineno); if (ret == DW_DLV_OK && inlines && cu != NULL && cu->srcfiles != NULL && f != NULL && f->inlined_caller != NULL) print_inlines(cu, f->inlined_caller, f->call_file, f->call_line); if (die != NULL) dwarf_dealloc(dbg, die, DW_DLA_DIE); /* * 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, "ab:Ce:fij:psHV", longopts, NULL)) != -1) { switch (opt) { case 'a': print_addr = 1; break; case 'b': /* ignored */ break; case 'C': demangle = 1; break; case 'e': exe = optarg; break; case 'f': func = 1; break; case 'i': inlines = 1; break; case 'j': section = optarg; break; case 'p': pretty_print = 1; 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, e, argv[i]); - else - while (fgets(line, sizeof(line), stdin) != NULL) { + else { + setvbuf(stdout, NULL, _IOLBF, 0); + while (fgets(line, sizeof(line), stdin) != NULL) translate(dbg, e, line); - fflush(stdout); - } + } dwarf_finish(dbg, &de); (void) elf_end(e); exit(0); } Index: vendor/elftoolchain/dist/ar/os.FreeBSD.mk =================================================================== --- vendor/elftoolchain/dist/ar/os.FreeBSD.mk (nonexistent) +++ vendor/elftoolchain/dist/ar/os.FreeBSD.mk (revision 317073) @@ -0,0 +1,2 @@ +DPADD+= ${LIBBZ2} +LDADD+= -lbz2 Property changes on: vendor/elftoolchain/dist/ar/os.FreeBSD.mk ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/elftoolchain/dist/common/elfdefinitions.h =================================================================== --- vendor/elftoolchain/dist/common/elfdefinitions.h (revision 317072) +++ vendor/elftoolchain/dist/common/elfdefinitions.h (revision 317073) @@ -1,2892 +1,2900 @@ /*- * Copyright (c) 2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: elfdefinitions.h 3485 2016-08-18 13:38:52Z emaste $ + * $Id: elfdefinitions.h 3515 2017-01-24 22:04:22Z emaste $ */ /* * These definitions are based on: * - The public specification of the ELF format as defined in the * October 2009 draft of System V ABI. * See: http://www.sco.com/developers/gabi/latest/ch4.intro.html * - The May 1998 (version 1.5) draft of "The ELF-64 object format". * - Processor-specific ELF ABI definitions for sparc, i386, amd64, mips, * ia64, and powerpc processors. * - The "Linkers and Libraries Guide", from Sun Microsystems. */ #ifndef _ELFDEFINITIONS_H_ #define _ELFDEFINITIONS_H_ #include /* * Types of capabilities. */ #define _ELF_DEFINE_CAPABILITIES() \ _ELF_DEFINE_CA(CA_SUNW_NULL, 0, "ignored") \ _ELF_DEFINE_CA(CA_SUNW_HW_1, 1, "hardware capability") \ _ELF_DEFINE_CA(CA_SUNW_SW_1, 2, "software capability") #undef _ELF_DEFINE_CA #define _ELF_DEFINE_CA(N, V, DESCR) N = V , enum { _ELF_DEFINE_CAPABILITIES() CA__LAST__ }; /* * Flags used with dynamic linking entries. */ #define _ELF_DEFINE_DYN_FLAGS() \ _ELF_DEFINE_DF(DF_ORIGIN, 0x1, \ "object being loaded may refer to $ORIGIN") \ _ELF_DEFINE_DF(DF_SYMBOLIC, 0x2, \ "search library for references before executable") \ _ELF_DEFINE_DF(DF_TEXTREL, 0x4, \ "relocation entries may modify text segment") \ _ELF_DEFINE_DF(DF_BIND_NOW, 0x8, \ "process relocation entries at load time") \ _ELF_DEFINE_DF(DF_STATIC_TLS, 0x10, \ "uses static thread-local storage") #undef _ELF_DEFINE_DF #define _ELF_DEFINE_DF(N, V, DESCR) N = V , enum { _ELF_DEFINE_DYN_FLAGS() DF__LAST__ }; /* * Dynamic linking entry types. */ #define _ELF_DEFINE_DYN_TYPES() \ _ELF_DEFINE_DT(DT_NULL, 0, "end of array") \ _ELF_DEFINE_DT(DT_NEEDED, 1, "names a needed library") \ _ELF_DEFINE_DT(DT_PLTRELSZ, 2, \ "size in bytes of associated relocation entries") \ _ELF_DEFINE_DT(DT_PLTGOT, 3, \ "address associated with the procedure linkage table") \ _ELF_DEFINE_DT(DT_HASH, 4, \ "address of the symbol hash table") \ _ELF_DEFINE_DT(DT_STRTAB, 5, \ "address of the string table") \ _ELF_DEFINE_DT(DT_SYMTAB, 6, \ "address of the symbol table") \ _ELF_DEFINE_DT(DT_RELA, 7, \ "address of the relocation table") \ _ELF_DEFINE_DT(DT_RELASZ, 8, "size of the DT_RELA table") \ _ELF_DEFINE_DT(DT_RELAENT, 9, "size of each DT_RELA entry") \ _ELF_DEFINE_DT(DT_STRSZ, 10, "size of the string table") \ _ELF_DEFINE_DT(DT_SYMENT, 11, \ "size of a symbol table entry") \ _ELF_DEFINE_DT(DT_INIT, 12, \ "address of the initialization function") \ _ELF_DEFINE_DT(DT_FINI, 13, \ "address of the finalization function") \ _ELF_DEFINE_DT(DT_SONAME, 14, "names the shared object") \ _ELF_DEFINE_DT(DT_RPATH, 15, \ "runtime library search path") \ _ELF_DEFINE_DT(DT_SYMBOLIC, 16, \ "alter symbol resolution algorithm") \ _ELF_DEFINE_DT(DT_REL, 17, \ "address of the DT_REL table") \ _ELF_DEFINE_DT(DT_RELSZ, 18, "size of the DT_REL table") \ _ELF_DEFINE_DT(DT_RELENT, 19, "size of each DT_REL entry") \ _ELF_DEFINE_DT(DT_PLTREL, 20, \ "type of relocation entry in the procedure linkage table") \ _ELF_DEFINE_DT(DT_DEBUG, 21, "used for debugging") \ _ELF_DEFINE_DT(DT_TEXTREL, 22, \ "text segment may be written to during relocation") \ _ELF_DEFINE_DT(DT_JMPREL, 23, \ "address of relocation entries associated with the procedure linkage table") \ _ELF_DEFINE_DT(DT_BIND_NOW, 24, \ "bind symbols at loading time") \ _ELF_DEFINE_DT(DT_INIT_ARRAY, 25, \ "pointers to initialization functions") \ _ELF_DEFINE_DT(DT_FINI_ARRAY, 26, \ "pointers to termination functions") \ _ELF_DEFINE_DT(DT_INIT_ARRAYSZ, 27, "size of the DT_INIT_ARRAY") \ _ELF_DEFINE_DT(DT_FINI_ARRAYSZ, 28, "size of the DT_FINI_ARRAY") \ _ELF_DEFINE_DT(DT_RUNPATH, 29, \ "index of library search path string") \ _ELF_DEFINE_DT(DT_FLAGS, 30, \ "flags specific to the object being loaded") \ _ELF_DEFINE_DT(DT_ENCODING, 32, "standard semantics") \ _ELF_DEFINE_DT(DT_PREINIT_ARRAY, 32, \ "pointers to pre-initialization functions") \ _ELF_DEFINE_DT(DT_PREINIT_ARRAYSZ, 33, \ "size of pre-initialization array") \ _ELF_DEFINE_DT(DT_MAXPOSTAGS, 34, \ "the number of positive tags") \ _ELF_DEFINE_DT(DT_LOOS, 0x6000000DUL, \ "start of OS-specific types") \ _ELF_DEFINE_DT(DT_SUNW_AUXILIARY, 0x6000000DUL, \ "offset of string naming auxiliary filtees") \ _ELF_DEFINE_DT(DT_SUNW_RTLDINF, 0x6000000EUL, "rtld internal use") \ _ELF_DEFINE_DT(DT_SUNW_FILTER, 0x6000000FUL, \ "offset of string naming standard filtees") \ _ELF_DEFINE_DT(DT_SUNW_CAP, 0x60000010UL, \ "address of hardware capabilities section") \ +_ELF_DEFINE_DT(DT_SUNW_ASLR, 0x60000023UL, \ + "Address Space Layout Randomization flag") \ _ELF_DEFINE_DT(DT_HIOS, 0x6FFFF000UL, \ "end of OS-specific types") \ _ELF_DEFINE_DT(DT_VALRNGLO, 0x6FFFFD00UL, \ "start of range using the d_val field") \ _ELF_DEFINE_DT(DT_GNU_PRELINKED, 0x6FFFFDF5UL, \ "prelinking timestamp") \ _ELF_DEFINE_DT(DT_GNU_CONFLICTSZ, 0x6FFFFDF6UL, \ "size of conflict section") \ _ELF_DEFINE_DT(DT_GNU_LIBLISTSZ, 0x6FFFFDF7UL, \ "size of library list") \ _ELF_DEFINE_DT(DT_CHECKSUM, 0x6FFFFDF8UL, \ "checksum for the object") \ _ELF_DEFINE_DT(DT_PLTPADSZ, 0x6FFFFDF9UL, \ "size of PLT padding") \ _ELF_DEFINE_DT(DT_MOVEENT, 0x6FFFFDFAUL, \ "size of DT_MOVETAB entries") \ _ELF_DEFINE_DT(DT_MOVESZ, 0x6FFFFDFBUL, \ "total size of the MOVETAB table") \ _ELF_DEFINE_DT(DT_FEATURE, 0x6FFFFDFCUL, "feature values") \ _ELF_DEFINE_DT(DT_POSFLAG_1, 0x6FFFFDFDUL, \ "dynamic position flags") \ _ELF_DEFINE_DT(DT_SYMINSZ, 0x6FFFFDFEUL, \ "size of the DT_SYMINFO table") \ _ELF_DEFINE_DT(DT_SYMINENT, 0x6FFFFDFFUL, \ "size of a DT_SYMINFO entry") \ _ELF_DEFINE_DT(DT_VALRNGHI, 0x6FFFFDFFUL, \ "end of range using the d_val field") \ _ELF_DEFINE_DT(DT_ADDRRNGLO, 0x6FFFFE00UL, \ "start of range using the d_ptr field") \ _ELF_DEFINE_DT(DT_GNU_HASH, 0x6FFFFEF5UL, \ "GNU style hash tables") \ _ELF_DEFINE_DT(DT_TLSDESC_PLT, 0x6FFFFEF6UL, \ "location of PLT entry for TLS descriptor resolver calls") \ _ELF_DEFINE_DT(DT_TLSDESC_GOT, 0x6FFFFEF7UL, \ "location of GOT entry used by TLS descriptor resolver PLT entry") \ _ELF_DEFINE_DT(DT_GNU_CONFLICT, 0x6FFFFEF8UL, \ "address of conflict section") \ _ELF_DEFINE_DT(DT_GNU_LIBLIST, 0x6FFFFEF9UL, \ "address of conflict section") \ _ELF_DEFINE_DT(DT_CONFIG, 0x6FFFFEFAUL, \ "configuration file") \ _ELF_DEFINE_DT(DT_DEPAUDIT, 0x6FFFFEFBUL, \ "string defining audit libraries") \ _ELF_DEFINE_DT(DT_AUDIT, 0x6FFFFEFCUL, \ "string defining audit libraries") \ _ELF_DEFINE_DT(DT_PLTPAD, 0x6FFFFEFDUL, "PLT padding") \ _ELF_DEFINE_DT(DT_MOVETAB, 0x6FFFFEFEUL, \ "address of a move table") \ _ELF_DEFINE_DT(DT_SYMINFO, 0x6FFFFEFFUL, \ "address of the symbol information table") \ _ELF_DEFINE_DT(DT_ADDRRNGHI, 0x6FFFFEFFUL, \ "end of range using the d_ptr field") \ _ELF_DEFINE_DT(DT_VERSYM, 0x6FFFFFF0UL, \ "address of the version section") \ _ELF_DEFINE_DT(DT_RELACOUNT, 0x6FFFFFF9UL, \ "count of RELA relocations") \ _ELF_DEFINE_DT(DT_RELCOUNT, 0x6FFFFFFAUL, \ "count of REL relocations") \ _ELF_DEFINE_DT(DT_FLAGS_1, 0x6FFFFFFBUL, "flag values") \ _ELF_DEFINE_DT(DT_VERDEF, 0x6FFFFFFCUL, \ "address of the version definition segment") \ _ELF_DEFINE_DT(DT_VERDEFNUM, 0x6FFFFFFDUL, \ "the number of version definition entries") \ _ELF_DEFINE_DT(DT_VERNEED, 0x6FFFFFFEUL, \ "address of section with needed versions") \ _ELF_DEFINE_DT(DT_VERNEEDNUM, 0x6FFFFFFFUL, \ "the number of version needed entries") \ _ELF_DEFINE_DT(DT_LOPROC, 0x70000000UL, \ "start of processor-specific types") \ _ELF_DEFINE_DT(DT_ARM_SYMTABSZ, 0x70000001UL, \ "number of entries in the dynamic symbol table") \ _ELF_DEFINE_DT(DT_SPARC_REGISTER, 0x70000001UL, \ "index of an STT_SPARC_REGISTER symbol") \ _ELF_DEFINE_DT(DT_ARM_PREEMPTMAP, 0x70000002UL, \ "address of the preemption map") \ _ELF_DEFINE_DT(DT_MIPS_RLD_VERSION, 0x70000001UL, \ "version ID for runtime linker interface") \ _ELF_DEFINE_DT(DT_MIPS_TIME_STAMP, 0x70000002UL, \ "timestamp") \ _ELF_DEFINE_DT(DT_MIPS_ICHECKSUM, 0x70000003UL, \ "checksum of all external strings and common sizes") \ _ELF_DEFINE_DT(DT_MIPS_IVERSION, 0x70000004UL, \ "string table index of a version string") \ _ELF_DEFINE_DT(DT_MIPS_FLAGS, 0x70000005UL, \ "MIPS-specific flags") \ _ELF_DEFINE_DT(DT_MIPS_BASE_ADDRESS, 0x70000006UL, \ "base address for the executable/DSO") \ _ELF_DEFINE_DT(DT_MIPS_CONFLICT, 0x70000008UL, \ "address of .conflict section") \ _ELF_DEFINE_DT(DT_MIPS_LIBLIST, 0x70000009UL, \ "address of .liblist section") \ _ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTNO, 0x7000000AUL, \ "number of local GOT entries") \ _ELF_DEFINE_DT(DT_MIPS_CONFLICTNO, 0x7000000BUL, \ "number of entries in the .conflict section") \ _ELF_DEFINE_DT(DT_MIPS_LIBLISTNO, 0x70000010UL, \ "number of entries in the .liblist section") \ _ELF_DEFINE_DT(DT_MIPS_SYMTABNO, 0x70000011UL, \ "number of entries in the .dynsym section") \ _ELF_DEFINE_DT(DT_MIPS_UNREFEXTNO, 0x70000012UL, \ "index of first external dynamic symbol not ref'ed locally") \ _ELF_DEFINE_DT(DT_MIPS_GOTSYM, 0x70000013UL, \ "index of first dynamic symbol corresponds to a GOT entry") \ _ELF_DEFINE_DT(DT_MIPS_HIPAGENO, 0x70000014UL, \ "number of page table entries in GOT") \ _ELF_DEFINE_DT(DT_MIPS_RLD_MAP, 0x70000016UL, \ "address of runtime linker map") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS, 0x70000017UL, \ "Delta C++ class definition") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASS_NO, 0x70000018UL, \ "number of entries in DT_MIPS_DELTA_CLASS") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE, 0x70000019UL, \ "Delta C++ class instances") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_INSTANCE_NO, 0x7000001AUL, \ "number of entries in DT_MIPS_DELTA_INSTANCE") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC, 0x7000001BUL, \ "Delta relocations") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_RELOC_NO, 0x7000001CUL, \ "number of entries in DT_MIPS_DELTA_RELOC") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_SYM, 0x7000001DUL, \ "Delta symbols referred by Delta relocations") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_SYM_NO, 0x7000001EUL, \ "number of entries in DT_MIPS_DELTA_SYM") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM, 0x70000020UL, \ "Delta symbols for class declarations") \ _ELF_DEFINE_DT(DT_MIPS_DELTA_CLASSSYM_NO, 0x70000021UL, \ "number of entries in DT_MIPS_DELTA_CLASSSYM") \ _ELF_DEFINE_DT(DT_MIPS_CXX_FLAGS, 0x70000022UL, \ "C++ flavor flags") \ _ELF_DEFINE_DT(DT_MIPS_PIXIE_INIT, 0x70000023UL, \ "address of an initialization routine created by pixie") \ _ELF_DEFINE_DT(DT_MIPS_SYMBOL_LIB, 0x70000024UL, \ "address of .MIPS.symlib section") \ _ELF_DEFINE_DT(DT_MIPS_LOCALPAGE_GOTIDX, 0x70000025UL, \ "GOT index of first page table entry for a segment") \ _ELF_DEFINE_DT(DT_MIPS_LOCAL_GOTIDX, 0x70000026UL, \ "GOT index of first page table entry for a local symbol") \ _ELF_DEFINE_DT(DT_MIPS_HIDDEN_GOTIDX, 0x70000027UL, \ "GOT index of first page table entry for a hidden symbol") \ _ELF_DEFINE_DT(DT_MIPS_PROTECTED_GOTIDX, 0x70000028UL, \ "GOT index of first page table entry for a protected symbol") \ _ELF_DEFINE_DT(DT_MIPS_OPTIONS, 0x70000029UL, \ "address of .MIPS.options section") \ _ELF_DEFINE_DT(DT_MIPS_INTERFACE, 0x7000002AUL, \ "address of .MIPS.interface section") \ _ELF_DEFINE_DT(DT_MIPS_DYNSTR_ALIGN, 0x7000002BUL, "???") \ _ELF_DEFINE_DT(DT_MIPS_INTERFACE_SIZE, 0x7000002CUL, \ "size of .MIPS.interface section") \ _ELF_DEFINE_DT(DT_MIPS_RLD_TEXT_RESOLVE_ADDR, 0x7000002DUL, \ "address of _rld_text_resolve in GOT") \ _ELF_DEFINE_DT(DT_MIPS_PERF_SUFFIX, 0x7000002EUL, \ "default suffix of DSO to be appended by dlopen") \ _ELF_DEFINE_DT(DT_MIPS_COMPACT_SIZE, 0x7000002FUL, \ "size of a ucode compact relocation record (o32)") \ _ELF_DEFINE_DT(DT_MIPS_GP_VALUE, 0x70000030UL, \ "GP value of a specified GP relative range") \ _ELF_DEFINE_DT(DT_MIPS_AUX_DYNAMIC, 0x70000031UL, \ "address of an auxiliary dynamic table") \ _ELF_DEFINE_DT(DT_MIPS_PLTGOT, 0x70000032UL, \ "address of the PLTGOT") \ _ELF_DEFINE_DT(DT_MIPS_RLD_OBJ_UPDATE, 0x70000033UL, \ "object list update callback") \ _ELF_DEFINE_DT(DT_MIPS_RWPLT, 0x70000034UL, \ "address of a writable PLT") \ _ELF_DEFINE_DT(DT_PPC_GOT, 0x70000000UL, \ "value of _GLOBAL_OFFSET_TABLE_") \ _ELF_DEFINE_DT(DT_PPC_TLSOPT, 0x70000001UL, \ "TLS descriptor should be optimized") \ _ELF_DEFINE_DT(DT_PPC64_GLINK, 0x70000000UL, \ "address of .glink section") \ _ELF_DEFINE_DT(DT_PPC64_OPD, 0x70000001UL, \ "address of .opd section") \ _ELF_DEFINE_DT(DT_PPC64_OPDSZ, 0x70000002UL, \ "size of .opd section") \ _ELF_DEFINE_DT(DT_PPC64_TLSOPT, 0x70000003UL, \ "TLS descriptor should be optimized") \ _ELF_DEFINE_DT(DT_AUXILIARY, 0x7FFFFFFDUL, \ "offset of string naming auxiliary filtees") \ _ELF_DEFINE_DT(DT_USED, 0x7FFFFFFEUL, "ignored") \ _ELF_DEFINE_DT(DT_FILTER, 0x7FFFFFFFUL, \ "index of string naming filtees") \ _ELF_DEFINE_DT(DT_HIPROC, 0x7FFFFFFFUL, \ "end of processor-specific types") #undef _ELF_DEFINE_DT #define _ELF_DEFINE_DT(N, V, DESCR) N = V , enum { _ELF_DEFINE_DYN_TYPES() DT__LAST__ = DT_HIPROC }; #define DT_DEPRECATED_SPARC_REGISTER DT_SPARC_REGISTER /* * Flags used in the executable header (field: e_flags). */ #define _ELF_DEFINE_EHDR_FLAGS() \ _ELF_DEFINE_EF(EF_ARM_RELEXEC, 0x00000001UL, \ "dynamic segment describes only how to relocate segments") \ _ELF_DEFINE_EF(EF_ARM_HASENTRY, 0x00000002UL, \ "e_entry contains a program entry point") \ _ELF_DEFINE_EF(EF_ARM_SYMSARESORTED, 0x00000004UL, \ "subsection of symbol table is sorted by symbol value") \ _ELF_DEFINE_EF(EF_ARM_DYNSYMSUSESEGIDX, 0x00000008UL, \ "dynamic symbol st_shndx = containing segment index + 1") \ _ELF_DEFINE_EF(EF_ARM_MAPSYMSFIRST, 0x00000010UL, \ "mapping symbols precede other local symbols in symtab") \ _ELF_DEFINE_EF(EF_ARM_BE8, 0x00800000UL, \ "file contains BE-8 code") \ _ELF_DEFINE_EF(EF_ARM_LE8, 0x00400000UL, \ "file contains LE-8 code") \ _ELF_DEFINE_EF(EF_ARM_EABIMASK, 0xFF000000UL, \ "mask for ARM EABI version number (0 denotes GNU or unknown)") \ _ELF_DEFINE_EF(EF_ARM_EABI_UNKNOWN, 0x00000000UL, \ "Unknown or GNU ARM EABI version number") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER1, 0x01000000UL, \ "ARM EABI version 1") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER2, 0x02000000UL, \ "ARM EABI version 2") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER3, 0x03000000UL, \ "ARM EABI version 3") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER4, 0x04000000UL, \ "ARM EABI version 4") \ _ELF_DEFINE_EF(EF_ARM_EABI_VER5, 0x05000000UL, \ "ARM EABI version 5") \ _ELF_DEFINE_EF(EF_ARM_INTERWORK, 0x00000004UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_APCS_26, 0x00000008UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_APCS_FLOAT, 0x00000010UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_PIC, 0x00000020UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_ALIGN8, 0x00000040UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_NEW_ABI, 0x00000080UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_OLD_ABI, 0x00000100UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_SOFT_FLOAT, 0x00000200UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_VFP_FLOAT, 0x00000400UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_ARM_MAVERICK_FLOAT, 0x00000800UL, \ "GNU EABI extension") \ _ELF_DEFINE_EF(EF_MIPS_NOREORDER, 0x00000001UL, \ "at least one .noreorder directive appeared in the source") \ _ELF_DEFINE_EF(EF_MIPS_PIC, 0x00000002UL, \ "file contains position independent code") \ _ELF_DEFINE_EF(EF_MIPS_CPIC, 0x00000004UL, \ "file's code uses standard conventions for calling PIC") \ _ELF_DEFINE_EF(EF_MIPS_UCODE, 0x00000010UL, \ "file contains UCODE (obsolete)") \ _ELF_DEFINE_EF(EF_MIPS_ABI2, 0x00000020UL, \ "file follows MIPS III 32-bit ABI") \ _ELF_DEFINE_EF(EF_MIPS_OPTIONS_FIRST, 0x00000080UL, \ "ld(1) should process .MIPS.options section first") \ _ELF_DEFINE_EF(EF_MIPS_ARCH_ASE, 0x0F000000UL, \ "file uses application-specific architectural extensions") \ _ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_MDMX, 0x08000000UL, \ "file uses MDMX multimedia extensions") \ _ELF_DEFINE_EF(EF_MIPS_ARCH_ASE_M16, 0x04000000UL, \ "file uses MIPS-16 ISA extensions") \ _ELF_DEFINE_EF(EF_MIPS_ARCH, 0xF0000000UL, \ "4-bit MIPS architecture field") \ _ELF_DEFINE_EF(EF_PPC_EMB, 0x80000000UL, \ "Embedded PowerPC flag") \ _ELF_DEFINE_EF(EF_PPC_RELOCATABLE, 0x00010000UL, \ "-mrelocatable flag") \ _ELF_DEFINE_EF(EF_PPC_RELOCATABLE_LIB, 0x00008000UL, \ "-mrelocatable-lib flag") \ _ELF_DEFINE_EF(EF_SPARC_EXT_MASK, 0x00ffff00UL, \ "Vendor Extension mask") \ _ELF_DEFINE_EF(EF_SPARC_32PLUS, 0x00000100UL, \ "Generic V8+ features") \ _ELF_DEFINE_EF(EF_SPARC_SUN_US1, 0x00000200UL, \ "Sun UltraSPARCTM 1 Extensions") \ _ELF_DEFINE_EF(EF_SPARC_HAL_R1, 0x00000400UL, "HAL R1 Extensions") \ _ELF_DEFINE_EF(EF_SPARC_SUN_US3, 0x00000800UL, \ "Sun UltraSPARC 3 Extensions") \ _ELF_DEFINE_EF(EF_SPARCV9_MM, 0x00000003UL, \ "Mask for Memory Model") \ _ELF_DEFINE_EF(EF_SPARCV9_TSO, 0x00000000UL, \ "Total Store Ordering") \ _ELF_DEFINE_EF(EF_SPARCV9_PSO, 0x00000001UL, \ "Partial Store Ordering") \ _ELF_DEFINE_EF(EF_SPARCV9_RMO, 0x00000002UL, \ "Relaxed Memory Ordering") #undef _ELF_DEFINE_EF #define _ELF_DEFINE_EF(N, V, DESCR) N = V , enum { _ELF_DEFINE_EHDR_FLAGS() EF__LAST__ }; /* * Offsets in the `ei_ident[]` field of an ELF executable header. */ #define _ELF_DEFINE_EI_OFFSETS() \ _ELF_DEFINE_EI(EI_MAG0, 0, "magic number") \ _ELF_DEFINE_EI(EI_MAG1, 1, "magic number") \ _ELF_DEFINE_EI(EI_MAG2, 2, "magic number") \ _ELF_DEFINE_EI(EI_MAG3, 3, "magic number") \ _ELF_DEFINE_EI(EI_CLASS, 4, "file class") \ _ELF_DEFINE_EI(EI_DATA, 5, "data encoding") \ _ELF_DEFINE_EI(EI_VERSION, 6, "file version") \ _ELF_DEFINE_EI(EI_OSABI, 7, "OS ABI kind") \ _ELF_DEFINE_EI(EI_ABIVERSION, 8, "OS ABI version") \ _ELF_DEFINE_EI(EI_PAD, 9, "padding start") \ _ELF_DEFINE_EI(EI_NIDENT, 16, "total size") #undef _ELF_DEFINE_EI #define _ELF_DEFINE_EI(N, V, DESCR) N = V , enum { _ELF_DEFINE_EI_OFFSETS() EI__LAST__ }; /* * The ELF class of an object. */ #define _ELF_DEFINE_ELFCLASS() \ _ELF_DEFINE_EC(ELFCLASSNONE, 0, "Unknown ELF class") \ _ELF_DEFINE_EC(ELFCLASS32, 1, "32 bit objects") \ _ELF_DEFINE_EC(ELFCLASS64, 2, "64 bit objects") #undef _ELF_DEFINE_EC #define _ELF_DEFINE_EC(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELFCLASS() EC__LAST__ }; /* * Endianness of data in an ELF object. */ #define _ELF_DEFINE_ELF_DATA_ENDIANNESS() \ _ELF_DEFINE_ED(ELFDATANONE, 0, "Unknown data endianness") \ _ELF_DEFINE_ED(ELFDATA2LSB, 1, "little endian") \ _ELF_DEFINE_ED(ELFDATA2MSB, 2, "big endian") #undef _ELF_DEFINE_ED #define _ELF_DEFINE_ED(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_DATA_ENDIANNESS() ED__LAST__ }; /* * Values of the magic numbers used in identification array. */ #define _ELF_DEFINE_ELF_MAGIC() \ _ELF_DEFINE_EMAG(ELFMAG0, 0x7FU) \ _ELF_DEFINE_EMAG(ELFMAG1, 'E') \ _ELF_DEFINE_EMAG(ELFMAG2, 'L') \ _ELF_DEFINE_EMAG(ELFMAG3, 'F') #undef _ELF_DEFINE_EMAG #define _ELF_DEFINE_EMAG(N, V) N = V , enum { _ELF_DEFINE_ELF_MAGIC() ELFMAG__LAST__ }; /* * ELF OS ABI field. */ #define _ELF_DEFINE_ELF_OSABI() \ _ELF_DEFINE_EABI(ELFOSABI_NONE, 0, \ "No extensions or unspecified") \ _ELF_DEFINE_EABI(ELFOSABI_SYSV, 0, "SYSV") \ _ELF_DEFINE_EABI(ELFOSABI_HPUX, 1, "Hewlett-Packard HP-UX") \ _ELF_DEFINE_EABI(ELFOSABI_NETBSD, 2, "NetBSD") \ _ELF_DEFINE_EABI(ELFOSABI_GNU, 3, "GNU") \ _ELF_DEFINE_EABI(ELFOSABI_HURD, 4, "GNU/HURD") \ _ELF_DEFINE_EABI(ELFOSABI_86OPEN, 5, "86Open Common ABI") \ _ELF_DEFINE_EABI(ELFOSABI_SOLARIS, 6, "Sun Solaris") \ _ELF_DEFINE_EABI(ELFOSABI_AIX, 7, "AIX") \ _ELF_DEFINE_EABI(ELFOSABI_IRIX, 8, "IRIX") \ _ELF_DEFINE_EABI(ELFOSABI_FREEBSD, 9, "FreeBSD") \ _ELF_DEFINE_EABI(ELFOSABI_TRU64, 10, "Compaq TRU64 UNIX") \ _ELF_DEFINE_EABI(ELFOSABI_MODESTO, 11, "Novell Modesto") \ _ELF_DEFINE_EABI(ELFOSABI_OPENBSD, 12, "Open BSD") \ _ELF_DEFINE_EABI(ELFOSABI_OPENVMS, 13, "Open VMS") \ _ELF_DEFINE_EABI(ELFOSABI_NSK, 14, \ "Hewlett-Packard Non-Stop Kernel") \ _ELF_DEFINE_EABI(ELFOSABI_AROS, 15, "Amiga Research OS") \ _ELF_DEFINE_EABI(ELFOSABI_FENIXOS, 16, \ "The FenixOS highly scalable multi-core OS") \ _ELF_DEFINE_EABI(ELFOSABI_CLOUDABI, 17, "Nuxi CloudABI") \ _ELF_DEFINE_EABI(ELFOSABI_ARM_AEABI, 64, \ "ARM specific symbol versioning extensions") \ _ELF_DEFINE_EABI(ELFOSABI_ARM, 97, "ARM ABI") \ _ELF_DEFINE_EABI(ELFOSABI_STANDALONE, 255, \ "Standalone (embedded) application") #undef _ELF_DEFINE_EABI #define _ELF_DEFINE_EABI(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_OSABI() ELFOSABI__LAST__ }; #define ELFOSABI_LINUX ELFOSABI_GNU /* * ELF Machine types: (EM_*). */ #define _ELF_DEFINE_ELF_MACHINES() \ _ELF_DEFINE_EM(EM_NONE, 0, "No machine") \ _ELF_DEFINE_EM(EM_M32, 1, "AT&T WE 32100") \ _ELF_DEFINE_EM(EM_SPARC, 2, "SPARC") \ _ELF_DEFINE_EM(EM_386, 3, "Intel 80386") \ _ELF_DEFINE_EM(EM_68K, 4, "Motorola 68000") \ _ELF_DEFINE_EM(EM_88K, 5, "Motorola 88000") \ _ELF_DEFINE_EM(EM_IAMCU, 6, "Intel MCU") \ _ELF_DEFINE_EM(EM_860, 7, "Intel 80860") \ _ELF_DEFINE_EM(EM_MIPS, 8, "MIPS I Architecture") \ _ELF_DEFINE_EM(EM_S370, 9, "IBM System/370 Processor") \ _ELF_DEFINE_EM(EM_MIPS_RS3_LE, 10, "MIPS RS3000 Little-endian") \ _ELF_DEFINE_EM(EM_PARISC, 15, "Hewlett-Packard PA-RISC") \ _ELF_DEFINE_EM(EM_VPP500, 17, "Fujitsu VPP500") \ _ELF_DEFINE_EM(EM_SPARC32PLUS, 18, \ "Enhanced instruction set SPARC") \ _ELF_DEFINE_EM(EM_960, 19, "Intel 80960") \ _ELF_DEFINE_EM(EM_PPC, 20, "PowerPC") \ _ELF_DEFINE_EM(EM_PPC64, 21, "64-bit PowerPC") \ _ELF_DEFINE_EM(EM_S390, 22, "IBM System/390 Processor") \ _ELF_DEFINE_EM(EM_SPU, 23, "IBM SPU/SPC") \ _ELF_DEFINE_EM(EM_V800, 36, "NEC V800") \ _ELF_DEFINE_EM(EM_FR20, 37, "Fujitsu FR20") \ _ELF_DEFINE_EM(EM_RH32, 38, "TRW RH-32") \ _ELF_DEFINE_EM(EM_RCE, 39, "Motorola RCE") \ _ELF_DEFINE_EM(EM_ARM, 40, "Advanced RISC Machines ARM") \ _ELF_DEFINE_EM(EM_ALPHA, 41, "Digital Alpha") \ _ELF_DEFINE_EM(EM_SH, 42, "Hitachi SH") \ _ELF_DEFINE_EM(EM_SPARCV9, 43, "SPARC Version 9") \ _ELF_DEFINE_EM(EM_TRICORE, 44, \ "Siemens TriCore embedded processor") \ _ELF_DEFINE_EM(EM_ARC, 45, \ "Argonaut RISC Core, Argonaut Technologies Inc.") \ _ELF_DEFINE_EM(EM_H8_300, 46, "Hitachi H8/300") \ _ELF_DEFINE_EM(EM_H8_300H, 47, "Hitachi H8/300H") \ _ELF_DEFINE_EM(EM_H8S, 48, "Hitachi H8S") \ _ELF_DEFINE_EM(EM_H8_500, 49, "Hitachi H8/500") \ _ELF_DEFINE_EM(EM_IA_64, 50, \ "Intel IA-64 processor architecture") \ _ELF_DEFINE_EM(EM_MIPS_X, 51, "Stanford MIPS-X") \ _ELF_DEFINE_EM(EM_COLDFIRE, 52, "Motorola ColdFire") \ _ELF_DEFINE_EM(EM_68HC12, 53, "Motorola M68HC12") \ _ELF_DEFINE_EM(EM_MMA, 54, \ "Fujitsu MMA Multimedia Accelerator") \ _ELF_DEFINE_EM(EM_PCP, 55, "Siemens PCP") \ _ELF_DEFINE_EM(EM_NCPU, 56, \ "Sony nCPU embedded RISC processor") \ _ELF_DEFINE_EM(EM_NDR1, 57, "Denso NDR1 microprocessor") \ _ELF_DEFINE_EM(EM_STARCORE, 58, "Motorola Star*Core processor") \ _ELF_DEFINE_EM(EM_ME16, 59, "Toyota ME16 processor") \ _ELF_DEFINE_EM(EM_ST100, 60, \ "STMicroelectronics ST100 processor") \ _ELF_DEFINE_EM(EM_TINYJ, 61, \ "Advanced Logic Corp. TinyJ embedded processor family") \ _ELF_DEFINE_EM(EM_X86_64, 62, "AMD x86-64 architecture") \ _ELF_DEFINE_EM(EM_PDSP, 63, "Sony DSP Processor") \ _ELF_DEFINE_EM(EM_PDP10, 64, \ "Digital Equipment Corp. PDP-10") \ _ELF_DEFINE_EM(EM_PDP11, 65, \ "Digital Equipment Corp. PDP-11") \ _ELF_DEFINE_EM(EM_FX66, 66, "Siemens FX66 microcontroller") \ _ELF_DEFINE_EM(EM_ST9PLUS, 67, \ "STMicroelectronics ST9+ 8/16 bit microcontroller") \ _ELF_DEFINE_EM(EM_ST7, 68, \ "STMicroelectronics ST7 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_68HC16, 69, \ "Motorola MC68HC16 Microcontroller") \ _ELF_DEFINE_EM(EM_68HC11, 70, \ "Motorola MC68HC11 Microcontroller") \ _ELF_DEFINE_EM(EM_68HC08, 71, \ "Motorola MC68HC08 Microcontroller") \ _ELF_DEFINE_EM(EM_68HC05, 72, \ "Motorola MC68HC05 Microcontroller") \ _ELF_DEFINE_EM(EM_SVX, 73, "Silicon Graphics SVx") \ _ELF_DEFINE_EM(EM_ST19, 74, \ "STMicroelectronics ST19 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_VAX, 75, "Digital VAX") \ _ELF_DEFINE_EM(EM_CRIS, 76, \ "Axis Communications 32-bit embedded processor") \ _ELF_DEFINE_EM(EM_JAVELIN, 77, \ "Infineon Technologies 32-bit embedded processor") \ _ELF_DEFINE_EM(EM_FIREPATH, 78, \ "Element 14 64-bit DSP Processor") \ _ELF_DEFINE_EM(EM_ZSP, 79, \ "LSI Logic 16-bit DSP Processor") \ _ELF_DEFINE_EM(EM_MMIX, 80, \ "Donald Knuth's educational 64-bit processor") \ _ELF_DEFINE_EM(EM_HUANY, 81, \ "Harvard University machine-independent object files") \ _ELF_DEFINE_EM(EM_PRISM, 82, "SiTera Prism") \ _ELF_DEFINE_EM(EM_AVR, 83, \ "Atmel AVR 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_FR30, 84, "Fujitsu FR30") \ _ELF_DEFINE_EM(EM_D10V, 85, "Mitsubishi D10V") \ _ELF_DEFINE_EM(EM_D30V, 86, "Mitsubishi D30V") \ _ELF_DEFINE_EM(EM_V850, 87, "NEC v850") \ _ELF_DEFINE_EM(EM_M32R, 88, "Mitsubishi M32R") \ _ELF_DEFINE_EM(EM_MN10300, 89, "Matsushita MN10300") \ _ELF_DEFINE_EM(EM_MN10200, 90, "Matsushita MN10200") \ _ELF_DEFINE_EM(EM_PJ, 91, "picoJava") \ _ELF_DEFINE_EM(EM_OPENRISC, 92, \ "OpenRISC 32-bit embedded processor") \ _ELF_DEFINE_EM(EM_ARC_COMPACT, 93, \ "ARC International ARCompact processor") \ _ELF_DEFINE_EM(EM_XTENSA, 94, \ "Tensilica Xtensa Architecture") \ _ELF_DEFINE_EM(EM_VIDEOCORE, 95, \ "Alphamosaic VideoCore processor") \ _ELF_DEFINE_EM(EM_TMM_GPP, 96, \ "Thompson Multimedia General Purpose Processor") \ _ELF_DEFINE_EM(EM_NS32K, 97, \ "National Semiconductor 32000 series") \ _ELF_DEFINE_EM(EM_TPC, 98, "Tenor Network TPC processor") \ _ELF_DEFINE_EM(EM_SNP1K, 99, "Trebia SNP 1000 processor") \ _ELF_DEFINE_EM(EM_ST200, 100, \ "STMicroelectronics (www.st.com) ST200 microcontroller") \ _ELF_DEFINE_EM(EM_IP2K, 101, \ "Ubicom IP2xxx microcontroller family") \ _ELF_DEFINE_EM(EM_MAX, 102, "MAX Processor") \ _ELF_DEFINE_EM(EM_CR, 103, \ "National Semiconductor CompactRISC microprocessor") \ _ELF_DEFINE_EM(EM_F2MC16, 104, "Fujitsu F2MC16") \ _ELF_DEFINE_EM(EM_MSP430, 105, \ "Texas Instruments embedded microcontroller msp430") \ _ELF_DEFINE_EM(EM_BLACKFIN, 106, \ "Analog Devices Blackfin (DSP) processor") \ _ELF_DEFINE_EM(EM_SE_C33, 107, \ "S1C33 Family of Seiko Epson processors") \ _ELF_DEFINE_EM(EM_SEP, 108, \ "Sharp embedded microprocessor") \ _ELF_DEFINE_EM(EM_ARCA, 109, "Arca RISC Microprocessor") \ _ELF_DEFINE_EM(EM_UNICORE, 110, \ "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University") \ _ELF_DEFINE_EM(EM_EXCESS, 111, \ "eXcess: 16/32/64-bit configurable embedded CPU") \ _ELF_DEFINE_EM(EM_DXP, 112, \ "Icera Semiconductor Inc. Deep Execution Processor") \ _ELF_DEFINE_EM(EM_ALTERA_NIOS2, 113, \ "Altera Nios II soft-core processor") \ _ELF_DEFINE_EM(EM_CRX, 114, \ "National Semiconductor CompactRISC CRX microprocessor") \ _ELF_DEFINE_EM(EM_XGATE, 115, \ "Motorola XGATE embedded processor") \ _ELF_DEFINE_EM(EM_C166, 116, \ "Infineon C16x/XC16x processor") \ _ELF_DEFINE_EM(EM_M16C, 117, \ "Renesas M16C series microprocessors") \ _ELF_DEFINE_EM(EM_DSPIC30F, 118, \ "Microchip Technology dsPIC30F Digital Signal Controller") \ _ELF_DEFINE_EM(EM_CE, 119, \ "Freescale Communication Engine RISC core") \ _ELF_DEFINE_EM(EM_M32C, 120, \ "Renesas M32C series microprocessors") \ _ELF_DEFINE_EM(EM_TSK3000, 131, "Altium TSK3000 core") \ _ELF_DEFINE_EM(EM_RS08, 132, \ "Freescale RS08 embedded processor") \ _ELF_DEFINE_EM(EM_SHARC, 133, \ "Analog Devices SHARC family of 32-bit DSP processors") \ _ELF_DEFINE_EM(EM_ECOG2, 134, \ "Cyan Technology eCOG2 microprocessor") \ _ELF_DEFINE_EM(EM_SCORE7, 135, \ "Sunplus S+core7 RISC processor") \ _ELF_DEFINE_EM(EM_DSP24, 136, \ "New Japan Radio (NJR) 24-bit DSP Processor") \ _ELF_DEFINE_EM(EM_VIDEOCORE3, 137, \ "Broadcom VideoCore III processor") \ _ELF_DEFINE_EM(EM_LATTICEMICO32, 138, \ "RISC processor for Lattice FPGA architecture") \ _ELF_DEFINE_EM(EM_SE_C17, 139, "Seiko Epson C17 family") \ _ELF_DEFINE_EM(EM_TI_C6000, 140, \ "The Texas Instruments TMS320C6000 DSP family") \ _ELF_DEFINE_EM(EM_TI_C2000, 141, \ "The Texas Instruments TMS320C2000 DSP family") \ _ELF_DEFINE_EM(EM_TI_C5500, 142, \ "The Texas Instruments TMS320C55x DSP family") \ _ELF_DEFINE_EM(EM_MMDSP_PLUS, 160, \ "STMicroelectronics 64bit VLIW Data Signal Processor") \ _ELF_DEFINE_EM(EM_CYPRESS_M8C, 161, "Cypress M8C microprocessor") \ _ELF_DEFINE_EM(EM_R32C, 162, \ "Renesas R32C series microprocessors") \ _ELF_DEFINE_EM(EM_TRIMEDIA, 163, \ "NXP Semiconductors TriMedia architecture family") \ _ELF_DEFINE_EM(EM_QDSP6, 164, "QUALCOMM DSP6 Processor") \ _ELF_DEFINE_EM(EM_8051, 165, "Intel 8051 and variants") \ _ELF_DEFINE_EM(EM_STXP7X, 166, \ "STMicroelectronics STxP7x family of configurable and extensible RISC processors") \ _ELF_DEFINE_EM(EM_NDS32, 167, \ "Andes Technology compact code size embedded RISC processor family") \ _ELF_DEFINE_EM(EM_ECOG1, 168, \ "Cyan Technology eCOG1X family") \ _ELF_DEFINE_EM(EM_ECOG1X, 168, \ "Cyan Technology eCOG1X family") \ _ELF_DEFINE_EM(EM_MAXQ30, 169, \ "Dallas Semiconductor MAXQ30 Core Micro-controllers") \ _ELF_DEFINE_EM(EM_XIMO16, 170, \ "New Japan Radio (NJR) 16-bit DSP Processor") \ _ELF_DEFINE_EM(EM_MANIK, 171, \ "M2000 Reconfigurable RISC Microprocessor") \ _ELF_DEFINE_EM(EM_CRAYNV2, 172, \ "Cray Inc. NV2 vector architecture") \ _ELF_DEFINE_EM(EM_RX, 173, "Renesas RX family") \ _ELF_DEFINE_EM(EM_METAG, 174, \ "Imagination Technologies META processor architecture") \ _ELF_DEFINE_EM(EM_MCST_ELBRUS, 175, \ "MCST Elbrus general purpose hardware architecture") \ _ELF_DEFINE_EM(EM_ECOG16, 176, \ "Cyan Technology eCOG16 family") \ _ELF_DEFINE_EM(EM_CR16, 177, \ "National Semiconductor CompactRISC CR16 16-bit microprocessor") \ _ELF_DEFINE_EM(EM_ETPU, 178, \ "Freescale Extended Time Processing Unit") \ _ELF_DEFINE_EM(EM_SLE9X, 179, \ "Infineon Technologies SLE9X core") \ _ELF_DEFINE_EM(EM_AARCH64, 183, \ "AArch64 (64-bit ARM)") \ _ELF_DEFINE_EM(EM_AVR32, 185, \ "Atmel Corporation 32-bit microprocessor family") \ _ELF_DEFINE_EM(EM_STM8, 186, \ "STMicroeletronics STM8 8-bit microcontroller") \ _ELF_DEFINE_EM(EM_TILE64, 187, \ "Tilera TILE64 multicore architecture family") \ _ELF_DEFINE_EM(EM_TILEPRO, 188, \ "Tilera TILEPro multicore architecture family") \ _ELF_DEFINE_EM(EM_MICROBLAZE, 189, \ "Xilinx MicroBlaze 32-bit RISC soft processor core") \ _ELF_DEFINE_EM(EM_CUDA, 190, "NVIDIA CUDA architecture") \ _ELF_DEFINE_EM(EM_TILEGX, 191, \ "Tilera TILE-Gx multicore architecture family") \ _ELF_DEFINE_EM(EM_CLOUDSHIELD, 192, \ "CloudShield architecture family") \ _ELF_DEFINE_EM(EM_COREA_1ST, 193, \ "KIPO-KAIST Core-A 1st generation processor family") \ _ELF_DEFINE_EM(EM_COREA_2ND, 194, \ "KIPO-KAIST Core-A 2nd generation processor family") \ _ELF_DEFINE_EM(EM_ARC_COMPACT2, 195, "Synopsys ARCompact V2") \ _ELF_DEFINE_EM(EM_OPEN8, 196, \ "Open8 8-bit RISC soft processor core") \ _ELF_DEFINE_EM(EM_RL78, 197, "Renesas RL78 family") \ _ELF_DEFINE_EM(EM_VIDEOCORE5, 198, "Broadcom VideoCore V processor") \ _ELF_DEFINE_EM(EM_78KOR, 199, "Renesas 78KOR family") \ _ELF_DEFINE_EM(EM_56800EX, 200, \ "Freescale 56800EX Digital Signal Controller") \ _ELF_DEFINE_EM(EM_BA1, 201, "Beyond BA1 CPU architecture") \ _ELF_DEFINE_EM(EM_BA2, 202, "Beyond BA2 CPU architecture") \ _ELF_DEFINE_EM(EM_XCORE, 203, "XMOS xCORE processor family") \ _ELF_DEFINE_EM(EM_MCHP_PIC, 204, "Microchip 8-bit PIC(r) family") \ _ELF_DEFINE_EM(EM_INTEL205, 205, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL206, 206, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL207, 207, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL208, 208, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_INTEL209, 209, "Reserved by Intel") \ _ELF_DEFINE_EM(EM_KM32, 210, "KM211 KM32 32-bit processor") \ _ELF_DEFINE_EM(EM_KMX32, 211, "KM211 KMX32 32-bit processor") \ _ELF_DEFINE_EM(EM_KMX16, 212, "KM211 KMX16 16-bit processor") \ _ELF_DEFINE_EM(EM_KMX8, 213, "KM211 KMX8 8-bit processor") \ _ELF_DEFINE_EM(EM_KVARC, 214, "KM211 KMX32 KVARC processor") \ _ELF_DEFINE_EM(EM_RISCV, 243, "RISC-V") #undef _ELF_DEFINE_EM #define _ELF_DEFINE_EM(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_MACHINES() EM__LAST__ }; /* Other synonyms. */ #define EM_AMD64 EM_X86_64 #define EM_ARC_A5 EM_ARC_COMPACT /* * ELF file types: (ET_*). */ #define _ELF_DEFINE_ELF_TYPES() \ _ELF_DEFINE_ET(ET_NONE, 0, "No file type") \ _ELF_DEFINE_ET(ET_REL, 1, "Relocatable object") \ _ELF_DEFINE_ET(ET_EXEC, 2, "Executable") \ _ELF_DEFINE_ET(ET_DYN, 3, "Shared object") \ _ELF_DEFINE_ET(ET_CORE, 4, "Core file") \ _ELF_DEFINE_ET(ET_LOOS, 0xFE00U, "Begin OS-specific range") \ _ELF_DEFINE_ET(ET_HIOS, 0xFEFFU, "End OS-specific range") \ _ELF_DEFINE_ET(ET_LOPROC, 0xFF00U, "Begin processor-specific range") \ _ELF_DEFINE_ET(ET_HIPROC, 0xFFFFU, "End processor-specific range") #undef _ELF_DEFINE_ET #define _ELF_DEFINE_ET(N, V, DESCR) N = V , enum { _ELF_DEFINE_ELF_TYPES() ET__LAST__ }; /* ELF file format version numbers. */ #define EV_NONE 0 #define EV_CURRENT 1 /* * Flags for section groups. */ #define GRP_COMDAT 0x1 /* COMDAT semantics */ #define GRP_MASKOS 0x0ff00000 /* OS-specific flags */ #define GRP_MASKPROC 0xf0000000 /* processor-specific flags */ /* * Flags / mask for .gnu.versym sections. */ #define VERSYM_VERSION 0x7fff #define VERSYM_HIDDEN 0x8000 /* * Flags used by program header table entries. */ #define _ELF_DEFINE_PHDR_FLAGS() \ _ELF_DEFINE_PF(PF_X, 0x1, "Execute") \ _ELF_DEFINE_PF(PF_W, 0x2, "Write") \ _ELF_DEFINE_PF(PF_R, 0x4, "Read") \ _ELF_DEFINE_PF(PF_MASKOS, 0x0ff00000, "OS-specific flags") \ _ELF_DEFINE_PF(PF_MASKPROC, 0xf0000000, "Processor-specific flags") \ _ELF_DEFINE_PF(PF_ARM_SB, 0x10000000, \ "segment contains the location addressed by the static base") \ _ELF_DEFINE_PF(PF_ARM_PI, 0x20000000, \ "segment is position-independent") \ _ELF_DEFINE_PF(PF_ARM_ABS, 0x40000000, \ "segment must be loaded at its base address") #undef _ELF_DEFINE_PF #define _ELF_DEFINE_PF(N, V, DESCR) N = V , enum { _ELF_DEFINE_PHDR_FLAGS() PF__LAST__ }; /* * Types of program header table entries. */ #define _ELF_DEFINE_PHDR_TYPES() \ _ELF_DEFINE_PT(PT_NULL, 0, "ignored entry") \ _ELF_DEFINE_PT(PT_LOAD, 1, "loadable segment") \ _ELF_DEFINE_PT(PT_DYNAMIC, 2, \ "contains dynamic linking information") \ _ELF_DEFINE_PT(PT_INTERP, 3, "names an interpreter") \ _ELF_DEFINE_PT(PT_NOTE, 4, "auxiliary information") \ _ELF_DEFINE_PT(PT_SHLIB, 5, "reserved") \ _ELF_DEFINE_PT(PT_PHDR, 6, \ "describes the program header itself") \ _ELF_DEFINE_PT(PT_TLS, 7, "thread local storage") \ _ELF_DEFINE_PT(PT_LOOS, 0x60000000UL, \ "start of OS-specific range") \ _ELF_DEFINE_PT(PT_SUNW_UNWIND, 0x6464E550UL, \ "Solaris/amd64 stack unwind tables") \ _ELF_DEFINE_PT(PT_GNU_EH_FRAME, 0x6474E550UL, \ "GCC generated .eh_frame_hdr segment") \ _ELF_DEFINE_PT(PT_GNU_STACK, 0x6474E551UL, \ "Stack flags") \ _ELF_DEFINE_PT(PT_GNU_RELRO, 0x6474E552UL, \ "Segment becomes read-only after relocation") \ +_ELF_DEFINE_PT(PT_OPENBSD_RANDOMIZE,0x65A3DBE6UL, \ + "Segment filled with random data") \ +_ELF_DEFINE_PT(PT_OPENBSD_WXNEEDED, 0x65A3DBE7UL, \ + "Program violates W^X") \ +_ELF_DEFINE_PT(PT_OPENBSD_BOOTDATA, 0x65A41BE6UL, \ + "Boot data") \ _ELF_DEFINE_PT(PT_SUNWBSS, 0x6FFFFFFAUL, \ "A Solaris .SUNW_bss section") \ _ELF_DEFINE_PT(PT_SUNWSTACK, 0x6FFFFFFBUL, \ "A Solaris process stack") \ _ELF_DEFINE_PT(PT_SUNWDTRACE, 0x6FFFFFFCUL, \ "Used by dtrace(1)") \ _ELF_DEFINE_PT(PT_SUNWCAP, 0x6FFFFFFDUL, \ "Special hardware capability requirements") \ _ELF_DEFINE_PT(PT_HIOS, 0x6FFFFFFFUL, \ "end of OS-specific range") \ _ELF_DEFINE_PT(PT_LOPROC, 0x70000000UL, \ "start of processor-specific range") \ _ELF_DEFINE_PT(PT_ARM_ARCHEXT, 0x70000000UL, \ "platform architecture compatibility information") \ _ELF_DEFINE_PT(PT_ARM_EXIDX, 0x70000001UL, \ "exception unwind tables") \ _ELF_DEFINE_PT(PT_MIPS_REGINFO, 0x70000000UL, \ "register usage information") \ _ELF_DEFINE_PT(PT_MIPS_RTPROC, 0x70000001UL, \ "runtime procedure table") \ _ELF_DEFINE_PT(PT_MIPS_OPTIONS, 0x70000002UL, \ "options segment") \ _ELF_DEFINE_PT(PT_HIPROC, 0x7FFFFFFFUL, \ "end of processor-specific range") #undef _ELF_DEFINE_PT #define _ELF_DEFINE_PT(N, V, DESCR) N = V , enum { _ELF_DEFINE_PHDR_TYPES() PT__LAST__ = PT_HIPROC }; /* synonyms. */ #define PT_ARM_UNWIND PT_ARM_EXIDX #define PT_HISUNW PT_HIOS #define PT_LOSUNW PT_SUNWBSS /* * Section flags. */ #define _ELF_DEFINE_SECTION_FLAGS() \ _ELF_DEFINE_SHF(SHF_WRITE, 0x1, \ "writable during program execution") \ _ELF_DEFINE_SHF(SHF_ALLOC, 0x2, \ "occupies memory during program execution") \ _ELF_DEFINE_SHF(SHF_EXECINSTR, 0x4, "executable instructions") \ _ELF_DEFINE_SHF(SHF_MERGE, 0x10, \ "may be merged to prevent duplication") \ _ELF_DEFINE_SHF(SHF_STRINGS, 0x20, \ "NUL-terminated character strings") \ _ELF_DEFINE_SHF(SHF_INFO_LINK, 0x40, \ "the sh_info field holds a link") \ _ELF_DEFINE_SHF(SHF_LINK_ORDER, 0x80, \ "special ordering requirements during linking") \ _ELF_DEFINE_SHF(SHF_OS_NONCONFORMING, 0x100, \ "requires OS-specific processing during linking") \ _ELF_DEFINE_SHF(SHF_GROUP, 0x200, \ "member of a section group") \ _ELF_DEFINE_SHF(SHF_TLS, 0x400, \ "holds thread-local storage") \ _ELF_DEFINE_SHF(SHF_COMPRESSED, 0x800, \ "holds compressed data") \ _ELF_DEFINE_SHF(SHF_MASKOS, 0x0FF00000UL, \ "bits reserved for OS-specific semantics") \ _ELF_DEFINE_SHF(SHF_AMD64_LARGE, 0x10000000UL, \ "section uses large code model") \ _ELF_DEFINE_SHF(SHF_ENTRYSECT, 0x10000000UL, \ "section contains an entry point (ARM)") \ _ELF_DEFINE_SHF(SHF_COMDEF, 0x80000000UL, \ "section may be multiply defined in input to link step (ARM)") \ _ELF_DEFINE_SHF(SHF_MIPS_GPREL, 0x10000000UL, \ "section must be part of global data area") \ _ELF_DEFINE_SHF(SHF_MIPS_MERGE, 0x20000000UL, \ "section data should be merged to eliminate duplication") \ _ELF_DEFINE_SHF(SHF_MIPS_ADDR, 0x40000000UL, \ "section data is addressed by default") \ _ELF_DEFINE_SHF(SHF_MIPS_STRING, 0x80000000UL, \ "section data is string data by default") \ _ELF_DEFINE_SHF(SHF_MIPS_NOSTRIP, 0x08000000UL, \ "section data may not be stripped") \ _ELF_DEFINE_SHF(SHF_MIPS_LOCAL, 0x04000000UL, \ "section data local to process") \ _ELF_DEFINE_SHF(SHF_MIPS_NAMES, 0x02000000UL, \ "linker must generate implicit hidden weak names") \ _ELF_DEFINE_SHF(SHF_MIPS_NODUPE, 0x01000000UL, \ "linker must retain only one copy") \ _ELF_DEFINE_SHF(SHF_ORDERED, 0x40000000UL, \ "section is ordered with respect to other sections") \ _ELF_DEFINE_SHF(SHF_EXCLUDE, 0x80000000UL, \ "section is excluded from executables and shared objects") \ _ELF_DEFINE_SHF(SHF_MASKPROC, 0xF0000000UL, \ "bits reserved for processor-specific semantics") #undef _ELF_DEFINE_SHF #define _ELF_DEFINE_SHF(N, V, DESCR) N = V , enum { _ELF_DEFINE_SECTION_FLAGS() SHF__LAST__ }; /* * Special section indices. */ #define _ELF_DEFINE_SECTION_INDICES() \ _ELF_DEFINE_SHN(SHN_UNDEF, 0, "undefined section") \ _ELF_DEFINE_SHN(SHN_LORESERVE, 0xFF00U, "start of reserved area") \ _ELF_DEFINE_SHN(SHN_LOPROC, 0xFF00U, \ "start of processor-specific range") \ _ELF_DEFINE_SHN(SHN_BEFORE, 0xFF00U, "used for section ordering") \ _ELF_DEFINE_SHN(SHN_AFTER, 0xFF01U, "used for section ordering") \ _ELF_DEFINE_SHN(SHN_AMD64_LCOMMON, 0xFF02U, "large common block label") \ _ELF_DEFINE_SHN(SHN_MIPS_ACOMMON, 0xFF00U, \ "allocated common symbols in a DSO") \ _ELF_DEFINE_SHN(SHN_MIPS_TEXT, 0xFF01U, "Reserved (obsolete)") \ _ELF_DEFINE_SHN(SHN_MIPS_DATA, 0xFF02U, "Reserved (obsolete)") \ _ELF_DEFINE_SHN(SHN_MIPS_SCOMMON, 0xFF03U, \ "gp-addressable common symbols") \ _ELF_DEFINE_SHN(SHN_MIPS_SUNDEFINED, 0xFF04U, \ "gp-addressable undefined symbols") \ _ELF_DEFINE_SHN(SHN_MIPS_LCOMMON, 0xFF05U, "local common symbols") \ _ELF_DEFINE_SHN(SHN_MIPS_LUNDEFINED, 0xFF06U, \ "local undefined symbols") \ _ELF_DEFINE_SHN(SHN_HIPROC, 0xFF1FU, \ "end of processor-specific range") \ _ELF_DEFINE_SHN(SHN_LOOS, 0xFF20U, \ "start of OS-specific range") \ _ELF_DEFINE_SHN(SHN_SUNW_IGNORE, 0xFF3FU, "used by dtrace") \ _ELF_DEFINE_SHN(SHN_HIOS, 0xFF3FU, \ "end of OS-specific range") \ _ELF_DEFINE_SHN(SHN_ABS, 0xFFF1U, "absolute references") \ _ELF_DEFINE_SHN(SHN_COMMON, 0xFFF2U, "references to COMMON areas") \ _ELF_DEFINE_SHN(SHN_XINDEX, 0xFFFFU, "extended index") \ _ELF_DEFINE_SHN(SHN_HIRESERVE, 0xFFFFU, "end of reserved area") #undef _ELF_DEFINE_SHN #define _ELF_DEFINE_SHN(N, V, DESCR) N = V , enum { _ELF_DEFINE_SECTION_INDICES() SHN__LAST__ }; /* * Section types. */ #define _ELF_DEFINE_SECTION_TYPES() \ _ELF_DEFINE_SHT(SHT_NULL, 0, "inactive header") \ _ELF_DEFINE_SHT(SHT_PROGBITS, 1, "program defined information") \ _ELF_DEFINE_SHT(SHT_SYMTAB, 2, "symbol table") \ _ELF_DEFINE_SHT(SHT_STRTAB, 3, "string table") \ _ELF_DEFINE_SHT(SHT_RELA, 4, \ "relocation entries with addends") \ _ELF_DEFINE_SHT(SHT_HASH, 5, "symbol hash table") \ _ELF_DEFINE_SHT(SHT_DYNAMIC, 6, \ "information for dynamic linking") \ _ELF_DEFINE_SHT(SHT_NOTE, 7, "additional notes") \ _ELF_DEFINE_SHT(SHT_NOBITS, 8, "section occupying no space") \ _ELF_DEFINE_SHT(SHT_REL, 9, \ "relocation entries without addends") \ _ELF_DEFINE_SHT(SHT_SHLIB, 10, "reserved") \ _ELF_DEFINE_SHT(SHT_DYNSYM, 11, "symbol table") \ _ELF_DEFINE_SHT(SHT_INIT_ARRAY, 14, \ "pointers to initialization functions") \ _ELF_DEFINE_SHT(SHT_FINI_ARRAY, 15, \ "pointers to termination functions") \ _ELF_DEFINE_SHT(SHT_PREINIT_ARRAY, 16, \ "pointers to functions called before initialization") \ _ELF_DEFINE_SHT(SHT_GROUP, 17, "defines a section group") \ _ELF_DEFINE_SHT(SHT_SYMTAB_SHNDX, 18, \ "used for extended section numbering") \ _ELF_DEFINE_SHT(SHT_LOOS, 0x60000000UL, \ "start of OS-specific range") \ _ELF_DEFINE_SHT(SHT_SUNW_dof, 0x6FFFFFF4UL, \ "used by dtrace") \ _ELF_DEFINE_SHT(SHT_SUNW_cap, 0x6FFFFFF5UL, \ "capability requirements") \ _ELF_DEFINE_SHT(SHT_GNU_ATTRIBUTES, 0x6FFFFFF5UL, \ "object attributes") \ _ELF_DEFINE_SHT(SHT_SUNW_SIGNATURE, 0x6FFFFFF6UL, \ "module verification signature") \ _ELF_DEFINE_SHT(SHT_GNU_HASH, 0x6FFFFFF6UL, \ "GNU Hash sections") \ _ELF_DEFINE_SHT(SHT_GNU_LIBLIST, 0x6FFFFFF7UL, \ "List of libraries to be prelinked") \ _ELF_DEFINE_SHT(SHT_SUNW_ANNOTATE, 0x6FFFFFF7UL, \ "special section where unresolved references are allowed") \ _ELF_DEFINE_SHT(SHT_SUNW_DEBUGSTR, 0x6FFFFFF8UL, \ "debugging information") \ _ELF_DEFINE_SHT(SHT_CHECKSUM, 0x6FFFFFF8UL, \ "checksum for dynamic shared objects") \ _ELF_DEFINE_SHT(SHT_SUNW_DEBUG, 0x6FFFFFF9UL, \ "debugging information") \ _ELF_DEFINE_SHT(SHT_SUNW_move, 0x6FFFFFFAUL, \ "information to handle partially initialized symbols") \ _ELF_DEFINE_SHT(SHT_SUNW_COMDAT, 0x6FFFFFFBUL, \ "section supporting merging of multiple copies of data") \ _ELF_DEFINE_SHT(SHT_SUNW_syminfo, 0x6FFFFFFCUL, \ "additional symbol information") \ _ELF_DEFINE_SHT(SHT_SUNW_verdef, 0x6FFFFFFDUL, \ "symbol versioning information") \ _ELF_DEFINE_SHT(SHT_SUNW_verneed, 0x6FFFFFFEUL, \ "symbol versioning requirements") \ _ELF_DEFINE_SHT(SHT_SUNW_versym, 0x6FFFFFFFUL, \ "symbol versioning table") \ _ELF_DEFINE_SHT(SHT_HIOS, 0x6FFFFFFFUL, \ "end of OS-specific range") \ _ELF_DEFINE_SHT(SHT_LOPROC, 0x70000000UL, \ "start of processor-specific range") \ _ELF_DEFINE_SHT(SHT_ARM_EXIDX, 0x70000001UL, \ "exception index table") \ _ELF_DEFINE_SHT(SHT_ARM_PREEMPTMAP, 0x70000002UL, \ "BPABI DLL dynamic linking preemption map") \ _ELF_DEFINE_SHT(SHT_ARM_ATTRIBUTES, 0x70000003UL, \ "object file compatibility attributes") \ _ELF_DEFINE_SHT(SHT_ARM_DEBUGOVERLAY, 0x70000004UL, \ "overlay debug information") \ _ELF_DEFINE_SHT(SHT_ARM_OVERLAYSECTION, 0x70000005UL, \ "overlay debug information") \ _ELF_DEFINE_SHT(SHT_MIPS_LIBLIST, 0x70000000UL, \ "DSO library information used in link") \ _ELF_DEFINE_SHT(SHT_MIPS_MSYM, 0x70000001UL, \ "MIPS symbol table extension") \ _ELF_DEFINE_SHT(SHT_MIPS_CONFLICT, 0x70000002UL, \ "symbol conflicting with DSO-defined symbols ") \ _ELF_DEFINE_SHT(SHT_MIPS_GPTAB, 0x70000003UL, \ "global pointer table") \ _ELF_DEFINE_SHT(SHT_MIPS_UCODE, 0x70000004UL, \ "reserved") \ _ELF_DEFINE_SHT(SHT_MIPS_DEBUG, 0x70000005UL, \ "reserved (obsolete debug information)") \ _ELF_DEFINE_SHT(SHT_MIPS_REGINFO, 0x70000006UL, \ "register usage information") \ _ELF_DEFINE_SHT(SHT_MIPS_PACKAGE, 0x70000007UL, \ "OSF reserved") \ _ELF_DEFINE_SHT(SHT_MIPS_PACKSYM, 0x70000008UL, \ "OSF reserved") \ _ELF_DEFINE_SHT(SHT_MIPS_RELD, 0x70000009UL, \ "dynamic relocation") \ _ELF_DEFINE_SHT(SHT_MIPS_IFACE, 0x7000000BUL, \ "subprogram interface information") \ _ELF_DEFINE_SHT(SHT_MIPS_CONTENT, 0x7000000CUL, \ "section content classification") \ _ELF_DEFINE_SHT(SHT_MIPS_OPTIONS, 0x7000000DUL, \ "general options") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTASYM, 0x7000001BUL, \ "Delta C++: symbol table") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTAINST, 0x7000001CUL, \ "Delta C++: instance table") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTACLASS, 0x7000001DUL, \ "Delta C++: class table") \ _ELF_DEFINE_SHT(SHT_MIPS_DWARF, 0x7000001EUL, \ "DWARF debug information") \ _ELF_DEFINE_SHT(SHT_MIPS_DELTADECL, 0x7000001FUL, \ "Delta C++: declarations") \ _ELF_DEFINE_SHT(SHT_MIPS_SYMBOL_LIB, 0x70000020UL, \ "symbol-to-library mapping") \ _ELF_DEFINE_SHT(SHT_MIPS_EVENTS, 0x70000021UL, \ "event locations") \ _ELF_DEFINE_SHT(SHT_MIPS_TRANSLATE, 0x70000022UL, \ "???") \ _ELF_DEFINE_SHT(SHT_MIPS_PIXIE, 0x70000023UL, \ "special pixie sections") \ _ELF_DEFINE_SHT(SHT_MIPS_XLATE, 0x70000024UL, \ "address translation table") \ _ELF_DEFINE_SHT(SHT_MIPS_XLATE_DEBUG, 0x70000025UL, \ "SGI internal address translation table") \ _ELF_DEFINE_SHT(SHT_MIPS_WHIRL, 0x70000026UL, \ "intermediate code") \ _ELF_DEFINE_SHT(SHT_MIPS_EH_REGION, 0x70000027UL, \ "C++ exception handling region info") \ _ELF_DEFINE_SHT(SHT_MIPS_XLATE_OLD, 0x70000028UL, \ "obsolete") \ _ELF_DEFINE_SHT(SHT_MIPS_PDR_EXCEPTION, 0x70000029UL, \ "runtime procedure descriptor table exception information") \ _ELF_DEFINE_SHT(SHT_MIPS_ABIFLAGS, 0x7000002AUL, \ "ABI flags") \ _ELF_DEFINE_SHT(SHT_SPARC_GOTDATA, 0x70000000UL, \ "SPARC-specific data") \ _ELF_DEFINE_SHT(SHT_X86_64_UNWIND, 0x70000001UL, \ "unwind tables for the AMD64") \ _ELF_DEFINE_SHT(SHT_ORDERED, 0x7FFFFFFFUL, \ "sort entries in the section") \ _ELF_DEFINE_SHT(SHT_HIPROC, 0x7FFFFFFFUL, \ "end of processor-specific range") \ _ELF_DEFINE_SHT(SHT_LOUSER, 0x80000000UL, \ "start of application-specific range") \ _ELF_DEFINE_SHT(SHT_HIUSER, 0xFFFFFFFFUL, \ "end of application-specific range") #undef _ELF_DEFINE_SHT #define _ELF_DEFINE_SHT(N, V, DESCR) N = V , enum { _ELF_DEFINE_SECTION_TYPES() SHT__LAST__ = SHT_HIUSER }; /* Aliases for section types. */ #define SHT_AMD64_UNWIND SHT_X86_64_UNWIND #define SHT_GNU_verdef SHT_SUNW_verdef #define SHT_GNU_verneed SHT_SUNW_verneed #define SHT_GNU_versym SHT_SUNW_versym /* * Symbol binding information. */ #define _ELF_DEFINE_SYMBOL_BINDING() \ _ELF_DEFINE_STB(STB_LOCAL, 0, \ "not visible outside defining object file") \ _ELF_DEFINE_STB(STB_GLOBAL, 1, \ "visible across all object files being combined") \ _ELF_DEFINE_STB(STB_WEAK, 2, \ "visible across all object files but with low precedence") \ _ELF_DEFINE_STB(STB_LOOS, 10, "start of OS-specific range") \ _ELF_DEFINE_STB(STB_GNU_UNIQUE, 10, "unique symbol (GNU)") \ _ELF_DEFINE_STB(STB_HIOS, 12, "end of OS-specific range") \ _ELF_DEFINE_STB(STB_LOPROC, 13, \ "start of processor-specific range") \ _ELF_DEFINE_STB(STB_HIPROC, 15, \ "end of processor-specific range") #undef _ELF_DEFINE_STB #define _ELF_DEFINE_STB(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_BINDING() STB__LAST__ }; /* * Symbol types */ #define _ELF_DEFINE_SYMBOL_TYPES() \ _ELF_DEFINE_STT(STT_NOTYPE, 0, "unspecified type") \ _ELF_DEFINE_STT(STT_OBJECT, 1, "data object") \ _ELF_DEFINE_STT(STT_FUNC, 2, "executable code") \ _ELF_DEFINE_STT(STT_SECTION, 3, "section") \ _ELF_DEFINE_STT(STT_FILE, 4, "source file") \ _ELF_DEFINE_STT(STT_COMMON, 5, "uninitialized common block") \ _ELF_DEFINE_STT(STT_TLS, 6, "thread local storage") \ _ELF_DEFINE_STT(STT_LOOS, 10, "start of OS-specific types") \ _ELF_DEFINE_STT(STT_GNU_IFUNC, 10, "indirect function") \ _ELF_DEFINE_STT(STT_HIOS, 12, "end of OS-specific types") \ _ELF_DEFINE_STT(STT_LOPROC, 13, \ "start of processor-specific types") \ _ELF_DEFINE_STT(STT_ARM_TFUNC, 13, "Thumb function (GNU)") \ _ELF_DEFINE_STT(STT_ARM_16BIT, 15, "Thumb label (GNU)") \ _ELF_DEFINE_STT(STT_SPARC_REGISTER, 13, "SPARC register information") \ _ELF_DEFINE_STT(STT_HIPROC, 15, \ "end of processor-specific types") #undef _ELF_DEFINE_STT #define _ELF_DEFINE_STT(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_TYPES() STT__LAST__ }; /* * Symbol binding. */ #define _ELF_DEFINE_SYMBOL_BINDING_KINDS() \ _ELF_DEFINE_SYB(SYMINFO_BT_SELF, 0xFFFFU, \ "bound to self") \ _ELF_DEFINE_SYB(SYMINFO_BT_PARENT, 0xFFFEU, \ "bound to parent") \ _ELF_DEFINE_SYB(SYMINFO_BT_NONE, 0xFFFDU, \ "no special binding") #undef _ELF_DEFINE_SYB #define _ELF_DEFINE_SYB(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_BINDING_KINDS() SYMINFO__LAST__ }; /* * Symbol visibility. */ #define _ELF_DEFINE_SYMBOL_VISIBILITY() \ _ELF_DEFINE_STV(STV_DEFAULT, 0, \ "as specified by symbol type") \ _ELF_DEFINE_STV(STV_INTERNAL, 1, \ "as defined by processor semantics") \ _ELF_DEFINE_STV(STV_HIDDEN, 2, \ "hidden from other components") \ _ELF_DEFINE_STV(STV_PROTECTED, 3, \ "local references are not preemptable") #undef _ELF_DEFINE_STV #define _ELF_DEFINE_STV(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_VISIBILITY() STV__LAST__ }; /* * Symbol flags. */ #define _ELF_DEFINE_SYMBOL_FLAGS() \ _ELF_DEFINE_SYF(SYMINFO_FLG_DIRECT, 0x01, \ "directly assocated reference") \ _ELF_DEFINE_SYF(SYMINFO_FLG_COPY, 0x04, \ "definition by copy-relocation") \ _ELF_DEFINE_SYF(SYMINFO_FLG_LAZYLOAD, 0x08, \ "object should be lazily loaded") \ _ELF_DEFINE_SYF(SYMINFO_FLG_DIRECTBIND, 0x10, \ "reference should be directly bound") \ _ELF_DEFINE_SYF(SYMINFO_FLG_NOEXTDIRECT, 0x20, \ "external references not allowed to bind to definition") #undef _ELF_DEFINE_SYF #define _ELF_DEFINE_SYF(N, V, DESCR) N = V , enum { _ELF_DEFINE_SYMBOL_FLAGS() SYMINFO_FLG__LAST__ }; /* * Version dependencies. */ #define _ELF_DEFINE_VERSIONING_DEPENDENCIES() \ _ELF_DEFINE_VERD(VER_NDX_LOCAL, 0, "local scope") \ _ELF_DEFINE_VERD(VER_NDX_GLOBAL, 1, "global scope") #undef _ELF_DEFINE_VERD #define _ELF_DEFINE_VERD(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_DEPENDENCIES() VER_NDX__LAST__ }; /* * Version flags. */ #define _ELF_DEFINE_VERSIONING_FLAGS() \ _ELF_DEFINE_VERF(VER_FLG_BASE, 0x1, "file version") \ _ELF_DEFINE_VERF(VER_FLG_WEAK, 0x2, "weak version") #undef _ELF_DEFINE_VERF #define _ELF_DEFINE_VERF(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_FLAGS() VER_FLG__LAST__ }; /* * Version needs */ #define _ELF_DEFINE_VERSIONING_NEEDS() \ _ELF_DEFINE_VRN(VER_NEED_NONE, 0, "invalid version") \ _ELF_DEFINE_VRN(VER_NEED_CURRENT, 1, "current version") #undef _ELF_DEFINE_VRN #define _ELF_DEFINE_VRN(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_NEEDS() VER_NEED__LAST__ }; /* * Version numbers. */ #define _ELF_DEFINE_VERSIONING_NUMBERS() \ _ELF_DEFINE_VRNU(VER_DEF_NONE, 0, "invalid version") \ _ELF_DEFINE_VRNU(VER_DEF_CURRENT, 1, "current version") #undef _ELF_DEFINE_VRNU #define _ELF_DEFINE_VRNU(N, V, DESCR) N = V , enum { _ELF_DEFINE_VERSIONING_NUMBERS() VER_DEF__LAST__ }; /** ** Relocation types. **/ #define _ELF_DEFINE_386_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_386_NONE, 0) \ _ELF_DEFINE_RELOC(R_386_32, 1) \ _ELF_DEFINE_RELOC(R_386_PC32, 2) \ _ELF_DEFINE_RELOC(R_386_GOT32, 3) \ _ELF_DEFINE_RELOC(R_386_PLT32, 4) \ _ELF_DEFINE_RELOC(R_386_COPY, 5) \ _ELF_DEFINE_RELOC(R_386_GLOB_DAT, 6) \ _ELF_DEFINE_RELOC(R_386_JUMP_SLOT, 7) \ _ELF_DEFINE_RELOC(R_386_RELATIVE, 8) \ _ELF_DEFINE_RELOC(R_386_GOTOFF, 9) \ _ELF_DEFINE_RELOC(R_386_GOTPC, 10) \ _ELF_DEFINE_RELOC(R_386_32PLT, 11) \ _ELF_DEFINE_RELOC(R_386_TLS_TPOFF, 14) \ _ELF_DEFINE_RELOC(R_386_TLS_IE, 15) \ _ELF_DEFINE_RELOC(R_386_TLS_GOTIE, 16) \ _ELF_DEFINE_RELOC(R_386_TLS_LE, 17) \ _ELF_DEFINE_RELOC(R_386_TLS_GD, 18) \ _ELF_DEFINE_RELOC(R_386_TLS_LDM, 19) \ _ELF_DEFINE_RELOC(R_386_16, 20) \ _ELF_DEFINE_RELOC(R_386_PC16, 21) \ _ELF_DEFINE_RELOC(R_386_8, 22) \ _ELF_DEFINE_RELOC(R_386_PC8, 23) \ _ELF_DEFINE_RELOC(R_386_TLS_GD_32, 24) \ _ELF_DEFINE_RELOC(R_386_TLS_GD_PUSH, 25) \ _ELF_DEFINE_RELOC(R_386_TLS_GD_CALL, 26) \ _ELF_DEFINE_RELOC(R_386_TLS_GD_POP, 27) \ _ELF_DEFINE_RELOC(R_386_TLS_LDM_32, 28) \ _ELF_DEFINE_RELOC(R_386_TLS_LDM_PUSH, 29) \ _ELF_DEFINE_RELOC(R_386_TLS_LDM_CALL, 30) \ _ELF_DEFINE_RELOC(R_386_TLS_LDM_POP, 31) \ _ELF_DEFINE_RELOC(R_386_TLS_LDO_32, 32) \ _ELF_DEFINE_RELOC(R_386_TLS_IE_32, 33) \ _ELF_DEFINE_RELOC(R_386_TLS_LE_32, 34) \ _ELF_DEFINE_RELOC(R_386_TLS_DTPMOD32, 35) \ _ELF_DEFINE_RELOC(R_386_TLS_DTPOFF32, 36) \ _ELF_DEFINE_RELOC(R_386_TLS_TPOFF32, 37) \ _ELF_DEFINE_RELOC(R_386_SIZE32, 38) \ _ELF_DEFINE_RELOC(R_386_TLS_GOTDESC, 39) \ _ELF_DEFINE_RELOC(R_386_TLS_DESC_CALL, 40) \ _ELF_DEFINE_RELOC(R_386_TLS_DESC, 41) \ _ELF_DEFINE_RELOC(R_386_IRELATIVE, 42) \ _ELF_DEFINE_RELOC(R_386_GOT32X, 43) /* */ #define _ELF_DEFINE_AARCH64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_AARCH64_NONE, 0) \ _ELF_DEFINE_RELOC(R_AARCH64_ABS64, 257) \ _ELF_DEFINE_RELOC(R_AARCH64_ABS32, 258) \ _ELF_DEFINE_RELOC(R_AARCH64_ABS16, 259) \ _ELF_DEFINE_RELOC(R_AARCH64_PREL64, 260) \ _ELF_DEFINE_RELOC(R_AARCH64_PREL32, 261) \ _ELF_DEFINE_RELOC(R_AARCH64_PREL16, 262) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G0, 263) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G0_NC, 264) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G1, 265) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G1_NC, 266) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G2, 267) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G2_NC, 268) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_UABS_G3, 269) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_SABS_G0, 270) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_SABS_G1, 271) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_SABS_G2, 272) \ _ELF_DEFINE_RELOC(R_AARCH64_LD_PREL_LO19, 273) \ _ELF_DEFINE_RELOC(R_AARCH64_ADR_PREL_LO21, 274) \ _ELF_DEFINE_RELOC(R_AARCH64_ADR_PREL_PG_HI21, 275) \ _ELF_DEFINE_RELOC(R_AARCH64_ADR_PREL_PG_HI21_NC, 276) \ _ELF_DEFINE_RELOC(R_AARCH64_ADD_ABS_LO12_NC, 277) \ _ELF_DEFINE_RELOC(R_AARCH64_LDST8_ABS_LO12_NC, 278) \ _ELF_DEFINE_RELOC(R_AARCH64_TSTBR14, 279) \ _ELF_DEFINE_RELOC(R_AARCH64_CONDBR19, 280) \ _ELF_DEFINE_RELOC(R_AARCH64_JUMP26, 282) \ _ELF_DEFINE_RELOC(R_AARCH64_CALL26, 283) \ _ELF_DEFINE_RELOC(R_AARCH64_LDST16_ABS_LO12_NC, 284) \ _ELF_DEFINE_RELOC(R_AARCH64_LDST32_ABS_LO12_NC, 285) \ _ELF_DEFINE_RELOC(R_AARCH64_LDST64_ABS_LO12_NC, 286) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G0, 287) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G0_NC, 288) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G1, 289) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G1_NC, 290) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G2, 291) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G2_NC, 292) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_PREL_G3, 293) \ _ELF_DEFINE_RELOC(R_AARCH64_LDST128_ABS_LO12_NC, 299) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G0, 300) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G0_NC, 301) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G1, 302) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G1_NC, 303) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G2, 304) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G2_NC, 305) \ _ELF_DEFINE_RELOC(R_AARCH64_MOVW_GOTOFF_G3, 306) \ _ELF_DEFINE_RELOC(R_AARCH64_GOTREL64, 307) \ _ELF_DEFINE_RELOC(R_AARCH64_GOTREL32, 308) \ _ELF_DEFINE_RELOC(R_AARCH64_GOT_LD_PREL19, 309) \ _ELF_DEFINE_RELOC(R_AARCH64_LD64_GOTOFF_LO15, 310) \ _ELF_DEFINE_RELOC(R_AARCH64_ADR_GOT_PAGE, 311) \ _ELF_DEFINE_RELOC(R_AARCH64_LD64_GOT_LO12_NC, 312) \ _ELF_DEFINE_RELOC(R_AARCH64_LD64_GOTPAGE_LO15, 313) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSGD_ADR_PREL21, 512) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSGD_ADR_PAGE21, 513) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSGD_ADD_LO12_NC, 514) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSGD_MOVW_G1, 515) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSGD_MOVW_G0_NC, 516) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_ADR_PREL21, 517) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_ADR_PAGE21, 518) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_ADD_LO12_NC, 519) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_G1, 520) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_G0_NC, 521) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LD_PREL19, 522) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G2, 523) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G1, 524) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC, 525) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G0, 526) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC, 527) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_ADD_DTPREL_HI12, 529) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC, 530) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST8_DTPREL_LO12, 531) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC, 532) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST16_DTPREL_LO12, 533) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC, 534) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST32_DTPREL_LO12, 535) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC, 536) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST64_DTPREL_LO12, 537) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC, 538) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSIE_MOVW_GOTTPREL_G1, 539) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC, 540) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, 541) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, 542) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSIE_LD_GOTTPREL_PREL19, 543) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G2, 544) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G1, 545) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G1_NC, 546) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G0, 547) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_MOVW_TPREL_G0_NC, 548) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_ADD_TPREL_HI12, 549) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_ADD_TPREL_LO12, 550) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_ADD_TPREL_LO12_NC, 551) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST8_TPREL_LO12, 552) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC, 553) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST16_TPREL_LO12, 554) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC, 555) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST32_TPREL_LO12, 556) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC, 557) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST64_TPREL_LO12, 558) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC, 559) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_LD_PREL19, 560) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_ADR_PREL21, 561) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_ADR_PAGE21, 562) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_LD64_LO12, 563) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_ADD_LO12, 564) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_OFF_G1, 565) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_OFF_G0_NC, 566) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_LDR, 567) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_ADD, 568) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC_CALL, 569) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST128_TPREL_LO12, 570) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC, 571) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST128_DTPREL_LO12, 572) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC, 573) \ _ELF_DEFINE_RELOC(R_AARCH64_COPY, 1024) \ _ELF_DEFINE_RELOC(R_AARCH64_GLOB_DAT, 1025) \ _ELF_DEFINE_RELOC(R_AARCH64_JUMP_SLOT, 1026) \ _ELF_DEFINE_RELOC(R_AARCH64_RELATIVE, 1027) \ _ELF_DEFINE_RELOC(R_AARCH64_TLS_DTPREL64, 1028) \ _ELF_DEFINE_RELOC(R_AARCH64_TLS_DTPMOD64, 1029) \ _ELF_DEFINE_RELOC(R_AARCH64_TLS_TPREL64, 1030) \ _ELF_DEFINE_RELOC(R_AARCH64_TLSDESC, 1031) \ _ELF_DEFINE_RELOC(R_AARCH64_IRELATIVE, 1032) /* * These are the symbols used in the Sun ``Linkers and Loaders * Guide'', Document No: 817-1984-17. See the X86_64 relocations list * below for the spellings used in the ELF specification. */ #define _ELF_DEFINE_AMD64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_AMD64_NONE, 0) \ _ELF_DEFINE_RELOC(R_AMD64_64, 1) \ _ELF_DEFINE_RELOC(R_AMD64_PC32, 2) \ _ELF_DEFINE_RELOC(R_AMD64_GOT32, 3) \ _ELF_DEFINE_RELOC(R_AMD64_PLT32, 4) \ _ELF_DEFINE_RELOC(R_AMD64_COPY, 5) \ _ELF_DEFINE_RELOC(R_AMD64_GLOB_DAT, 6) \ _ELF_DEFINE_RELOC(R_AMD64_JUMP_SLOT, 7) \ _ELF_DEFINE_RELOC(R_AMD64_RELATIVE, 8) \ _ELF_DEFINE_RELOC(R_AMD64_GOTPCREL, 9) \ _ELF_DEFINE_RELOC(R_AMD64_32, 10) \ _ELF_DEFINE_RELOC(R_AMD64_32S, 11) \ _ELF_DEFINE_RELOC(R_AMD64_16, 12) \ _ELF_DEFINE_RELOC(R_AMD64_PC16, 13) \ _ELF_DEFINE_RELOC(R_AMD64_8, 14) \ _ELF_DEFINE_RELOC(R_AMD64_PC8, 15) \ _ELF_DEFINE_RELOC(R_AMD64_PC64, 24) \ _ELF_DEFINE_RELOC(R_AMD64_GOTOFF64, 25) \ _ELF_DEFINE_RELOC(R_AMD64_GOTPC32, 26) /* * Relocation definitions from the ARM ELF ABI, version "ARM IHI * 0044E" released on 30th November 2012. */ #define _ELF_DEFINE_ARM_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_ARM_NONE, 0) \ _ELF_DEFINE_RELOC(R_ARM_PC24, 1) \ _ELF_DEFINE_RELOC(R_ARM_ABS32, 2) \ _ELF_DEFINE_RELOC(R_ARM_REL32, 3) \ _ELF_DEFINE_RELOC(R_ARM_LDR_PC_G0, 4) \ _ELF_DEFINE_RELOC(R_ARM_ABS16, 5) \ _ELF_DEFINE_RELOC(R_ARM_ABS12, 6) \ _ELF_DEFINE_RELOC(R_ARM_THM_ABS5, 7) \ _ELF_DEFINE_RELOC(R_ARM_ABS8, 8) \ _ELF_DEFINE_RELOC(R_ARM_SBREL32, 9) \ _ELF_DEFINE_RELOC(R_ARM_THM_CALL, 10) \ _ELF_DEFINE_RELOC(R_ARM_THM_PC8, 11) \ _ELF_DEFINE_RELOC(R_ARM_BREL_ADJ, 12) \ _ELF_DEFINE_RELOC(R_ARM_SWI24, 13) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DESC, 13) \ _ELF_DEFINE_RELOC(R_ARM_THM_SWI8, 14) \ _ELF_DEFINE_RELOC(R_ARM_XPC25, 15) \ _ELF_DEFINE_RELOC(R_ARM_THM_XPC22, 16) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DTPMOD32, 17) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DTPOFF32, 18) \ _ELF_DEFINE_RELOC(R_ARM_TLS_TPOFF32, 19) \ _ELF_DEFINE_RELOC(R_ARM_COPY, 20) \ _ELF_DEFINE_RELOC(R_ARM_GLOB_DAT, 21) \ _ELF_DEFINE_RELOC(R_ARM_JUMP_SLOT, 22) \ _ELF_DEFINE_RELOC(R_ARM_RELATIVE, 23) \ _ELF_DEFINE_RELOC(R_ARM_GOTOFF32, 24) \ _ELF_DEFINE_RELOC(R_ARM_BASE_PREL, 25) \ _ELF_DEFINE_RELOC(R_ARM_GOT_BREL, 26) \ _ELF_DEFINE_RELOC(R_ARM_PLT32, 27) \ _ELF_DEFINE_RELOC(R_ARM_CALL, 28) \ _ELF_DEFINE_RELOC(R_ARM_JUMP24, 29) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP24, 30) \ _ELF_DEFINE_RELOC(R_ARM_BASE_ABS, 31) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PCREL_7_0, 32) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PCREL_15_8, 33) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PCREL_23_15, 34) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SBREL_11_0_NC, 35) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_19_12_NC, 36) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SBREL_27_20_CK, 37) \ _ELF_DEFINE_RELOC(R_ARM_TARGET1, 38) \ _ELF_DEFINE_RELOC(R_ARM_SBREL31, 39) \ _ELF_DEFINE_RELOC(R_ARM_V4BX, 40) \ _ELF_DEFINE_RELOC(R_ARM_TARGET2, 41) \ _ELF_DEFINE_RELOC(R_ARM_PREL31, 42) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_ABS_NC, 43) \ _ELF_DEFINE_RELOC(R_ARM_MOVT_ABS, 44) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_PREL_NC, 45) \ _ELF_DEFINE_RELOC(R_ARM_MOVT_PREL, 46) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_ABS_NC, 47) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVT_ABS, 48) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_PREL_NC, 49) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVT_PREL, 50) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP19, 51) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP6, 52) \ _ELF_DEFINE_RELOC(R_ARM_THM_ALU_PREL_11_0, 53) \ _ELF_DEFINE_RELOC(R_ARM_THM_PC12, 54) \ _ELF_DEFINE_RELOC(R_ARM_ABS32_NOI, 55) \ _ELF_DEFINE_RELOC(R_ARM_REL32_NOI, 56) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0_NC, 57) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G0, 58) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1_NC, 59) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G1, 60) \ _ELF_DEFINE_RELOC(R_ARM_ALU_PC_G2, 61) \ _ELF_DEFINE_RELOC(R_ARM_LDR_PC_G1, 62) \ _ELF_DEFINE_RELOC(R_ARM_LDR_PC_G2, 63) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G0, 64) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G1, 65) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_PC_G2, 66) \ _ELF_DEFINE_RELOC(R_ARM_LDC_PC_G0, 67) \ _ELF_DEFINE_RELOC(R_ARM_LDC_PC_G1, 68) \ _ELF_DEFINE_RELOC(R_ARM_LDC_PC_G2, 69) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0_NC, 70) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G0, 71) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1_NC, 72) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G1, 73) \ _ELF_DEFINE_RELOC(R_ARM_ALU_SB_G2, 74) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SB_G0, 75) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SB_G1, 76) \ _ELF_DEFINE_RELOC(R_ARM_LDR_SB_G2, 77) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G0, 78) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G1, 79) \ _ELF_DEFINE_RELOC(R_ARM_LDRS_SB_G2, 80) \ _ELF_DEFINE_RELOC(R_ARM_LDC_SB_G0, 81) \ _ELF_DEFINE_RELOC(R_ARM_LDC_SB_G1, 82) \ _ELF_DEFINE_RELOC(R_ARM_LDC_SB_G2, 83) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_BREL_NC, 84) \ _ELF_DEFINE_RELOC(R_ARM_MOVT_BREL, 85) \ _ELF_DEFINE_RELOC(R_ARM_MOVW_BREL, 86) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL_NC, 87) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVT_BREL, 88) \ _ELF_DEFINE_RELOC(R_ARM_THM_MOVW_BREL, 89) \ _ELF_DEFINE_RELOC(R_ARM_TLS_GOTDESC, 90) \ _ELF_DEFINE_RELOC(R_ARM_TLS_CALL, 91) \ _ELF_DEFINE_RELOC(R_ARM_TLS_DESCSEQ, 92) \ _ELF_DEFINE_RELOC(R_ARM_THM_TLS_CALL, 93) \ _ELF_DEFINE_RELOC(R_ARM_PLT32_ABS, 94) \ _ELF_DEFINE_RELOC(R_ARM_GOT_ABS, 95) \ _ELF_DEFINE_RELOC(R_ARM_GOT_PREL, 96) \ _ELF_DEFINE_RELOC(R_ARM_GOT_BREL12, 97) \ _ELF_DEFINE_RELOC(R_ARM_GOTOFF12, 98) \ _ELF_DEFINE_RELOC(R_ARM_GOTRELAX, 99) \ _ELF_DEFINE_RELOC(R_ARM_GNU_VTENTRY, 100) \ _ELF_DEFINE_RELOC(R_ARM_GNU_VTINHERIT, 101) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP11, 102) \ _ELF_DEFINE_RELOC(R_ARM_THM_JUMP8, 103) \ _ELF_DEFINE_RELOC(R_ARM_TLS_GD32, 104) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LDM32, 105) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LDO32, 106) \ _ELF_DEFINE_RELOC(R_ARM_TLS_IE32, 107) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LE32, 108) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LDO12, 109) \ _ELF_DEFINE_RELOC(R_ARM_TLS_LE12, 110) \ _ELF_DEFINE_RELOC(R_ARM_TLS_IE12GP, 111) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_0, 112) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_1, 113) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_2, 114) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_3, 115) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_4, 116) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_5, 117) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_6, 118) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_7, 119) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_8, 120) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_9, 121) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_10, 122) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_11, 123) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_12, 124) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_13, 125) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_14, 126) \ _ELF_DEFINE_RELOC(R_ARM_PRIVATE_15, 127) \ _ELF_DEFINE_RELOC(R_ARM_ME_TOO, 128) \ _ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ16, 129) \ _ELF_DEFINE_RELOC(R_ARM_THM_TLS_DESCSEQ32, 130) \ _ELF_DEFINE_RELOC(R_ARM_THM_GOT_BREL12, 131) \ _ELF_DEFINE_RELOC(R_ARM_IRELATIVE, 140) #define _ELF_DEFINE_IA64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_IA_64_NONE, 0) \ _ELF_DEFINE_RELOC(R_IA_64_IMM14, 0x21) \ _ELF_DEFINE_RELOC(R_IA_64_IMM22, 0x22) \ _ELF_DEFINE_RELOC(R_IA_64_IMM64, 0x23) \ _ELF_DEFINE_RELOC(R_IA_64_DIR32MSB, 0x24) \ _ELF_DEFINE_RELOC(R_IA_64_DIR32LSB, 0x25) \ _ELF_DEFINE_RELOC(R_IA_64_DIR64MSB, 0x26) \ _ELF_DEFINE_RELOC(R_IA_64_DIR64LSB, 0x27) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL22, 0x2a) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL64I, 0x2b) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL32MSB, 0x2c) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL32LSB, 0x2d) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL64MSB, 0x2e) \ _ELF_DEFINE_RELOC(R_IA_64_GPREL64LSB, 0x2f) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF22, 0x32) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF64I, 0x33) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF22, 0x3a) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF64I, 0x3b) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF64MSB, 0x3e) \ _ELF_DEFINE_RELOC(R_IA_64_PLTOFF64LSB, 0x3f) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR64I, 0x43) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR32MSB, 0x44) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR32LSB, 0x45) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR64MSB, 0x46) \ _ELF_DEFINE_RELOC(R_IA_64_FPTR64LSB, 0x47) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL60B, 0x48) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21B, 0x49) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21M, 0x4a) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21F, 0x4b) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL32MSB, 0x4c) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL32LSB, 0x4d) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL64MSB, 0x4e) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL64LSB, 0x4f) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR22, 0x52) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64I, 0x53) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32MSB, 0x54) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR32LSB, 0x55) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64MSB, 0x56) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_FPTR64LSB, 0x57) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL32MSB, 0x5c) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL32LSB, 0x5d) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL64MSB, 0x5e) \ _ELF_DEFINE_RELOC(R_IA_64_SEGREL64LSB, 0x5f) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL32MSB, 0x64) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL32LSB, 0x65) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL64MSB, 0x66) \ _ELF_DEFINE_RELOC(R_IA_64_SECREL64LSB, 0x67) \ _ELF_DEFINE_RELOC(R_IA_64_REL32MSB, 0x6c) \ _ELF_DEFINE_RELOC(R_IA_64_REL32LSB, 0x6d) \ _ELF_DEFINE_RELOC(R_IA_64_REL64MSB, 0x6e) \ _ELF_DEFINE_RELOC(R_IA_64_REL64LSB, 0x6f) \ _ELF_DEFINE_RELOC(R_IA_64_LTV32MSB, 0x74) \ _ELF_DEFINE_RELOC(R_IA_64_LTV32LSB, 0x75) \ _ELF_DEFINE_RELOC(R_IA_64_LTV64MSB, 0x76) \ _ELF_DEFINE_RELOC(R_IA_64_LTV64LSB, 0x77) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL21BI, 0x79) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL22, 0x7A) \ _ELF_DEFINE_RELOC(R_IA_64_PCREL64I, 0x7B) \ _ELF_DEFINE_RELOC(R_IA_64_IPLTMSB, 0x80) \ _ELF_DEFINE_RELOC(R_IA_64_IPLTLSB, 0x81) \ _ELF_DEFINE_RELOC(R_IA_64_SUB, 0x85) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF22X, 0x86) \ _ELF_DEFINE_RELOC(R_IA_64_LDXMOV, 0x87) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL14, 0x91) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL22, 0x92) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL64I, 0x93) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL64MSB, 0x96) \ _ELF_DEFINE_RELOC(R_IA_64_TPREL64LSB, 0x97) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_TPREL22, 0x9A) \ _ELF_DEFINE_RELOC(R_IA_64_DTPMOD64MSB, 0xA6) \ _ELF_DEFINE_RELOC(R_IA_64_DTPMOD64LSB, 0xA7) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPMOD22, 0xAA) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL14, 0xB1) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL22, 0xB2) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL64I, 0xB3) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL32MSB, 0xB4) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL32LSB, 0xB5) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL64MSB, 0xB6) \ _ELF_DEFINE_RELOC(R_IA_64_DTPREL64LSB, 0xB7) \ _ELF_DEFINE_RELOC(R_IA_64_LTOFF_DTPREL22, 0xBA) #define _ELF_DEFINE_MIPS_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_MIPS_NONE, 0) \ _ELF_DEFINE_RELOC(R_MIPS_16, 1) \ _ELF_DEFINE_RELOC(R_MIPS_32, 2) \ _ELF_DEFINE_RELOC(R_MIPS_REL32, 3) \ _ELF_DEFINE_RELOC(R_MIPS_26, 4) \ _ELF_DEFINE_RELOC(R_MIPS_HI16, 5) \ _ELF_DEFINE_RELOC(R_MIPS_LO16, 6) \ _ELF_DEFINE_RELOC(R_MIPS_GPREL16, 7) \ _ELF_DEFINE_RELOC(R_MIPS_LITERAL, 8) \ _ELF_DEFINE_RELOC(R_MIPS_GOT16, 9) \ _ELF_DEFINE_RELOC(R_MIPS_PC16, 10) \ _ELF_DEFINE_RELOC(R_MIPS_CALL16, 11) \ _ELF_DEFINE_RELOC(R_MIPS_GPREL32, 12) \ _ELF_DEFINE_RELOC(R_MIPS_SHIFT5, 16) \ _ELF_DEFINE_RELOC(R_MIPS_SHIFT6, 17) \ _ELF_DEFINE_RELOC(R_MIPS_64, 18) \ _ELF_DEFINE_RELOC(R_MIPS_GOT_DISP, 19) \ _ELF_DEFINE_RELOC(R_MIPS_GOT_PAGE, 20) \ _ELF_DEFINE_RELOC(R_MIPS_GOT_OFST, 21) \ _ELF_DEFINE_RELOC(R_MIPS_GOT_HI16, 22) \ _ELF_DEFINE_RELOC(R_MIPS_GOT_LO16, 23) \ _ELF_DEFINE_RELOC(R_MIPS_SUB, 24) \ _ELF_DEFINE_RELOC(R_MIPS_CALLHI16, 30) \ _ELF_DEFINE_RELOC(R_MIPS_CALLLO16, 31) \ _ELF_DEFINE_RELOC(R_MIPS_JALR, 37) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_DTPMOD32, 38) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_DTPREL32, 39) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_DTPMOD64, 40) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_DTPREL64, 41) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_GD, 42) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_LDM, 43) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_DTPREL_HI16, 44) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_DTPREL_LO16, 45) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_GOTTPREL, 46) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_TPREL32, 47) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_TPREL64, 48) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_TPREL_HI16, 49) \ _ELF_DEFINE_RELOC(R_MIPS_TLS_TPREL_LO16, 50) #define _ELF_DEFINE_PPC32_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_PPC_NONE, 0) \ _ELF_DEFINE_RELOC(R_PPC_ADDR32, 1) \ _ELF_DEFINE_RELOC(R_PPC_ADDR24, 2) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16, 3) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16_LO, 4) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16_HI, 5) \ _ELF_DEFINE_RELOC(R_PPC_ADDR16_HA, 6) \ _ELF_DEFINE_RELOC(R_PPC_ADDR14, 7) \ _ELF_DEFINE_RELOC(R_PPC_ADDR14_BRTAKEN, 8) \ _ELF_DEFINE_RELOC(R_PPC_ADDR14_BRNTAKEN, 9) \ _ELF_DEFINE_RELOC(R_PPC_REL24, 10) \ _ELF_DEFINE_RELOC(R_PPC_REL14, 11) \ _ELF_DEFINE_RELOC(R_PPC_REL14_BRTAKEN, 12) \ _ELF_DEFINE_RELOC(R_PPC_REL14_BRNTAKEN, 13) \ _ELF_DEFINE_RELOC(R_PPC_GOT16, 14) \ _ELF_DEFINE_RELOC(R_PPC_GOT16_LO, 15) \ _ELF_DEFINE_RELOC(R_PPC_GOT16_HI, 16) \ _ELF_DEFINE_RELOC(R_PPC_GOT16_HA, 17) \ _ELF_DEFINE_RELOC(R_PPC_PLTREL24, 18) \ _ELF_DEFINE_RELOC(R_PPC_COPY, 19) \ _ELF_DEFINE_RELOC(R_PPC_GLOB_DAT, 20) \ _ELF_DEFINE_RELOC(R_PPC_JMP_SLOT, 21) \ _ELF_DEFINE_RELOC(R_PPC_RELATIVE, 22) \ _ELF_DEFINE_RELOC(R_PPC_LOCAL24PC, 23) \ _ELF_DEFINE_RELOC(R_PPC_UADDR32, 24) \ _ELF_DEFINE_RELOC(R_PPC_UADDR16, 25) \ _ELF_DEFINE_RELOC(R_PPC_REL32, 26) \ _ELF_DEFINE_RELOC(R_PPC_PLT32, 27) \ _ELF_DEFINE_RELOC(R_PPC_PLTREL32, 28) \ _ELF_DEFINE_RELOC(R_PPC_PLT16_LO, 29) \ _ELF_DEFINE_RELOC(R_PPC_PLT16_HI, 30) \ _ELF_DEFINE_RELOC(R_PPC_PLT16_HA, 31) \ _ELF_DEFINE_RELOC(R_PPC_SDAREL16, 32) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF, 33) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF_LO, 34) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF_HI, 35) \ _ELF_DEFINE_RELOC(R_PPC_SECTOFF_HA, 36) \ _ELF_DEFINE_RELOC(R_PPC_ADDR30, 37) \ _ELF_DEFINE_RELOC(R_PPC_TLS, 67) \ _ELF_DEFINE_RELOC(R_PPC_DTPMOD32, 68) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16, 69) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16_LO, 70) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16_HI, 71) \ _ELF_DEFINE_RELOC(R_PPC_TPREL16_HA, 72) \ _ELF_DEFINE_RELOC(R_PPC_TPREL32, 73) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16, 74) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16_LO, 75) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16_HI, 76) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL16_HA, 77) \ _ELF_DEFINE_RELOC(R_PPC_DTPREL32, 78) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16, 79) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_LO, 80) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HI, 81) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSGD16_HA, 82) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16, 83) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_LO, 84) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HI, 85) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TLSLD16_HA, 86) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16, 87) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_LO, 88) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HI, 89) \ _ELF_DEFINE_RELOC(R_PPC_GOT_TPREL16_HA, 90) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16, 91) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_LO, 92) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HI, 93) \ _ELF_DEFINE_RELOC(R_PPC_GOT_DTPREL16_HA, 94) \ _ELF_DEFINE_RELOC(R_PPC_TLSGD, 95) \ _ELF_DEFINE_RELOC(R_PPC_TLSLD, 96) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR32, 101) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16, 102) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_LO, 103) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HI, 104) \ _ELF_DEFINE_RELOC(R_PPC_EMB_NADDR16_HA, 105) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDAI16, 106) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDA2I16, 107) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDA2REL, 108) \ _ELF_DEFINE_RELOC(R_PPC_EMB_SDA21, 109) \ _ELF_DEFINE_RELOC(R_PPC_EMB_MRKREF, 110) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELSEC16, 111) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELST_LO, 112) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HI, 113) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELST_HA, 114) \ _ELF_DEFINE_RELOC(R_PPC_EMB_BIT_FLD, 115) \ _ELF_DEFINE_RELOC(R_PPC_EMB_RELSDA, 116) \ #define _ELF_DEFINE_PPC64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_PPC64_NONE, 0) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR32, 1) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR24, 2) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16, 3) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO, 4) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HI, 5) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HA, 6) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR14, 7) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRTAKEN, 8) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR14_BRNTAKEN, 9) \ _ELF_DEFINE_RELOC(R_PPC64_REL24, 10) \ _ELF_DEFINE_RELOC(R_PPC64_REL14, 11) \ _ELF_DEFINE_RELOC(R_PPC64_REL14_BRTAKEN, 12) \ _ELF_DEFINE_RELOC(R_PPC64_REL14_BRNTAKEN, 13) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16, 14) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_LO, 15) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_HI, 16) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_HA, 17) \ _ELF_DEFINE_RELOC(R_PPC64_COPY, 19) \ _ELF_DEFINE_RELOC(R_PPC64_GLOB_DAT, 20) \ _ELF_DEFINE_RELOC(R_PPC64_JMP_SLOT, 21) \ _ELF_DEFINE_RELOC(R_PPC64_RELATIVE, 22) \ _ELF_DEFINE_RELOC(R_PPC64_UADDR32, 24) \ _ELF_DEFINE_RELOC(R_PPC64_UADDR16, 25) \ _ELF_DEFINE_RELOC(R_PPC64_REL32, 26) \ _ELF_DEFINE_RELOC(R_PPC64_PLT32, 27) \ _ELF_DEFINE_RELOC(R_PPC64_PLTREL32, 28) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_LO, 29) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_HI, 30) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_HA, 31) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF, 33) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO, 34) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HI, 35) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_HA, 36) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR30, 37) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR64, 38) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHER, 39) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHERA, 40) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHEST, 41) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_HIGHESTA, 42) \ _ELF_DEFINE_RELOC(R_PPC64_UADDR64, 43) \ _ELF_DEFINE_RELOC(R_PPC64_REL64, 44) \ _ELF_DEFINE_RELOC(R_PPC64_PLT64, 45) \ _ELF_DEFINE_RELOC(R_PPC64_PLTREL64, 46) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16, 47) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_LO, 48) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_HI, 49) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_HA, 50) \ _ELF_DEFINE_RELOC(R_PPC64_TOC, 51) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16, 52) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO, 53) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HI, 54) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_HA, 55) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_DS, 56) \ _ELF_DEFINE_RELOC(R_PPC64_ADDR16_LO_DS, 57) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_DS, 58) \ _ELF_DEFINE_RELOC(R_PPC64_GOT16_LO_DS, 59) \ _ELF_DEFINE_RELOC(R_PPC64_PLT16_LO_DS, 60) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_DS, 61) \ _ELF_DEFINE_RELOC(R_PPC64_SECTOFF_LO_DS, 62) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_DS, 63) \ _ELF_DEFINE_RELOC(R_PPC64_TOC16_LO_DS, 64) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_DS, 65) \ _ELF_DEFINE_RELOC(R_PPC64_PLTGOT16_LO_DS, 66) \ _ELF_DEFINE_RELOC(R_PPC64_TLS, 67) \ _ELF_DEFINE_RELOC(R_PPC64_DTPMOD64, 68) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16, 69) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO, 60) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HI, 71) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HA, 72) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL64, 73) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16, 74) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO, 75) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HI, 76) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HA, 77) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL64, 78) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16, 79) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_LO, 80) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HI, 81) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSGD16_HA, 82) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16, 83) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_LO, 84) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HI, 85) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TLSLD16_HA, 86) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_DS, 87) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_LO_DS, 88) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HI, 89) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_TPREL16_HA, 90) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_DS, 91) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_LO_DS, 92) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HI, 93) \ _ELF_DEFINE_RELOC(R_PPC64_GOT_DTPREL16_HA, 94) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_DS, 95) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_LO_DS, 96) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHER, 97) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHERA, 98) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHEST, 99) \ _ELF_DEFINE_RELOC(R_PPC64_TPREL16_HIGHESTA, 100) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_DS, 101) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_LO_DS, 102) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHER, 103) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHERA, 104) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHEST, 105) \ _ELF_DEFINE_RELOC(R_PPC64_DTPREL16_HIGHESTA, 106) \ _ELF_DEFINE_RELOC(R_PPC64_TLSGD, 107) \ _ELF_DEFINE_RELOC(R_PPC64_TLSLD, 108) #define _ELF_DEFINE_RISCV_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_RISCV_NONE, 0) \ _ELF_DEFINE_RELOC(R_RISCV_32, 1) \ _ELF_DEFINE_RELOC(R_RISCV_64, 2) \ _ELF_DEFINE_RELOC(R_RISCV_RELATIVE, 3) \ _ELF_DEFINE_RELOC(R_RISCV_COPY, 4) \ _ELF_DEFINE_RELOC(R_RISCV_JUMP_SLOT, 5) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_DTPMOD32, 6) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_DTPMOD64, 7) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_DTPREL32, 8) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_DTPREL64, 9) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_TPREL32, 10) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_TPREL64, 11) \ _ELF_DEFINE_RELOC(R_RISCV_BRANCH, 16) \ _ELF_DEFINE_RELOC(R_RISCV_JAL, 17) \ _ELF_DEFINE_RELOC(R_RISCV_CALL, 18) \ _ELF_DEFINE_RELOC(R_RISCV_CALL_PLT, 19) \ _ELF_DEFINE_RELOC(R_RISCV_GOT_HI20, 20) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_GOT_HI20, 21) \ _ELF_DEFINE_RELOC(R_RISCV_TLS_GD_HI20, 22) \ _ELF_DEFINE_RELOC(R_RISCV_PCREL_HI20, 23) \ _ELF_DEFINE_RELOC(R_RISCV_PCREL_LO12_I, 24) \ _ELF_DEFINE_RELOC(R_RISCV_PCREL_LO12_S, 25) \ _ELF_DEFINE_RELOC(R_RISCV_HI20, 26) \ _ELF_DEFINE_RELOC(R_RISCV_LO12_I, 27) \ _ELF_DEFINE_RELOC(R_RISCV_LO12_S, 28) \ _ELF_DEFINE_RELOC(R_RISCV_TPREL_HI20, 29) \ _ELF_DEFINE_RELOC(R_RISCV_TPREL_LO12_I, 30) \ _ELF_DEFINE_RELOC(R_RISCV_TPREL_LO12_S, 31) \ _ELF_DEFINE_RELOC(R_RISCV_TPREL_ADD, 32) \ _ELF_DEFINE_RELOC(R_RISCV_ADD8, 33) \ _ELF_DEFINE_RELOC(R_RISCV_ADD16, 34) \ _ELF_DEFINE_RELOC(R_RISCV_ADD32, 35) \ _ELF_DEFINE_RELOC(R_RISCV_ADD64, 36) \ _ELF_DEFINE_RELOC(R_RISCV_SUB8, 37) \ _ELF_DEFINE_RELOC(R_RISCV_SUB16, 38) \ _ELF_DEFINE_RELOC(R_RISCV_SUB32, 39) \ _ELF_DEFINE_RELOC(R_RISCV_SUB64, 40) \ _ELF_DEFINE_RELOC(R_RISCV_GNU_VTINHERIT, 41) \ _ELF_DEFINE_RELOC(R_RISCV_GNU_VTENTRY, 42) \ _ELF_DEFINE_RELOC(R_RISCV_ALIGN, 43) \ _ELF_DEFINE_RELOC(R_RISCV_RVC_BRANCH, 44) \ _ELF_DEFINE_RELOC(R_RISCV_RVC_JUMP, 45) \ _ELF_DEFINE_RELOC(R_RISCV_RVC_LUI, 46) \ _ELF_DEFINE_RELOC(R_RISCV_GPREL_I, 47) \ _ELF_DEFINE_RELOC(R_RISCV_GPREL_S, 48) #define _ELF_DEFINE_SPARC_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_SPARC_NONE, 0) \ _ELF_DEFINE_RELOC(R_SPARC_8, 1) \ _ELF_DEFINE_RELOC(R_SPARC_16, 2) \ _ELF_DEFINE_RELOC(R_SPARC_32, 3) \ _ELF_DEFINE_RELOC(R_SPARC_DISP8, 4) \ _ELF_DEFINE_RELOC(R_SPARC_DISP16, 5) \ _ELF_DEFINE_RELOC(R_SPARC_DISP32, 6) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP30, 7) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP22, 8) \ _ELF_DEFINE_RELOC(R_SPARC_HI22, 9) \ _ELF_DEFINE_RELOC(R_SPARC_22, 10) \ _ELF_DEFINE_RELOC(R_SPARC_13, 11) \ _ELF_DEFINE_RELOC(R_SPARC_LO10, 12) \ _ELF_DEFINE_RELOC(R_SPARC_GOT10, 13) \ _ELF_DEFINE_RELOC(R_SPARC_GOT13, 14) \ _ELF_DEFINE_RELOC(R_SPARC_GOT22, 15) \ _ELF_DEFINE_RELOC(R_SPARC_PC10, 16) \ _ELF_DEFINE_RELOC(R_SPARC_PC22, 17) \ _ELF_DEFINE_RELOC(R_SPARC_WPLT30, 18) \ _ELF_DEFINE_RELOC(R_SPARC_COPY, 19) \ _ELF_DEFINE_RELOC(R_SPARC_GLOB_DAT, 20) \ _ELF_DEFINE_RELOC(R_SPARC_JMP_SLOT, 21) \ _ELF_DEFINE_RELOC(R_SPARC_RELATIVE, 22) \ _ELF_DEFINE_RELOC(R_SPARC_UA32, 23) \ _ELF_DEFINE_RELOC(R_SPARC_PLT32, 24) \ _ELF_DEFINE_RELOC(R_SPARC_HIPLT22, 25) \ _ELF_DEFINE_RELOC(R_SPARC_LOPLT10, 26) \ _ELF_DEFINE_RELOC(R_SPARC_PCPLT32, 27) \ _ELF_DEFINE_RELOC(R_SPARC_PCPLT22, 28) \ _ELF_DEFINE_RELOC(R_SPARC_PCPLT10, 29) \ _ELF_DEFINE_RELOC(R_SPARC_10, 30) \ _ELF_DEFINE_RELOC(R_SPARC_11, 31) \ _ELF_DEFINE_RELOC(R_SPARC_64, 32) \ _ELF_DEFINE_RELOC(R_SPARC_OLO10, 33) \ _ELF_DEFINE_RELOC(R_SPARC_HH22, 34) \ _ELF_DEFINE_RELOC(R_SPARC_HM10, 35) \ _ELF_DEFINE_RELOC(R_SPARC_LM22, 36) \ _ELF_DEFINE_RELOC(R_SPARC_PC_HH22, 37) \ _ELF_DEFINE_RELOC(R_SPARC_PC_HM10, 38) \ _ELF_DEFINE_RELOC(R_SPARC_PC_LM22, 39) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP16, 40) \ _ELF_DEFINE_RELOC(R_SPARC_WDISP19, 41) \ _ELF_DEFINE_RELOC(R_SPARC_GLOB_JMP, 42) \ _ELF_DEFINE_RELOC(R_SPARC_7, 43) \ _ELF_DEFINE_RELOC(R_SPARC_5, 44) \ _ELF_DEFINE_RELOC(R_SPARC_6, 45) \ _ELF_DEFINE_RELOC(R_SPARC_DISP64, 46) \ _ELF_DEFINE_RELOC(R_SPARC_PLT64, 47) \ _ELF_DEFINE_RELOC(R_SPARC_HIX22, 48) \ _ELF_DEFINE_RELOC(R_SPARC_LOX10, 49) \ _ELF_DEFINE_RELOC(R_SPARC_H44, 50) \ _ELF_DEFINE_RELOC(R_SPARC_M44, 51) \ _ELF_DEFINE_RELOC(R_SPARC_L44, 52) \ _ELF_DEFINE_RELOC(R_SPARC_REGISTER, 53) \ _ELF_DEFINE_RELOC(R_SPARC_UA64, 54) \ _ELF_DEFINE_RELOC(R_SPARC_UA16, 55) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_GD_HI22, 56) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_GD_LO10, 57) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_GD_ADD, 58) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_GD_CALL, 59) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDM_HI22, 60) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDM_LO10, 61) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDM_ADD, 62) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDM_CALL, 63) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDO_HIX22, 64) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDO_LOX10, 65) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LDO_ADD, 66) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_IE_HI22, 67) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_IE_LO10, 68) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_IE_LD, 69) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_IE_LDX, 70) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_IE_ADD, 71) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LE_HIX22, 72) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_LE_LOX10, 73) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_DTPMOD32, 74) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_DTPMOD64, 75) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_DTPOFF32, 76) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_DTPOFF64, 77) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_TPOFF32, 78) \ _ELF_DEFINE_RELOC(R_SPARC_TLS_TPOFF64, 79) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_HIX22, 80) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_LOX10, 81) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_HIX22, 82) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP_LOX10, 83) \ _ELF_DEFINE_RELOC(R_SPARC_GOTDATA_OP, 84) \ _ELF_DEFINE_RELOC(R_SPARC_H34, 85) #define _ELF_DEFINE_X86_64_RELOCATIONS() \ _ELF_DEFINE_RELOC(R_X86_64_NONE, 0) \ _ELF_DEFINE_RELOC(R_X86_64_64, 1) \ _ELF_DEFINE_RELOC(R_X86_64_PC32, 2) \ _ELF_DEFINE_RELOC(R_X86_64_GOT32, 3) \ _ELF_DEFINE_RELOC(R_X86_64_PLT32, 4) \ _ELF_DEFINE_RELOC(R_X86_64_COPY, 5) \ _ELF_DEFINE_RELOC(R_X86_64_GLOB_DAT, 6) \ _ELF_DEFINE_RELOC(R_X86_64_JUMP_SLOT, 7) \ _ELF_DEFINE_RELOC(R_X86_64_RELATIVE, 8) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPCREL, 9) \ _ELF_DEFINE_RELOC(R_X86_64_32, 10) \ _ELF_DEFINE_RELOC(R_X86_64_32S, 11) \ _ELF_DEFINE_RELOC(R_X86_64_16, 12) \ _ELF_DEFINE_RELOC(R_X86_64_PC16, 13) \ _ELF_DEFINE_RELOC(R_X86_64_8, 14) \ _ELF_DEFINE_RELOC(R_X86_64_PC8, 15) \ _ELF_DEFINE_RELOC(R_X86_64_DTPMOD64, 16) \ _ELF_DEFINE_RELOC(R_X86_64_DTPOFF64, 17) \ _ELF_DEFINE_RELOC(R_X86_64_TPOFF64, 18) \ _ELF_DEFINE_RELOC(R_X86_64_TLSGD, 19) \ _ELF_DEFINE_RELOC(R_X86_64_TLSLD, 20) \ _ELF_DEFINE_RELOC(R_X86_64_DTPOFF32, 21) \ _ELF_DEFINE_RELOC(R_X86_64_GOTTPOFF, 22) \ _ELF_DEFINE_RELOC(R_X86_64_TPOFF32, 23) \ _ELF_DEFINE_RELOC(R_X86_64_PC64, 24) \ _ELF_DEFINE_RELOC(R_X86_64_GOTOFF64, 25) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC32, 26) \ _ELF_DEFINE_RELOC(R_X86_64_GOT64, 27) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPCREL64, 28) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC64, 29) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPLT64, 30) \ _ELF_DEFINE_RELOC(R_X86_64_PLTOFF64, 31) \ _ELF_DEFINE_RELOC(R_X86_64_SIZE32, 32) \ _ELF_DEFINE_RELOC(R_X86_64_SIZE64, 33) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPC32_TLSDESC, 34) \ _ELF_DEFINE_RELOC(R_X86_64_TLSDESC_CALL, 35) \ _ELF_DEFINE_RELOC(R_X86_64_TLSDESC, 36) \ _ELF_DEFINE_RELOC(R_X86_64_IRELATIVE, 37) \ _ELF_DEFINE_RELOC(R_X86_64_RELATIVE64, 38) \ _ELF_DEFINE_RELOC(R_X86_64_GOTPCRELX, 41) \ _ELF_DEFINE_RELOC(R_X86_64_REX_GOTPCRELX, 42) #define _ELF_DEFINE_RELOCATIONS() \ _ELF_DEFINE_386_RELOCATIONS() \ _ELF_DEFINE_AARCH64_RELOCATIONS() \ _ELF_DEFINE_AMD64_RELOCATIONS() \ _ELF_DEFINE_ARM_RELOCATIONS() \ _ELF_DEFINE_IA64_RELOCATIONS() \ _ELF_DEFINE_MIPS_RELOCATIONS() \ _ELF_DEFINE_PPC32_RELOCATIONS() \ _ELF_DEFINE_PPC64_RELOCATIONS() \ _ELF_DEFINE_RISCV_RELOCATIONS() \ _ELF_DEFINE_SPARC_RELOCATIONS() \ _ELF_DEFINE_X86_64_RELOCATIONS() #undef _ELF_DEFINE_RELOC #define _ELF_DEFINE_RELOC(N, V) N = V , enum { _ELF_DEFINE_RELOCATIONS() R__LAST__ }; #define PN_XNUM 0xFFFFU /* Use extended section numbering. */ /** ** ELF Types. **/ typedef uint32_t Elf32_Addr; /* Program address. */ typedef uint8_t Elf32_Byte; /* Unsigned tiny integer. */ typedef uint16_t Elf32_Half; /* Unsigned medium integer. */ typedef uint32_t Elf32_Off; /* File offset. */ typedef uint16_t Elf32_Section; /* Section index. */ typedef int32_t Elf32_Sword; /* Signed integer. */ typedef uint32_t Elf32_Word; /* Unsigned integer. */ typedef uint64_t Elf32_Lword; /* Unsigned long integer. */ typedef uint64_t Elf64_Addr; /* Program address. */ typedef uint8_t Elf64_Byte; /* Unsigned tiny integer. */ typedef uint16_t Elf64_Half; /* Unsigned medium integer. */ typedef uint64_t Elf64_Off; /* File offset. */ typedef uint16_t Elf64_Section; /* Section index. */ typedef int32_t Elf64_Sword; /* Signed integer. */ typedef uint32_t Elf64_Word; /* Unsigned integer. */ typedef uint64_t Elf64_Lword; /* Unsigned long integer. */ typedef uint64_t Elf64_Xword; /* Unsigned long integer. */ typedef int64_t Elf64_Sxword; /* Signed long integer. */ /* * Capability descriptors. */ /* 32-bit capability descriptor. */ typedef struct { Elf32_Word c_tag; /* Type of entry. */ union { Elf32_Word c_val; /* Integer value. */ Elf32_Addr c_ptr; /* Pointer value. */ } c_un; } Elf32_Cap; /* 64-bit capability descriptor. */ typedef struct { Elf64_Xword c_tag; /* Type of entry. */ union { Elf64_Xword c_val; /* Integer value. */ Elf64_Addr c_ptr; /* Pointer value. */ } c_un; } Elf64_Cap; /* * MIPS .conflict section entries. */ /* 32-bit entry. */ typedef struct { Elf32_Addr c_index; } Elf32_Conflict; /* 64-bit entry. */ typedef struct { Elf64_Addr c_index; } Elf64_Conflict; /* * Dynamic section entries. */ /* 32-bit entry. */ typedef struct { Elf32_Sword d_tag; /* Type of entry. */ union { Elf32_Word d_val; /* Integer value. */ Elf32_Addr d_ptr; /* Pointer value. */ } d_un; } Elf32_Dyn; /* 64-bit entry. */ typedef struct { Elf64_Sxword d_tag; /* Type of entry. */ union { Elf64_Xword d_val; /* Integer value. */ Elf64_Addr d_ptr; /* Pointer value; */ } d_un; } Elf64_Dyn; /* * The executable header (EHDR). */ /* 32 bit EHDR. */ typedef struct { unsigned char e_ident[EI_NIDENT]; /* ELF identification. */ Elf32_Half e_type; /* Object file type (ET_*). */ Elf32_Half e_machine; /* Machine type (EM_*). */ Elf32_Word e_version; /* File format version (EV_*). */ Elf32_Addr e_entry; /* Start address. */ Elf32_Off e_phoff; /* File offset to the PHDR table. */ Elf32_Off e_shoff; /* File offset to the SHDRheader. */ Elf32_Word e_flags; /* Flags (EF_*). */ Elf32_Half e_ehsize; /* Elf header size in bytes. */ Elf32_Half e_phentsize; /* PHDR table entry size in bytes. */ Elf32_Half e_phnum; /* Number of PHDR entries. */ Elf32_Half e_shentsize; /* SHDR table entry size in bytes. */ Elf32_Half e_shnum; /* Number of SHDR entries. */ Elf32_Half e_shstrndx; /* Index of section name string table. */ } Elf32_Ehdr; /* 64 bit EHDR. */ typedef struct { unsigned char e_ident[EI_NIDENT]; /* ELF identification. */ Elf64_Half e_type; /* Object file type (ET_*). */ Elf64_Half e_machine; /* Machine type (EM_*). */ Elf64_Word e_version; /* File format version (EV_*). */ Elf64_Addr e_entry; /* Start address. */ Elf64_Off e_phoff; /* File offset to the PHDR table. */ Elf64_Off e_shoff; /* File offset to the SHDRheader. */ Elf64_Word e_flags; /* Flags (EF_*). */ Elf64_Half e_ehsize; /* Elf header size in bytes. */ Elf64_Half e_phentsize; /* PHDR table entry size in bytes. */ Elf64_Half e_phnum; /* Number of PHDR entries. */ Elf64_Half e_shentsize; /* SHDR table entry size in bytes. */ Elf64_Half e_shnum; /* Number of SHDR entries. */ Elf64_Half e_shstrndx; /* Index of section name string table. */ } Elf64_Ehdr; /* * Shared object information. */ /* 32-bit entry. */ typedef struct { Elf32_Word l_name; /* The name of a shared object. */ Elf32_Word l_time_stamp; /* 32-bit timestamp. */ Elf32_Word l_checksum; /* Checksum of visible symbols, sizes. */ Elf32_Word l_version; /* Interface version string index. */ Elf32_Word l_flags; /* Flags (LL_*). */ } Elf32_Lib; /* 64-bit entry. */ typedef struct { Elf64_Word l_name; /* The name of a shared object. */ Elf64_Word l_time_stamp; /* 32-bit timestamp. */ Elf64_Word l_checksum; /* Checksum of visible symbols, sizes. */ Elf64_Word l_version; /* Interface version string index. */ Elf64_Word l_flags; /* Flags (LL_*). */ } Elf64_Lib; #define _ELF_DEFINE_LL_FLAGS() \ _ELF_DEFINE_LL(LL_NONE, 0, \ "no flags") \ _ELF_DEFINE_LL(LL_EXACT_MATCH, 0x1, \ "require an exact match") \ _ELF_DEFINE_LL(LL_IGNORE_INT_VER, 0x2, \ "ignore version incompatibilities") \ _ELF_DEFINE_LL(LL_REQUIRE_MINOR, 0x4, \ "") \ _ELF_DEFINE_LL(LL_EXPORTS, 0x8, \ "") \ _ELF_DEFINE_LL(LL_DELAY_LOAD, 0x10, \ "") \ _ELF_DEFINE_LL(LL_DELTA, 0x20, \ "") #undef _ELF_DEFINE_LL #define _ELF_DEFINE_LL(N, V, DESCR) N = V , enum { _ELF_DEFINE_LL_FLAGS() LL__LAST__ }; /* * Note tags */ #define _ELF_DEFINE_NOTE_ENTRY_TYPES() \ _ELF_DEFINE_NT(NT_ABI_TAG, 1, "Tag indicating the ABI") \ _ELF_DEFINE_NT(NT_GNU_HWCAP, 2, "Hardware capabilities") \ _ELF_DEFINE_NT(NT_GNU_BUILD_ID, 3, "Build id, set by ld(1)") \ _ELF_DEFINE_NT(NT_GNU_GOLD_VERSION, 4, \ "Version number of the GNU gold linker") \ _ELF_DEFINE_NT(NT_PRSTATUS, 1, "Process status") \ _ELF_DEFINE_NT(NT_FPREGSET, 2, "Floating point information") \ _ELF_DEFINE_NT(NT_PRPSINFO, 3, "Process information") \ _ELF_DEFINE_NT(NT_AUXV, 6, "Auxiliary vector") \ _ELF_DEFINE_NT(NT_PRXFPREG, 0x46E62B7FUL, \ "Linux user_xfpregs structure") \ _ELF_DEFINE_NT(NT_PSTATUS, 10, "Linux process status") \ _ELF_DEFINE_NT(NT_FPREGS, 12, "Linux floating point regset") \ _ELF_DEFINE_NT(NT_PSINFO, 13, "Linux process information") \ _ELF_DEFINE_NT(NT_LWPSTATUS, 16, "Linux lwpstatus_t type") \ _ELF_DEFINE_NT(NT_LWPSINFO, 17, "Linux lwpinfo_t type") #undef _ELF_DEFINE_NT #define _ELF_DEFINE_NT(N, V, DESCR) N = V , enum { _ELF_DEFINE_NOTE_ENTRY_TYPES() NT__LAST__ }; /* Aliases for the ABI tag. */ #define NT_FREEBSD_ABI_TAG NT_ABI_TAG #define NT_GNU_ABI_TAG NT_ABI_TAG #define NT_NETBSD_IDENT NT_ABI_TAG #define NT_OPENBSD_IDENT NT_ABI_TAG /* * Note descriptors. */ typedef struct { uint32_t n_namesz; /* Length of note's name. */ uint32_t n_descsz; /* Length of note's value. */ uint32_t n_type; /* Type of note. */ } Elf_Note; typedef Elf_Note Elf32_Nhdr; /* 32-bit note header. */ typedef Elf_Note Elf64_Nhdr; /* 64-bit note header. */ /* * MIPS ELF options descriptor header. */ typedef struct { Elf64_Byte kind; /* Type of options. */ Elf64_Byte size; /* Size of option descriptor. */ Elf64_Half section; /* Index of section affected. */ Elf64_Word info; /* Kind-specific information. */ } Elf_Options; /* * Option kinds. */ #define _ELF_DEFINE_OPTION_KINDS() \ _ELF_DEFINE_ODK(ODK_NULL, 0, "undefined") \ _ELF_DEFINE_ODK(ODK_REGINFO, 1, "register usage info") \ _ELF_DEFINE_ODK(ODK_EXCEPTIONS, 2, "exception processing info") \ _ELF_DEFINE_ODK(ODK_PAD, 3, "section padding") \ _ELF_DEFINE_ODK(ODK_HWPATCH, 4, "hardware patch applied") \ _ELF_DEFINE_ODK(ODK_FILL, 5, "fill value used by linker") \ _ELF_DEFINE_ODK(ODK_TAGS, 6, "reserved space for tools") \ _ELF_DEFINE_ODK(ODK_HWAND, 7, "hardware AND patch applied") \ _ELF_DEFINE_ODK(ODK_HWOR, 8, "hardware OR patch applied") \ _ELF_DEFINE_ODK(ODK_GP_GROUP, 9, \ "GP group to use for text/data sections") \ _ELF_DEFINE_ODK(ODK_IDENT, 10, "ID information") \ _ELF_DEFINE_ODK(ODK_PAGESIZE, 11, "page size information") #undef _ELF_DEFINE_ODK #define _ELF_DEFINE_ODK(N, V, DESCR) N = V , enum { _ELF_DEFINE_OPTION_KINDS() ODK__LAST__ }; /* * ODK_EXCEPTIONS info field masks. */ #define _ELF_DEFINE_ODK_EXCEPTIONS_MASK() \ _ELF_DEFINE_OEX(OEX_FPU_MIN, 0x0000001FUL, \ "minimum FPU exception which must be enabled") \ _ELF_DEFINE_OEX(OEX_FPU_MAX, 0x00001F00UL, \ "maximum FPU exception which can be enabled") \ _ELF_DEFINE_OEX(OEX_PAGE0, 0x00010000UL, \ "page zero must be mapped") \ _ELF_DEFINE_OEX(OEX_SMM, 0x00020000UL, \ "run in sequential memory mode") \ _ELF_DEFINE_OEX(OEX_PRECISEFP, 0x00040000UL, \ "run in precise FP exception mode") \ _ELF_DEFINE_OEX(OEX_DISMISS, 0x00080000UL, \ "dismiss invalid address traps") #undef _ELF_DEFINE_OEX #define _ELF_DEFINE_OEX(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_EXCEPTIONS_MASK() OEX__LAST__ }; /* * ODK_PAD info field masks. */ #define _ELF_DEFINE_ODK_PAD_MASK() \ _ELF_DEFINE_OPAD(OPAD_PREFIX, 0x0001) \ _ELF_DEFINE_OPAD(OPAD_POSTFIX, 0x0002) \ _ELF_DEFINE_OPAD(OPAD_SYMBOL, 0x0004) #undef _ELF_DEFINE_OPAD #define _ELF_DEFINE_OPAD(N, V) N = V , enum { _ELF_DEFINE_ODK_PAD_MASK() OPAD__LAST__ }; /* * ODK_HWPATCH info field masks. */ #define _ELF_DEFINE_ODK_HWPATCH_MASK() \ _ELF_DEFINE_OHW(OHW_R4KEOP, 0x00000001UL, \ "patch for R4000 branch at end-of-page bug") \ _ELF_DEFINE_OHW(OHW_R8KPFETCH, 0x00000002UL, \ "R8000 prefetch bug may occur") \ _ELF_DEFINE_OHW(OHW_R5KEOP, 0x00000004UL, \ "patch for R5000 branch at end-of-page bug") \ _ELF_DEFINE_OHW(OHW_R5KCVTL, 0x00000008UL, \ "R5000 cvt.[ds].l bug: clean == 1") \ _ELF_DEFINE_OHW(OHW_R10KLDL, 0x00000010UL, \ "needd patch for R10000 misaligned load") #undef _ELF_DEFINE_OHW #define _ELF_DEFINE_OHW(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_HWPATCH_MASK() OHW__LAST__ }; /* * ODK_HWAND/ODK_HWOR info field and hwp_flags[12] masks. */ #define _ELF_DEFINE_ODK_HWP_MASK() \ _ELF_DEFINE_HWP(OHWA0_R4KEOP_CHECKED, 0x00000001UL, \ "object checked for R4000 end-of-page bug") \ _ELF_DEFINE_HWP(OHWA0_R4KEOP_CLEAN, 0x00000002UL, \ "object verified clean for R4000 end-of-page bug") \ _ELF_DEFINE_HWP(OHWO0_FIXADE, 0x00000001UL, \ "object requires call to fixade") #undef _ELF_DEFINE_HWP #define _ELF_DEFINE_HWP(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_HWP_MASK() OHWX0__LAST__ }; /* * ODK_IDENT/ODK_GP_GROUP info field masks. */ #define _ELF_DEFINE_ODK_GP_MASK() \ _ELF_DEFINE_OGP(OGP_GROUP, 0x0000FFFFUL, "GP group number") \ _ELF_DEFINE_OGP(OGP_SELF, 0x00010000UL, \ "GP group is self-contained") #undef _ELF_DEFINE_OGP #define _ELF_DEFINE_OGP(N, V, DESCR) N = V , enum { _ELF_DEFINE_ODK_GP_MASK() OGP__LAST__ }; /* * MIPS ELF register info descriptor. */ /* 32 bit RegInfo entry. */ typedef struct { Elf32_Word ri_gprmask; /* Mask of general register used. */ Elf32_Word ri_cprmask[4]; /* Mask of coprocessor register used. */ Elf32_Addr ri_gp_value; /* GP register value. */ } Elf32_RegInfo; /* 64 bit RegInfo entry. */ typedef struct { Elf64_Word ri_gprmask; /* Mask of general register used. */ Elf64_Word ri_pad; /* Padding. */ Elf64_Word ri_cprmask[4]; /* Mask of coprocessor register used. */ Elf64_Addr ri_gp_value; /* GP register value. */ } Elf64_RegInfo; /* * Program Header Table (PHDR) entries. */ /* 32 bit PHDR entry. */ typedef struct { Elf32_Word p_type; /* Type of segment. */ Elf32_Off p_offset; /* File offset to segment. */ Elf32_Addr p_vaddr; /* Virtual address in memory. */ Elf32_Addr p_paddr; /* Physical address (if relevant). */ Elf32_Word p_filesz; /* Size of segment in file. */ Elf32_Word p_memsz; /* Size of segment in memory. */ Elf32_Word p_flags; /* Segment flags. */ Elf32_Word p_align; /* Alignment constraints. */ } Elf32_Phdr; /* 64 bit PHDR entry. */ typedef struct { Elf64_Word p_type; /* Type of segment. */ Elf64_Word p_flags; /* Segment flags. */ Elf64_Off p_offset; /* File offset to segment. */ Elf64_Addr p_vaddr; /* Virtual address in memory. */ Elf64_Addr p_paddr; /* Physical address (if relevant). */ Elf64_Xword p_filesz; /* Size of segment in file. */ Elf64_Xword p_memsz; /* Size of segment in memory. */ Elf64_Xword p_align; /* Alignment constraints. */ } Elf64_Phdr; /* * Move entries, for describing data in COMMON blocks in a compact * manner. */ /* 32-bit move entry. */ typedef struct { Elf32_Lword m_value; /* Initialization value. */ Elf32_Word m_info; /* Encoded size and index. */ Elf32_Word m_poffset; /* Offset relative to symbol. */ Elf32_Half m_repeat; /* Repeat count. */ Elf32_Half m_stride; /* Number of units to skip. */ } Elf32_Move; /* 64-bit move entry. */ typedef struct { Elf64_Lword m_value; /* Initialization value. */ Elf64_Xword m_info; /* Encoded size and index. */ Elf64_Xword m_poffset; /* Offset relative to symbol. */ Elf64_Half m_repeat; /* Repeat count. */ Elf64_Half m_stride; /* Number of units to skip. */ } Elf64_Move; #define ELF32_M_SYM(I) ((I) >> 8) #define ELF32_M_SIZE(I) ((unsigned char) (I)) #define ELF32_M_INFO(M, S) (((M) << 8) + (unsigned char) (S)) #define ELF64_M_SYM(I) ((I) >> 8) #define ELF64_M_SIZE(I) ((unsigned char) (I)) #define ELF64_M_INFO(M, S) (((M) << 8) + (unsigned char) (S)) /* * Section Header Table (SHDR) entries. */ /* 32 bit SHDR */ typedef struct { Elf32_Word sh_name; /* index of section name */ Elf32_Word sh_type; /* section type */ Elf32_Word sh_flags; /* section flags */ Elf32_Addr sh_addr; /* in-memory address of section */ Elf32_Off sh_offset; /* file offset of section */ Elf32_Word sh_size; /* section size in bytes */ Elf32_Word sh_link; /* section header table link */ Elf32_Word sh_info; /* extra information */ Elf32_Word sh_addralign; /* alignment constraint */ Elf32_Word sh_entsize; /* size for fixed-size entries */ } Elf32_Shdr; /* 64 bit SHDR */ typedef struct { Elf64_Word sh_name; /* index of section name */ Elf64_Word sh_type; /* section type */ Elf64_Xword sh_flags; /* section flags */ Elf64_Addr sh_addr; /* in-memory address of section */ Elf64_Off sh_offset; /* file offset of section */ Elf64_Xword sh_size; /* section size in bytes */ Elf64_Word sh_link; /* section header table link */ Elf64_Word sh_info; /* extra information */ Elf64_Xword sh_addralign; /* alignment constraint */ Elf64_Xword sh_entsize; /* size for fixed-size entries */ } Elf64_Shdr; /* * Symbol table entries. */ typedef struct { Elf32_Word st_name; /* index of symbol's name */ Elf32_Addr st_value; /* value for the symbol */ Elf32_Word st_size; /* size of associated data */ unsigned char st_info; /* type and binding attributes */ unsigned char st_other; /* visibility */ Elf32_Half st_shndx; /* index of related section */ } Elf32_Sym; typedef struct { Elf64_Word st_name; /* index of symbol's name */ unsigned char st_info; /* type and binding attributes */ unsigned char st_other; /* visibility */ Elf64_Half st_shndx; /* index of related section */ Elf64_Addr st_value; /* value for the symbol */ Elf64_Xword st_size; /* size of associated data */ } Elf64_Sym; #define ELF32_ST_BIND(I) ((I) >> 4) #define ELF32_ST_TYPE(I) ((I) & 0xFU) #define ELF32_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF)) #define ELF64_ST_BIND(I) ((I) >> 4) #define ELF64_ST_TYPE(I) ((I) & 0xFU) #define ELF64_ST_INFO(B,T) (((B) << 4) + ((T) & 0xF)) #define ELF32_ST_VISIBILITY(O) ((O) & 0x3) #define ELF64_ST_VISIBILITY(O) ((O) & 0x3) /* * Syminfo descriptors, containing additional symbol information. */ /* 32-bit entry. */ typedef struct { Elf32_Half si_boundto; /* Entry index with additional flags. */ Elf32_Half si_flags; /* Flags. */ } Elf32_Syminfo; /* 64-bit entry. */ typedef struct { Elf64_Half si_boundto; /* Entry index with additional flags. */ Elf64_Half si_flags; /* Flags. */ } Elf64_Syminfo; /* * Relocation descriptors. */ typedef struct { Elf32_Addr r_offset; /* location to apply relocation to */ Elf32_Word r_info; /* type+section for relocation */ } Elf32_Rel; typedef struct { Elf32_Addr r_offset; /* location to apply relocation to */ Elf32_Word r_info; /* type+section for relocation */ Elf32_Sword r_addend; /* constant addend */ } Elf32_Rela; typedef struct { Elf64_Addr r_offset; /* location to apply relocation to */ Elf64_Xword r_info; /* type+section for relocation */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset; /* location to apply relocation to */ Elf64_Xword r_info; /* type+section for relocation */ Elf64_Sxword r_addend; /* constant addend */ } Elf64_Rela; #define ELF32_R_SYM(I) ((I) >> 8) #define ELF32_R_TYPE(I) ((unsigned char) (I)) #define ELF32_R_INFO(S,T) (((S) << 8) + (unsigned char) (T)) #define ELF64_R_SYM(I) ((I) >> 32) #define ELF64_R_TYPE(I) ((I) & 0xFFFFFFFFUL) #define ELF64_R_INFO(S,T) (((S) << 32) + ((T) & 0xFFFFFFFFUL)) /* * Symbol versioning structures. */ /* 32-bit structures. */ typedef struct { Elf32_Word vda_name; /* Index to name. */ Elf32_Word vda_next; /* Offset to next entry. */ } Elf32_Verdaux; typedef struct { Elf32_Word vna_hash; /* Hash value of dependency name. */ Elf32_Half vna_flags; /* Flags. */ Elf32_Half vna_other; /* Unused. */ Elf32_Word vna_name; /* Offset to dependency name. */ Elf32_Word vna_next; /* Offset to next vernaux entry. */ } Elf32_Vernaux; typedef struct { Elf32_Half vd_version; /* Version information. */ Elf32_Half vd_flags; /* Flags. */ Elf32_Half vd_ndx; /* Index into the versym section. */ Elf32_Half vd_cnt; /* Number of aux entries. */ Elf32_Word vd_hash; /* Hash value of name. */ Elf32_Word vd_aux; /* Offset to aux entries. */ Elf32_Word vd_next; /* Offset to next version definition. */ } Elf32_Verdef; typedef struct { Elf32_Half vn_version; /* Version number. */ Elf32_Half vn_cnt; /* Number of aux entries. */ Elf32_Word vn_file; /* Offset of associated file name. */ Elf32_Word vn_aux; /* Offset of vernaux array. */ Elf32_Word vn_next; /* Offset of next verneed entry. */ } Elf32_Verneed; typedef Elf32_Half Elf32_Versym; /* 64-bit structures. */ typedef struct { Elf64_Word vda_name; /* Index to name. */ Elf64_Word vda_next; /* Offset to next entry. */ } Elf64_Verdaux; typedef struct { Elf64_Word vna_hash; /* Hash value of dependency name. */ Elf64_Half vna_flags; /* Flags. */ Elf64_Half vna_other; /* Unused. */ Elf64_Word vna_name; /* Offset to dependency name. */ Elf64_Word vna_next; /* Offset to next vernaux entry. */ } Elf64_Vernaux; typedef struct { Elf64_Half vd_version; /* Version information. */ Elf64_Half vd_flags; /* Flags. */ Elf64_Half vd_ndx; /* Index into the versym section. */ Elf64_Half vd_cnt; /* Number of aux entries. */ Elf64_Word vd_hash; /* Hash value of name. */ Elf64_Word vd_aux; /* Offset to aux entries. */ Elf64_Word vd_next; /* Offset to next version definition. */ } Elf64_Verdef; typedef struct { Elf64_Half vn_version; /* Version number. */ Elf64_Half vn_cnt; /* Number of aux entries. */ Elf64_Word vn_file; /* Offset of associated file name. */ Elf64_Word vn_aux; /* Offset of vernaux array. */ Elf64_Word vn_next; /* Offset of next verneed entry. */ } Elf64_Verneed; typedef Elf64_Half Elf64_Versym; /* * The header for GNU-style hash sections. */ typedef struct { uint32_t gh_nbuckets; /* Number of hash buckets. */ uint32_t gh_symndx; /* First visible symbol in .dynsym. */ uint32_t gh_maskwords; /* #maskwords used in bloom filter. */ uint32_t gh_shift2; /* Bloom filter shift count. */ } Elf_GNU_Hash_Header; #endif /* _ELFDEFINITIONS_H_ */ Index: vendor/elftoolchain/dist/cxxfilt/cxxfilt.c =================================================================== --- vendor/elftoolchain/dist/cxxfilt/cxxfilt.c (revision 317072) +++ vendor/elftoolchain/dist/cxxfilt/cxxfilt.c (revision 317073) @@ -1,202 +1,203 @@ /*- * Copyright (c) 2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: cxxfilt.c 3454 2016-05-07 17:11:05Z kaiwang27 $"); +ELFTC_VCSID("$Id: cxxfilt.c 3499 2016-11-25 16:06:29Z emaste $"); #define STRBUFSZ 8192 static int stripus = 0; static int noparam = 0; static int format = 0; enum options { OPTION_HELP, OPTION_VERSION }; static struct option longopts[] = { {"format", required_argument, NULL, 's'}, {"help", no_argument, NULL, OPTION_HELP}, {"no-params", no_argument, NULL, 'p'}, {"no-strip-underscores", no_argument, NULL, 'n'}, {"strip-underscores", no_argument, NULL, '_'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; static struct { const char *fname; int fvalue; } flist[] = { {"auto", 0}, {"arm", ELFTC_DEM_ARM}, {"gnu", ELFTC_DEM_GNU2}, {"gnu-v3", ELFTC_DEM_GNU3} }; #define USAGE_MESSAGE "\ Usage: %s [options] [encoded-names...]\n\ Translate C++ symbol names to human-readable form.\n\n\ Options:\n\ -_ | --strip-underscores Remove leading underscores prior to decoding.\n\ -n | --no-strip-underscores Do not remove leading underscores.\n\ -p | --no-params (Accepted but ignored).\n\ -s SCHEME | --format=SCHEME Select the encoding scheme to use.\n\ Valid schemes are: 'arm', 'auto', 'gnu' and\n\ 'gnu-v3'.\n\ --help Print a help message.\n\ --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); } static int find_format(const char *fstr) { int i; for (i = 0; (size_t) i < sizeof(flist) / sizeof(flist[0]); i++) { if (!strcmp(fstr, flist[i].fname)) return (flist[i].fvalue); } return (-1); } static char * demangle(char *name) { static char dem[STRBUFSZ]; if (stripus && *name == '_') name++; if (strlen(name) == 0) return (NULL); if (elftc_demangle(name, dem, sizeof(dem), (unsigned) format) < 0) return (NULL); return (dem); } int main(int argc, char **argv) { char *dem, buf[STRBUFSZ]; size_t p; int c, n, opt; while ((opt = getopt_long(argc, argv, "_nps:V", longopts, NULL)) != -1) { switch (opt) { case '_': stripus = 1; break; case 'n': stripus = 0; break; case 'p': noparam = 1; break; case 's': if ((format = find_format(optarg)) < 0) errx(EXIT_FAILURE, "unsupported format: %s", optarg); break; case 'V': version(); /* NOT REACHED */ case OPTION_HELP: default: usage(); /* NOT REACHED */ } } argv += optind; argc -= optind; if (*argv != NULL) { for (n = 0; n < argc; n++) { if ((dem = demangle(argv[n])) == NULL) printf("%s\n", argv[n]); else printf("%s\n", dem); } } else { p = 0; for (;;) { + setvbuf(stdout, NULL, _IOLBF, 0); c = fgetc(stdin); if (c == EOF || !(isalnum(c) || strchr(".$_", c))) { if (p > 0) { buf[p] = '\0'; if ((dem = demangle(buf)) == NULL) printf("%s", buf); else printf("%s", dem); p = 0; } if (c == EOF) break; putchar(c); } else { if ((size_t) p >= sizeof(buf) - 1) warnx("buffer overflowed"); else buf[p++] = (char) c; } } } exit(0); } Index: vendor/elftoolchain/dist/elfcopy/main.c =================================================================== --- vendor/elftoolchain/dist/elfcopy/main.c (revision 317072) +++ vendor/elftoolchain/dist/elfcopy/main.c (revision 317073) @@ -1,1577 +1,1582 @@ /*- * Copyright (c) 2007-2013 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: main.c 3446 2016-05-03 01:31:17Z emaste $"); +ELFTC_VCSID("$Id: main.c 3520 2017-04-17 01:47:52Z kaiwang27 $"); enum options { ECP_ADD_GNU_DEBUGLINK, ECP_ADD_SECTION, ECP_CHANGE_ADDR, ECP_CHANGE_SEC_ADDR, ECP_CHANGE_SEC_LMA, ECP_CHANGE_SEC_VMA, ECP_CHANGE_START, ECP_CHANGE_WARN, ECP_GAP_FILL, ECP_GLOBALIZE_SYMBOL, ECP_GLOBALIZE_SYMBOLS, ECP_KEEP_SYMBOLS, ECP_KEEP_GLOBAL_SYMBOLS, ECP_LOCALIZE_HIDDEN, ECP_LOCALIZE_SYMBOLS, ECP_NO_CHANGE_WARN, ECP_ONLY_DEBUG, ECP_ONLY_DWO, ECP_PAD_TO, ECP_PREFIX_ALLOC, ECP_PREFIX_SEC, ECP_PREFIX_SYM, ECP_REDEF_SYMBOL, ECP_REDEF_SYMBOLS, ECP_RENAME_SECTION, ECP_SET_OSABI, ECP_SET_SEC_FLAGS, ECP_SET_START, ECP_SREC_FORCE_S3, ECP_SREC_LEN, ECP_STRIP_DWO, ECP_STRIP_SYMBOLS, ECP_STRIP_UNNEEDED, ECP_WEAKEN_ALL, ECP_WEAKEN_SYMBOLS }; static struct option mcs_longopts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; static struct option strip_longopts[] = { {"discard-all", no_argument, NULL, 'x'}, {"discard-locals", no_argument, NULL, 'X'}, {"help", no_argument, NULL, 'h'}, {"input-target", required_argument, NULL, 'I'}, {"keep-symbol", required_argument, NULL, 'K'}, {"only-keep-debug", no_argument, NULL, ECP_ONLY_DEBUG}, {"output-file", required_argument, NULL, 'o'}, {"output-target", required_argument, NULL, 'O'}, {"preserve-dates", no_argument, NULL, 'p'}, {"remove-section", required_argument, NULL, 'R'}, {"strip-all", no_argument, NULL, 's'}, {"strip-debug", no_argument, NULL, 'S'}, {"strip-symbol", required_argument, NULL, 'N'}, {"strip-unneeded", no_argument, NULL, ECP_STRIP_UNNEEDED}, {"version", no_argument, NULL, 'V'}, {"wildcard", no_argument, NULL, 'w'}, {NULL, 0, NULL, 0} }; static struct option elfcopy_longopts[] = { {"add-gnu-debuglink", required_argument, NULL, ECP_ADD_GNU_DEBUGLINK}, {"add-section", required_argument, NULL, ECP_ADD_SECTION}, {"adjust-section-vma", required_argument, NULL, ECP_CHANGE_SEC_ADDR}, {"adjust-vma", required_argument, NULL, ECP_CHANGE_ADDR}, {"adjust-start", required_argument, NULL, ECP_CHANGE_START}, {"adjust-warnings", no_argument, NULL, ECP_CHANGE_WARN}, {"binary-architecture", required_argument, NULL, 'B'}, {"change-addresses", required_argument, NULL, ECP_CHANGE_ADDR}, {"change-section-address", required_argument, NULL, ECP_CHANGE_SEC_ADDR}, {"change-section-lma", required_argument, NULL, ECP_CHANGE_SEC_LMA}, {"change-section-vma", required_argument, NULL, ECP_CHANGE_SEC_VMA}, {"change-start", required_argument, NULL, ECP_CHANGE_START}, {"change-warnings", no_argument, NULL, ECP_CHANGE_WARN}, {"discard-all", no_argument, NULL, 'x'}, {"discard-locals", no_argument, NULL, 'X'}, {"extract-dwo", no_argument, NULL, ECP_ONLY_DWO}, {"gap-fill", required_argument, NULL, ECP_GAP_FILL}, {"globalize-symbol", required_argument, NULL, ECP_GLOBALIZE_SYMBOL}, {"globalize-symbols", required_argument, NULL, ECP_GLOBALIZE_SYMBOLS}, {"help", no_argument, NULL, 'h'}, {"input-target", required_argument, NULL, 'I'}, {"keep-symbol", required_argument, NULL, 'K'}, {"keep-symbols", required_argument, NULL, ECP_KEEP_SYMBOLS}, {"keep-global-symbol", required_argument, NULL, 'G'}, {"keep-global-symbols", required_argument, NULL, ECP_KEEP_GLOBAL_SYMBOLS}, {"localize-hidden", no_argument, NULL, ECP_LOCALIZE_HIDDEN}, {"localize-symbol", required_argument, NULL, 'L'}, {"localize-symbols", required_argument, NULL, ECP_LOCALIZE_SYMBOLS}, {"no-adjust-warnings", no_argument, NULL, ECP_NO_CHANGE_WARN}, {"no-change-warnings", no_argument, NULL, ECP_NO_CHANGE_WARN}, {"only-keep-debug", no_argument, NULL, ECP_ONLY_DEBUG}, {"only-section", required_argument, NULL, 'j'}, {"osabi", required_argument, NULL, ECP_SET_OSABI}, {"output-target", required_argument, NULL, 'O'}, {"pad-to", required_argument, NULL, ECP_PAD_TO}, {"preserve-dates", no_argument, NULL, 'p'}, {"prefix-alloc-sections", required_argument, NULL, ECP_PREFIX_ALLOC}, {"prefix-sections", required_argument, NULL, ECP_PREFIX_SEC}, {"prefix-symbols", required_argument, NULL, ECP_PREFIX_SYM}, {"redefine-sym", required_argument, NULL, ECP_REDEF_SYMBOL}, {"redefine-syms", required_argument, NULL, ECP_REDEF_SYMBOLS}, {"remove-section", required_argument, NULL, 'R'}, {"rename-section", required_argument, NULL, ECP_RENAME_SECTION}, {"set-section-flags", required_argument, NULL, ECP_SET_SEC_FLAGS}, {"set-start", required_argument, NULL, ECP_SET_START}, {"srec-forceS3", no_argument, NULL, ECP_SREC_FORCE_S3}, {"srec-len", required_argument, NULL, ECP_SREC_LEN}, {"strip-all", no_argument, NULL, 'S'}, {"strip-debug", no_argument, 0, 'g'}, {"strip-dwo", no_argument, NULL, ECP_STRIP_DWO}, {"strip-symbol", required_argument, NULL, 'N'}, {"strip-symbols", required_argument, NULL, ECP_STRIP_SYMBOLS}, {"strip-unneeded", no_argument, NULL, ECP_STRIP_UNNEEDED}, {"version", no_argument, NULL, 'V'}, {"weaken", no_argument, NULL, ECP_WEAKEN_ALL}, {"weaken-symbol", required_argument, NULL, 'W'}, {"weaken-symbols", required_argument, NULL, ECP_WEAKEN_SYMBOLS}, {"wildcard", no_argument, NULL, 'w'}, {NULL, 0, NULL, 0} }; static struct { const char *name; int value; } sec_flags[] = { {"alloc", SF_ALLOC}, {"load", SF_LOAD}, {"noload", SF_NOLOAD}, {"readonly", SF_READONLY}, {"debug", SF_DEBUG}, {"code", SF_CODE}, {"data", SF_DATA}, {"rom", SF_ROM}, {"share", SF_SHARED}, {"contents", SF_CONTENTS}, {NULL, 0} }; static struct { const char *name; int abi; } osabis[] = { {"sysv", ELFOSABI_SYSV}, {"hpus", ELFOSABI_HPUX}, {"netbsd", ELFOSABI_NETBSD}, {"linux", ELFOSABI_LINUX}, {"hurd", ELFOSABI_HURD}, {"86open", ELFOSABI_86OPEN}, {"solaris", ELFOSABI_SOLARIS}, {"aix", ELFOSABI_AIX}, {"irix", ELFOSABI_IRIX}, {"freebsd", ELFOSABI_FREEBSD}, {"tru64", ELFOSABI_TRU64}, {"modesto", ELFOSABI_MODESTO}, {"openbsd", ELFOSABI_OPENBSD}, {"openvms", ELFOSABI_OPENVMS}, {"nsk", ELFOSABI_NSK}, {"cloudabi", ELFOSABI_CLOUDABI}, {"arm", ELFOSABI_ARM}, {"standalone", ELFOSABI_STANDALONE}, {NULL, 0} }; static int copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd, int in_place); static void create_file(struct elfcopy *ecp, const char *src, const char *dst); static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv); static void elfcopy_usage(void); static void mcs_main(struct elfcopy *ecp, int argc, char **argv); static void mcs_usage(void); static void parse_sec_address_op(struct elfcopy *ecp, int optnum, const char *optname, char *s); static void parse_sec_flags(struct sec_action *sac, char *s); static void parse_symlist_file(struct elfcopy *ecp, const char *fn, unsigned int op); static void print_version(void); static void set_input_target(struct elfcopy *ecp, const char *target_name); static void set_osabi(struct elfcopy *ecp, const char *abi); static void set_output_target(struct elfcopy *ecp, const char *target_name); static void strip_main(struct elfcopy *ecp, int argc, char **argv); static void strip_usage(void); /* * An ELF object usually has a structure described by the * diagram below. * _____________ * | | * | NULL | <- always a SHT_NULL section * |_____________| * | | * | .interp | * |_____________| * | | * | ... | * |_____________| * | | * | .text | * |_____________| * | | * | ... | * |_____________| * | | * | .comment | <- above(include) this: normal sections * |_____________| * | | * | add sections| <- unloadable sections added by --add-section * |_____________| * | | * | .shstrtab | <- section name string table * |_____________| * | | * | shdrs | <- section header table * |_____________| * | | * | .symtab | <- symbol table, if any * |_____________| * | | * | .strtab | <- symbol name string table, if any * |_____________| * | | * | .rel.text | <- relocation info for .o files. * |_____________| */ void create_elf(struct elfcopy *ecp) { struct section *shtab; GElf_Ehdr ieh; GElf_Ehdr oeh; size_t ishnum; ecp->flags |= SYMTAB_INTACT; + ecp->flags &= ~SYMTAB_EXIST; /* Create EHDR. */ if (gelf_getehdr(ecp->ein, &ieh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); if ((ecp->iec = gelf_getclass(ecp->ein)) == ELFCLASSNONE) errx(EXIT_FAILURE, "getclass() failed: %s", elf_errmsg(-1)); if (ecp->oec == ELFCLASSNONE) ecp->oec = ecp->iec; if (ecp->oed == ELFDATANONE) ecp->oed = ieh.e_ident[EI_DATA]; if (gelf_newehdr(ecp->eout, ecp->oec) == NULL) errx(EXIT_FAILURE, "gelf_newehdr failed: %s", elf_errmsg(-1)); if (gelf_getehdr(ecp->eout, &oeh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); memcpy(oeh.e_ident, ieh.e_ident, sizeof(ieh.e_ident)); oeh.e_ident[EI_CLASS] = ecp->oec; oeh.e_ident[EI_DATA] = ecp->oed; if (ecp->abi != -1) oeh.e_ident[EI_OSABI] = ecp->abi; oeh.e_flags = ieh.e_flags; oeh.e_machine = ieh.e_machine; oeh.e_type = ieh.e_type; oeh.e_entry = ieh.e_entry; oeh.e_version = ieh.e_version; ecp->flags &= ~(EXECUTABLE | DYNAMIC | RELOCATABLE); if (ieh.e_type == ET_EXEC) ecp->flags |= EXECUTABLE; else if (ieh.e_type == ET_DYN) ecp->flags |= DYNAMIC; else if (ieh.e_type == ET_REL) ecp->flags |= RELOCATABLE; else errx(EXIT_FAILURE, "unsupported e_type"); if (!elf_getshnum(ecp->ein, &ishnum)) errx(EXIT_FAILURE, "elf_getshnum failed: %s", elf_errmsg(-1)); if (ishnum > 0 && (ecp->secndx = calloc(ishnum, sizeof(*ecp->secndx))) == NULL) err(EXIT_FAILURE, "calloc failed"); /* Read input object program header. */ setup_phdr(ecp); /* * Scan of input sections: we iterate through sections from input * object, skip sections need to be stripped, allot Elf_Scn and * create internal section structure for sections we want. * (i.e., determine output sections) */ create_scn(ecp); /* Apply section address changes, if any. */ adjust_addr(ecp); /* * Determine if the symbol table needs to be changed based on * command line options. */ if (ecp->strip == STRIP_DEBUG || ecp->strip == STRIP_UNNEEDED || ecp->flags & WEAKEN_ALL || ecp->flags & LOCALIZE_HIDDEN || ecp->flags & DISCARD_LOCAL || ecp->flags & DISCARD_LLABEL || ecp->prefix_sym != NULL || !STAILQ_EMPTY(&ecp->v_symop)) ecp->flags &= ~SYMTAB_INTACT; /* * Create symbol table. Symbols are filtered or stripped according to * command line args specified by user, and later updated for the new * layout of sections in the output object. */ if ((ecp->flags & SYMTAB_EXIST) != 0) create_symtab(ecp); /* * First processing of output sections: at this stage we copy the * content of each section from input to output object. Section * content will be modified and printed (mcs) if need. Also content of * relocation section probably will be filtered and updated according * to symbol table changes. */ copy_content(ecp); /* * Write the underlying ehdr. Note that it should be called * before elf_setshstrndx() since it will overwrite e->e_shstrndx. */ if (gelf_update_ehdr(ecp->eout, &oeh) == 0) errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", elf_errmsg(-1)); /* Generate section name string table (.shstrtab). */ set_shstrtab(ecp); /* * Second processing of output sections: Update section headers. * At this stage we set name string index, update st_link and st_info * for output sections. */ update_shdr(ecp, 1); /* Renew oeh to get the updated e_shstrndx. */ if (gelf_getehdr(ecp->eout, &oeh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); /* * Insert SHDR table into the internal section list as a "pseudo" * section, so later it will get sorted and resynced just as "normal" * sections. * * Under FreeBSD, Binutils objcopy always put the section header * at the end of all the sections. We want to do the same here. * * However, note that the behaviour is still different with Binutils: * elfcopy checks the FreeBSD OSABI tag to tell whether it needs to * move the section headers, while Binutils is probably configured * this way when it's compiled on FreeBSD. */ if (oeh.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) shtab = insert_shtab(ecp, 1); else shtab = insert_shtab(ecp, 0); /* * Resync section offsets in the output object. This is needed * because probably sections are modified or new sections are added, * as a result overlap/gap might appears. */ resync_sections(ecp); /* Store SHDR offset in EHDR. */ oeh.e_shoff = shtab->off; /* Put program header table immediately after the Elf header. */ if (ecp->ophnum > 0) { oeh.e_phoff = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT); if (oeh.e_phoff == 0) errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); } /* * Update ELF object entry point if requested. */ if (ecp->change_addr != 0) oeh.e_entry += ecp->change_addr; if (ecp->flags & SET_START) oeh.e_entry = ecp->set_start; if (ecp->change_start != 0) oeh.e_entry += ecp->change_start; /* * Update ehdr again before we call elf_update(), since we * modified e_shoff and e_phoff. */ if (gelf_update_ehdr(ecp->eout, &oeh) == 0) errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s", elf_errmsg(-1)); if (ecp->ophnum > 0) copy_phdr(ecp); /* Write out the output elf object. */ if (elf_update(ecp->eout, ELF_C_WRITE) < 0) errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1)); /* Release allocated resource. */ free_elf(ecp); } void free_elf(struct elfcopy *ecp) { struct segment *seg, *seg_temp; struct section *sec, *sec_temp; /* Free internal segment list. */ if (!STAILQ_EMPTY(&ecp->v_seg)) { STAILQ_FOREACH_SAFE(seg, &ecp->v_seg, seg_list, seg_temp) { STAILQ_REMOVE(&ecp->v_seg, seg, segment, seg_list); free(seg); } } /* Free symbol table buffers. */ free_symtab(ecp); /* Free internal section list. */ if (!TAILQ_EMPTY(&ecp->v_sec)) { TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) { TAILQ_REMOVE(&ecp->v_sec, sec, sec_list); if (sec->buf != NULL) free(sec->buf); if (sec->newname != NULL) free(sec->newname); if (sec->pad != NULL) free(sec->pad); free(sec); } } + + ecp->symtab = NULL; + ecp->strtab = NULL; + ecp->shstrtab = NULL; if (ecp->secndx != NULL) { free(ecp->secndx); ecp->secndx = NULL; } } /* Create a temporary file. */ void create_tempfile(char **fn, int *fd) { const char *tmpdir; char *cp, *tmpf; size_t tlen, plen; #define _TEMPFILE "ecp.XXXXXXXX" #define _TEMPFILEPATH "/tmp/ecp.XXXXXXXX" if (fn == NULL || fd == NULL) return; /* Repect TMPDIR environment variable. */ tmpdir = getenv("TMPDIR"); if (tmpdir != NULL && *tmpdir != '\0') { tlen = strlen(tmpdir); plen = strlen(_TEMPFILE); tmpf = malloc(tlen + plen + 2); if (tmpf == NULL) err(EXIT_FAILURE, "malloc failed"); strncpy(tmpf, tmpdir, tlen); cp = &tmpf[tlen - 1]; if (*cp++ != '/') *cp++ = '/'; strncpy(cp, _TEMPFILE, plen); cp[plen] = '\0'; } else { tmpf = strdup(_TEMPFILEPATH); if (tmpf == NULL) err(EXIT_FAILURE, "strdup failed"); } if ((*fd = mkstemp(tmpf)) == -1) err(EXIT_FAILURE, "mkstemp %s failed", tmpf); if (fchmod(*fd, 0644) == -1) err(EXIT_FAILURE, "fchmod %s failed", tmpf); *fn = tmpf; #undef _TEMPFILE #undef _TEMPFILEPATH } /* * Copy temporary file with path src and file descriptor infd to path dst. * If in_place is set act as if editing the file in place, avoiding rename() * to preserve hard and symbolic links. Output file remains open, with file * descriptor returned in outfd. */ static int copy_from_tempfile(const char *src, const char *dst, int infd, int *outfd, int in_place) { int tmpfd; /* * First, check if we can use rename(). */ if (in_place == 0) { if (rename(src, dst) >= 0) { *outfd = infd; return (0); } else if (errno != EXDEV) return (-1); /* * If the rename() failed due to 'src' and 'dst' residing in * two different file systems, invoke a helper function in * libelftc to do the copy. */ if (unlink(dst) < 0) return (-1); } if ((tmpfd = open(dst, O_CREAT | O_TRUNC | O_WRONLY, 0755)) < 0) return (-1); if (elftc_copyfile(infd, tmpfd) < 0) return (-1); /* * Remove the temporary file from the file system * namespace, and close its file descriptor. */ if (unlink(src) < 0) return (-1); (void) close(infd); /* * Return the file descriptor for the destination. */ *outfd = tmpfd; return (0); } static void create_file(struct elfcopy *ecp, const char *src, const char *dst) { struct stat sb; char *tempfile, *elftemp; int efd, ifd, ofd, ofd0, tfd; int in_place; tempfile = NULL; if (src == NULL) errx(EXIT_FAILURE, "internal: src == NULL"); if ((ifd = open(src, O_RDONLY)) == -1) err(EXIT_FAILURE, "open %s failed", src); if (fstat(ifd, &sb) == -1) err(EXIT_FAILURE, "fstat %s failed", src); if (dst == NULL) create_tempfile(&tempfile, &ofd); else if ((ofd = open(dst, O_RDWR|O_CREAT, 0755)) == -1) err(EXIT_FAILURE, "open %s failed", dst); #ifndef LIBELF_AR /* Detect and process ar(1) archive using libarchive. */ if (ac_detect_ar(ifd)) { ac_create_ar(ecp, ifd, ofd); goto copy_done; } #endif if (lseek(ifd, 0, SEEK_SET) < 0) err(EXIT_FAILURE, "lseek failed"); /* * If input object is not ELF file, convert it to an intermediate * ELF object before processing. */ if (ecp->itf != ETF_ELF) { /* * If the output object is not an ELF file, choose an arbitrary * ELF format for the intermediate file. srec, ihex and binary * formats are independent of class, endianness and machine * type so these choices do not affect the output. */ if (ecp->otf != ETF_ELF) { if (ecp->oec == ELFCLASSNONE) ecp->oec = ELFCLASS64; if (ecp->oed == ELFDATANONE) ecp->oed = ELFDATA2LSB; } create_tempfile(&elftemp, &efd); if ((ecp->eout = elf_begin(efd, ELF_C_WRITE, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); if (ecp->itf == ETF_BINARY) create_elf_from_binary(ecp, ifd, src); else if (ecp->itf == ETF_IHEX) create_elf_from_ihex(ecp, ifd); else if (ecp->itf == ETF_SREC) create_elf_from_srec(ecp, ifd); else errx(EXIT_FAILURE, "Internal: invalid target flavour"); elf_end(ecp->eout); /* Open intermediate ELF object as new input object. */ close(ifd); if ((ifd = open(elftemp, O_RDONLY)) == -1) err(EXIT_FAILURE, "open %s failed", src); close(efd); free(elftemp); } if ((ecp->ein = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); switch (elf_kind(ecp->ein)) { case ELF_K_NONE: errx(EXIT_FAILURE, "file format not recognized"); case ELF_K_ELF: if ((ecp->eout = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); /* elfcopy(1) manage ELF layout by itself. */ elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); /* * Create output ELF object. */ create_elf(ecp); elf_end(ecp->eout); /* * Convert the output ELF object to binary/srec/ihex if need. */ if (ecp->otf != ETF_ELF) { /* * Create (another) tempfile for binary/srec/ihex * output object. */ if (tempfile != NULL) { if (unlink(tempfile) < 0) err(EXIT_FAILURE, "unlink %s failed", tempfile); free(tempfile); } create_tempfile(&tempfile, &ofd0); /* * Rewind the file descriptor being processed. */ if (lseek(ofd, 0, SEEK_SET) < 0) err(EXIT_FAILURE, "lseek failed for the output object"); /* * Call flavour-specific conversion routine. */ switch (ecp->otf) { case ETF_BINARY: create_binary(ofd, ofd0); break; case ETF_IHEX: create_ihex(ofd, ofd0); break; case ETF_SREC: create_srec(ecp, ofd, ofd0, dst != NULL ? dst : src); break; case ETF_PE: case ETF_EFI: #if WITH_PE create_pe(ecp, ofd, ofd0); #else errx(EXIT_FAILURE, "PE/EFI support not enabled" " at compile time"); #endif break; default: errx(EXIT_FAILURE, "Internal: unsupported" " output flavour %d", ecp->oec); } close(ofd); ofd = ofd0; } break; case ELF_K_AR: /* XXX: Not yet supported. */ break; default: errx(EXIT_FAILURE, "file format not supported"); } elf_end(ecp->ein); #ifndef LIBELF_AR copy_done: #endif if (tempfile != NULL) { in_place = 0; if (dst == NULL) { dst = src; if (lstat(dst, &sb) != -1 && (sb.st_nlink > 1 || S_ISLNK(sb.st_mode))) in_place = 1; } if (copy_from_tempfile(tempfile, dst, ofd, &tfd, in_place) < 0) err(EXIT_FAILURE, "creation of %s failed", dst); free(tempfile); tempfile = NULL; ofd = tfd; } if (strcmp(dst, "/dev/null") && fchmod(ofd, sb.st_mode) == -1) err(EXIT_FAILURE, "fchmod %s failed", dst); if ((ecp->flags & PRESERVE_DATE) && elftc_set_timestamps(dst, &sb) < 0) err(EXIT_FAILURE, "setting timestamps failed"); close(ifd); close(ofd); } static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv) { struct sec_action *sac; const char *infile, *outfile; char *fn, *s; int opt; while ((opt = getopt_long(argc, argv, "dB:gG:I:j:K:L:N:O:pR:s:SwW:xXV", elfcopy_longopts, NULL)) != -1) { switch(opt) { case 'B': /* ignored */ break; case 'R': sac = lookup_sec_act(ecp, optarg, 1); if (sac->copy != 0) errx(EXIT_FAILURE, "both copy and remove specified"); sac->remove = 1; ecp->flags |= SEC_REMOVE; break; case 'S': ecp->strip = STRIP_ALL; break; case 'g': ecp->strip = STRIP_DEBUG; break; case 'G': ecp->flags |= KEEP_GLOBAL; add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEPG); break; case 'I': case 's': set_input_target(ecp, optarg); break; case 'j': sac = lookup_sec_act(ecp, optarg, 1); if (sac->remove != 0) errx(EXIT_FAILURE, "both copy and remove specified"); sac->copy = 1; ecp->flags |= SEC_COPY; break; case 'K': add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEP); break; case 'L': add_to_symop_list(ecp, optarg, NULL, SYMOP_LOCALIZE); break; case 'N': add_to_symop_list(ecp, optarg, NULL, SYMOP_STRIP); break; case 'O': set_output_target(ecp, optarg); break; case 'p': ecp->flags |= PRESERVE_DATE; break; case 'V': print_version(); break; case 'w': ecp->flags |= WILDCARD; break; case 'W': add_to_symop_list(ecp, optarg, NULL, SYMOP_WEAKEN); break; case 'x': ecp->flags |= DISCARD_LOCAL; break; case 'X': ecp->flags |= DISCARD_LLABEL; break; case ECP_ADD_GNU_DEBUGLINK: ecp->debuglink = optarg; break; case ECP_ADD_SECTION: add_section(ecp, optarg); break; case ECP_CHANGE_ADDR: ecp->change_addr = (int64_t) strtoll(optarg, NULL, 0); break; case ECP_CHANGE_SEC_ADDR: parse_sec_address_op(ecp, opt, "--change-section-addr", optarg); break; case ECP_CHANGE_SEC_LMA: parse_sec_address_op(ecp, opt, "--change-section-lma", optarg); break; case ECP_CHANGE_SEC_VMA: parse_sec_address_op(ecp, opt, "--change-section-vma", optarg); break; case ECP_CHANGE_START: ecp->change_start = (int64_t) strtoll(optarg, NULL, 0); break; case ECP_CHANGE_WARN: /* default */ break; case ECP_GAP_FILL: ecp->fill = (uint8_t) strtoul(optarg, NULL, 0); ecp->flags |= GAP_FILL; break; case ECP_GLOBALIZE_SYMBOL: add_to_symop_list(ecp, optarg, NULL, SYMOP_GLOBALIZE); break; case ECP_GLOBALIZE_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_GLOBALIZE); break; case ECP_KEEP_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_KEEP); break; case ECP_KEEP_GLOBAL_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_KEEPG); break; case ECP_LOCALIZE_HIDDEN: ecp->flags |= LOCALIZE_HIDDEN; break; case ECP_LOCALIZE_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_LOCALIZE); break; case ECP_NO_CHANGE_WARN: ecp->flags |= NO_CHANGE_WARN; break; case ECP_ONLY_DEBUG: ecp->strip = STRIP_NONDEBUG; break; case ECP_ONLY_DWO: ecp->strip = STRIP_NONDWO; break; case ECP_PAD_TO: ecp->pad_to = (uint64_t) strtoull(optarg, NULL, 0); break; case ECP_PREFIX_ALLOC: ecp->prefix_alloc = optarg; break; case ECP_PREFIX_SEC: ecp->prefix_sec = optarg; break; case ECP_PREFIX_SYM: ecp->prefix_sym = optarg; break; case ECP_REDEF_SYMBOL: if ((s = strchr(optarg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --redefine-sym"); *s++ = '\0'; add_to_symop_list(ecp, optarg, s, SYMOP_REDEF); break; case ECP_REDEF_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_REDEF); break; case ECP_RENAME_SECTION: if ((fn = strchr(optarg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --rename-section"); *fn++ = '\0'; /* Check for optional flags. */ if ((s = strchr(fn, ',')) != NULL) *s++ = '\0'; sac = lookup_sec_act(ecp, optarg, 1); sac->rename = 1; sac->newname = fn; if (s != NULL) parse_sec_flags(sac, s); break; case ECP_SET_OSABI: set_osabi(ecp, optarg); break; case ECP_SET_SEC_FLAGS: if ((s = strchr(optarg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --set-section-flags"); *s++ = '\0'; sac = lookup_sec_act(ecp, optarg, 1); parse_sec_flags(sac, s); break; case ECP_SET_START: ecp->flags |= SET_START; ecp->set_start = (uint64_t) strtoull(optarg, NULL, 0); break; case ECP_SREC_FORCE_S3: ecp->flags |= SREC_FORCE_S3; break; case ECP_SREC_LEN: ecp->flags |= SREC_FORCE_LEN; ecp->srec_len = strtoul(optarg, NULL, 0); break; case ECP_STRIP_DWO: ecp->strip = STRIP_DWO; break; case ECP_STRIP_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_STRIP); break; case ECP_STRIP_UNNEEDED: ecp->strip = STRIP_UNNEEDED; break; case ECP_WEAKEN_ALL: ecp->flags |= WEAKEN_ALL; break; case ECP_WEAKEN_SYMBOLS: parse_symlist_file(ecp, optarg, SYMOP_WEAKEN); break; default: elfcopy_usage(); } } if (optind == argc || optind + 2 < argc) elfcopy_usage(); infile = argv[optind]; outfile = NULL; if (optind + 1 < argc) outfile = argv[optind + 1]; create_file(ecp, infile, outfile); } static void mcs_main(struct elfcopy *ecp, int argc, char **argv) { struct sec_action *sac; const char *string; int append, delete, compress, name, print; int opt, i; append = delete = compress = name = print = 0; string = NULL; while ((opt = getopt_long(argc, argv, "a:cdhn:pV", mcs_longopts, NULL)) != -1) { switch(opt) { case 'a': append = 1; string = optarg; /* XXX multiple -a not supported */ break; case 'c': compress = 1; break; case 'd': delete = 1; break; case 'n': name = 1; (void)lookup_sec_act(ecp, optarg, 1); break; case 'p': print = 1; break; case 'V': print_version(); break; case 'h': default: mcs_usage(); } } if (optind == argc) mcs_usage(); /* Must specify one operation at least. */ if (!append && !compress && !delete && !print) mcs_usage(); /* * If we are going to delete, ignore other operations. This is * different from the Solaris implementation, which can print * and delete a section at the same time, for example. Also, this * implementation do not respect the order between operations that * user specified, i.e., "mcs -pc a.out" equals to "mcs -cp a.out". */ if (delete) { append = compress = print = 0; ecp->flags |= SEC_REMOVE; } if (append) ecp->flags |= SEC_APPEND; if (compress) ecp->flags |= SEC_COMPRESS; if (print) ecp->flags |= SEC_PRINT; /* .comment is the default section to operate on. */ if (!name) (void)lookup_sec_act(ecp, ".comment", 1); STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { sac->append = append; sac->compress = compress; sac->print = print; sac->remove = delete; sac->string = string; } for (i = optind; i < argc; i++) { /* If only -p is specified, output to /dev/null */ if (print && !append && !compress && !delete) create_file(ecp, argv[i], "/dev/null"); else create_file(ecp, argv[i], NULL); } } static void strip_main(struct elfcopy *ecp, int argc, char **argv) { struct sec_action *sac; const char *outfile; int opt; int i; outfile = NULL; while ((opt = getopt_long(argc, argv, "hI:K:N:o:O:pR:sSdgVxXw", strip_longopts, NULL)) != -1) { switch(opt) { case 'R': sac = lookup_sec_act(ecp, optarg, 1); sac->remove = 1; ecp->flags |= SEC_REMOVE; break; case 's': ecp->strip = STRIP_ALL; break; case 'S': case 'g': case 'd': ecp->strip = STRIP_DEBUG; break; case 'I': /* ignored */ break; case 'K': add_to_symop_list(ecp, optarg, NULL, SYMOP_KEEP); break; case 'N': add_to_symop_list(ecp, optarg, NULL, SYMOP_STRIP); break; case 'o': outfile = optarg; break; case 'O': set_output_target(ecp, optarg); break; case 'p': ecp->flags |= PRESERVE_DATE; break; case 'V': print_version(); break; case 'w': ecp->flags |= WILDCARD; break; case 'x': ecp->flags |= DISCARD_LOCAL; break; case 'X': ecp->flags |= DISCARD_LLABEL; break; case ECP_ONLY_DEBUG: ecp->strip = STRIP_NONDEBUG; break; case ECP_STRIP_UNNEEDED: ecp->strip = STRIP_UNNEEDED; break; case 'h': default: strip_usage(); } } if (ecp->strip == 0 && ((ecp->flags & DISCARD_LOCAL) == 0) && ((ecp->flags & DISCARD_LLABEL) == 0) && lookup_symop_list(ecp, NULL, SYMOP_STRIP) == NULL) ecp->strip = STRIP_ALL; if (optind == argc) strip_usage(); for (i = optind; i < argc; i++) create_file(ecp, argv[i], outfile); } static void parse_sec_flags(struct sec_action *sac, char *s) { const char *flag; int found, i; for (flag = strtok(s, ","); flag; flag = strtok(NULL, ",")) { found = 0; for (i = 0; sec_flags[i].name != NULL; i++) if (strcasecmp(sec_flags[i].name, flag) == 0) { sac->flags |= sec_flags[i].value; found = 1; break; } if (!found) errx(EXIT_FAILURE, "unrecognized section flag %s", flag); } } static void parse_sec_address_op(struct elfcopy *ecp, int optnum, const char *optname, char *s) { struct sec_action *sac; const char *name; char *v; char op; name = v = s; do { v++; } while (*v != '\0' && *v != '=' && *v != '+' && *v != '-'); if (*v == '\0' || *(v + 1) == '\0') errx(EXIT_FAILURE, "invalid format for %s", optname); op = *v; *v++ = '\0'; sac = lookup_sec_act(ecp, name, 1); switch (op) { case '=': if (optnum == ECP_CHANGE_SEC_LMA || optnum == ECP_CHANGE_SEC_ADDR) { sac->setlma = 1; sac->lma = (uint64_t) strtoull(v, NULL, 0); } if (optnum == ECP_CHANGE_SEC_VMA || optnum == ECP_CHANGE_SEC_ADDR) { sac->setvma = 1; sac->vma = (uint64_t) strtoull(v, NULL, 0); } break; case '+': if (optnum == ECP_CHANGE_SEC_LMA || optnum == ECP_CHANGE_SEC_ADDR) sac->lma_adjust = (int64_t) strtoll(v, NULL, 0); if (optnum == ECP_CHANGE_SEC_VMA || optnum == ECP_CHANGE_SEC_ADDR) sac->vma_adjust = (int64_t) strtoll(v, NULL, 0); break; case '-': if (optnum == ECP_CHANGE_SEC_LMA || optnum == ECP_CHANGE_SEC_ADDR) sac->lma_adjust = (int64_t) -strtoll(v, NULL, 0); if (optnum == ECP_CHANGE_SEC_VMA || optnum == ECP_CHANGE_SEC_ADDR) sac->vma_adjust = (int64_t) -strtoll(v, NULL, 0); break; default: break; } } static void parse_symlist_file(struct elfcopy *ecp, const char *fn, unsigned int op) { struct symfile *sf; struct stat sb; FILE *fp; char *data, *p, *line, *end, *e, *n; if (stat(fn, &sb) == -1) err(EXIT_FAILURE, "stat %s failed", fn); /* Check if we already read and processed this file. */ STAILQ_FOREACH(sf, &ecp->v_symfile, symfile_list) { if (sf->dev == sb.st_dev && sf->ino == sb.st_ino) goto process_symfile; } if ((fp = fopen(fn, "r")) == NULL) err(EXIT_FAILURE, "can not open %s", fn); if ((data = malloc(sb.st_size + 1)) == NULL) err(EXIT_FAILURE, "malloc failed"); if (fread(data, 1, sb.st_size, fp) == 0 || ferror(fp)) err(EXIT_FAILURE, "fread failed"); fclose(fp); data[sb.st_size] = '\0'; if ((sf = calloc(1, sizeof(*sf))) == NULL) err(EXIT_FAILURE, "malloc failed"); sf->dev = sb.st_dev; sf->ino = sb.st_ino; sf->size = sb.st_size + 1; sf->data = data; process_symfile: /* * Basically what we do here is to convert EOL to '\0', and remove * leading and trailing whitespaces for each line. */ end = sf->data + sf->size; line = NULL; for(p = sf->data; p < end; p++) { if ((*p == '\t' || *p == ' ') && line == NULL) continue; if (*p == '\r' || *p == '\n' || *p == '\0') { *p = '\0'; if (line == NULL) continue; /* Skip comment. */ if (*line == '#') { line = NULL; continue; } e = p - 1; while(e != line && (*e == '\t' || *e == ' ')) *e-- = '\0'; if (op != SYMOP_REDEF) add_to_symop_list(ecp, line, NULL, op); else { if (strlen(line) < 3) errx(EXIT_FAILURE, "illegal format for" " --redefine-sym"); for(n = line + 1; n < e; n++) { if (*n == ' ' || *n == '\t') { while(*n == ' ' || *n == '\t') *n++ = '\0'; break; } } if (n >= e) errx(EXIT_FAILURE, "illegal format for" " --redefine-sym"); add_to_symop_list(ecp, line, n, op); } line = NULL; continue; } if (line == NULL) line = p; } } static void set_input_target(struct elfcopy *ecp, const char *target_name) { Elftc_Bfd_Target *tgt; if ((tgt = elftc_bfd_find_target(target_name)) == NULL) errx(EXIT_FAILURE, "%s: invalid target name", target_name); ecp->itf = elftc_bfd_target_flavor(tgt); } static void set_output_target(struct elfcopy *ecp, const char *target_name) { Elftc_Bfd_Target *tgt; if ((tgt = elftc_bfd_find_target(target_name)) == NULL) errx(EXIT_FAILURE, "%s: invalid target name", target_name); ecp->otf = elftc_bfd_target_flavor(tgt); if (ecp->otf == ETF_ELF) { ecp->oec = elftc_bfd_target_class(tgt); ecp->oed = elftc_bfd_target_byteorder(tgt); ecp->oem = elftc_bfd_target_machine(tgt); } if (ecp->otf == ETF_EFI || ecp->otf == ETF_PE) ecp->oem = elftc_bfd_target_machine(tgt); ecp->otgt = target_name; } static void set_osabi(struct elfcopy *ecp, const char *abi) { int i, found; found = 0; for (i = 0; osabis[i].name != NULL; i++) if (strcasecmp(osabis[i].name, abi) == 0) { ecp->abi = osabis[i].abi; found = 1; break; } if (!found) errx(EXIT_FAILURE, "unrecognized OSABI %s", abi); } #define ELFCOPY_USAGE_MESSAGE "\ Usage: %s [options] infile [outfile]\n\ Transform object files.\n\n\ Options:\n\ -d | -g | --strip-debug Remove debugging information from the output.\n\ -j SECTION | --only-section=SECTION\n\ Copy only the named section to the output.\n\ -p | --preserve-dates Preserve access and modification times.\n\ -w | --wildcard Use shell-style patterns to name symbols.\n\ -x | --discard-all Do not copy non-globals to the output.\n\ -I FORMAT | --input-target=FORMAT\n\ Specify object format for the input file.\n\ -K SYM | --keep-symbol=SYM Copy symbol SYM to the output.\n\ -L SYM | --localize-symbol=SYM\n\ Make symbol SYM local to the output file.\n\ -N SYM | --strip-symbol=SYM Do not copy symbol SYM to the output.\n\ -O FORMAT | --output-target=FORMAT\n\ Specify object format for the output file.\n\ FORMAT should be a target name understood by\n\ elftc_bfd_find_target(3).\n\ -R NAME | --remove-section=NAME\n\ Remove the named section.\n\ -S | --strip-all Remove all symbol and relocation information\n\ from the output.\n\ -V | --version Print a version identifier and exit.\n\ -W SYM | --weaken-symbol=SYM Mark symbol SYM as weak in the output.\n\ -X | --discard-locals Do not copy compiler generated symbols to\n\ the output.\n\ --add-section NAME=FILE Add the contents of FILE to the ELF object as\n\ a new section named NAME.\n\ --adjust-section-vma SECTION{=,+,-}VAL | \\\n\ --change-section-address SECTION{=,+,-}VAL\n\ Set or adjust the VMA and the LMA of the\n\ named section by VAL.\n\ --adjust-start=INCR | --change-start=INCR\n\ Add INCR to the start address for the ELF\n\ object.\n\ --adjust-vma=INCR | --change-addresses=INCR\n\ Increase the VMA and LMA of all sections by\n\ INCR.\n\ --adjust-warning | --change-warnings\n\ Issue warnings for non-existent sections.\n\ --change-section-lma SECTION{=,+,-}VAL\n\ Set or adjust the LMA address of the named\n\ section by VAL.\n\ --change-section-vma SECTION{=,+,-}VAL\n\ Set or adjust the VMA address of the named\n\ section by VAL.\n\ --gap-fill=VAL Fill the gaps between sections with bytes\n\ of value VAL.\n\ --localize-hidden Make all hidden symbols local to the output\n\ file.\n\ --no-adjust-warning| --no-change-warnings\n\ Do not issue warnings for non-existent\n\ sections.\n\ --only-keep-debug Copy only debugging information.\n\ --output-target=FORMAT Use the specified format for the output.\n\ --pad-to=ADDRESS Pad the output object up to the given address.\n\ --prefix-alloc-sections=STRING\n\ Prefix the section names of all the allocated\n\ sections with STRING.\n\ --prefix-sections=STRING Prefix the section names of all the sections\n\ with STRING.\n\ --prefix-symbols=STRING Prefix the symbol names of all the symbols\n\ with STRING.\n\ --rename-section OLDNAME=NEWNAME[,FLAGS]\n\ Rename and optionally change section flags.\n\ --set-section-flags SECTION=FLAGS\n\ Set section flags for the named section.\n\ Supported flags are: 'alloc', 'code',\n\ 'contents', 'data', 'debug', 'load',\n\ 'noload', 'readonly', 'rom', and 'shared'.\n\ --set-start=ADDRESS Set the start address of the ELF object.\n\ --srec-forceS3 Only generate S3 S-Records.\n\ --srec-len=LEN Set the maximum length of a S-Record line.\n\ --strip-unneeded Do not copy relocation information.\n" static void elfcopy_usage(void) { (void) fprintf(stderr, ELFCOPY_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } #define MCS_USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Manipulate the comment section in an ELF object.\n\n\ Options:\n\ -a STRING Append 'STRING' to the comment section.\n\ -c Remove duplicate entries from the comment section.\n\ -d Delete the comment section.\n\ -h | --help Print a help message and exit.\n\ -n NAME Operate on the ELF section with name 'NAME'.\n\ -p Print the contents of the comment section.\n\ -V | --version Print a version identifier and exit.\n" static void mcs_usage(void) { (void) fprintf(stderr, MCS_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } #define STRIP_USAGE_MESSAGE "\ Usage: %s [options] file...\n\ Discard information from ELF objects.\n\n\ Options:\n\ -d | -g | -S | --strip-debug Remove debugging symbols.\n\ -h | --help Print a help message.\n\ -o FILE | --output-file FILE Write output to FILE.\n\ --only-keep-debug Keep debugging information only.\n\ -p | --preserve-dates Preserve access and modification times.\n\ -s | --strip-all Remove all symbols.\n\ --strip-unneeded Remove symbols not needed for relocation\n\ processing.\n\ -w | --wildcard Use shell-style patterns to name symbols.\n\ -x | --discard-all Discard all non-global symbols.\n\ -I TGT| --input-target=TGT (Accepted, but ignored).\n\ -K SYM | --keep-symbol=SYM Keep symbol 'SYM' in the output.\n\ -N SYM | --strip-symbol=SYM Remove symbol 'SYM' from the output.\n\ -O TGT | --output-target=TGT Set the output file format to 'TGT'.\n\ -R SEC | --remove-section=SEC Remove the section named 'SEC'.\n\ -V | --version Print a version identifier and exit.\n\ -X | --discard-locals Remove compiler-generated local symbols.\n" static void strip_usage(void) { (void) fprintf(stderr, STRIP_USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } static void print_version(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } int main(int argc, char **argv) { struct elfcopy *ecp; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); ecp = calloc(1, sizeof(*ecp)); if (ecp == NULL) err(EXIT_FAILURE, "calloc failed"); memset(ecp, 0, sizeof(*ecp)); ecp->itf = ecp->otf = ETF_ELF; ecp->iec = ecp->oec = ELFCLASSNONE; ecp->oed = ELFDATANONE; ecp->abi = -1; /* There is always an empty section. */ ecp->nos = 1; ecp->fill = 0; STAILQ_INIT(&ecp->v_seg); STAILQ_INIT(&ecp->v_sac); STAILQ_INIT(&ecp->v_sadd); STAILQ_INIT(&ecp->v_symop); STAILQ_INIT(&ecp->v_symfile); STAILQ_INIT(&ecp->v_arobj); TAILQ_INIT(&ecp->v_sec); if ((ecp->progname = ELFTC_GETPROGNAME()) == NULL) ecp->progname = "elfcopy"; if (strcmp(ecp->progname, "strip") == 0) strip_main(ecp, argc, argv); else if (strcmp(ecp->progname, "mcs") == 0) mcs_main(ecp, argc, argv); else elfcopy_main(ecp, argc, argv); free_sec_add(ecp); free_sec_act(ecp); free(ecp); exit(EXIT_SUCCESS); } Index: vendor/elftoolchain/dist/elfcopy/os.FreeBSD.mk =================================================================== --- vendor/elftoolchain/dist/elfcopy/os.FreeBSD.mk (nonexistent) +++ vendor/elftoolchain/dist/elfcopy/os.FreeBSD.mk (revision 317073) @@ -0,0 +1,4 @@ +.if !defined(LIBELF_AR) +DPADD+= ${LIBBZ2} +LDADD+= -lbz2 +.endif Property changes on: vendor/elftoolchain/dist/elfcopy/os.FreeBSD.mk ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/elftoolchain/dist/elfcopy/pe.c =================================================================== --- vendor/elftoolchain/dist/elfcopy/pe.c (revision 317072) +++ vendor/elftoolchain/dist/elfcopy/pe.c (revision 317073) @@ -1,234 +1,236 @@ /*- * Copyright (c) 2016 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: pe.c 3490 2016-08-31 00:12:22Z emaste $"); +ELFTC_VCSID("$Id: pe.c 3508 2016-12-27 06:19:39Z kaiwang27 $"); /* Convert ELF object to Portable Executable (PE). */ void create_pe(struct elfcopy *ecp, int ifd, int ofd) { Elf *e; Elf_Scn *scn; Elf_Data *d; GElf_Ehdr eh; GElf_Shdr sh; PE *pe; PE_Scn *ps; PE_SecHdr psh; PE_CoffHdr pch; PE_OptHdr poh; PE_Object po; PE_Buffer *pb; const char *name; size_t indx; time_t timestamp; int elferr; if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64) po = PE_O_PE32P; else po = PE_O_PE32; if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) errx(EXIT_FAILURE, "elf_begin() failed: %s", elf_errmsg(-1)); if (gelf_getehdr(e, &eh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); - if (elf_getshstrndx(ecp->ein, &indx) == 0) + if (elf_getshstrndx(e, &indx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s", elf_errmsg(-1)); if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL) err(EXIT_FAILURE, "pe_init() failed"); /* Setup PE COFF header. */ memset(&pch, 0, sizeof(pch)); switch (ecp->oem) { case EM_386: pch.ch_machine = IMAGE_FILE_MACHINE_I386; break; case EM_X86_64: pch.ch_machine = IMAGE_FILE_MACHINE_AMD64; break; default: pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN; break; } if (elftc_timestamp(×tamp) != 0) err(EXIT_FAILURE, "elftc_timestamp"); pch.ch_timestamp = (uint32_t) timestamp; if (pe_update_coff_header(pe, &pch) < 0) err(EXIT_FAILURE, "pe_update_coff_header() failed"); /* Setup PE optional header. */ memset(&poh, 0, sizeof(poh)); if (ecp->otf == ETF_EFI) poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION; poh.oh_entry = (uint32_t) eh.e_entry; /* * Default section alignment and file alignment. (Here the * section alignment is set to the default page size of the * archs supported. We should use different section alignment * for some arch. (e.g. IA64) */ poh.oh_secalign = 0x1000; poh.oh_filealign = 0x200; /* Copy sections. */ scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { /* * Read in ELF section. */ if (gelf_getshdr(scn, &sh) == NULL) { warnx("gelf_getshdr() failed: %s", elf_errmsg(-1)); (void) elf_errno(); continue; } - if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == + if ((name = elf_strptr(e, indx, sh.sh_name)) == NULL) { warnx("elf_strptr() failed: %s", elf_errmsg(-1)); (void) elf_errno(); continue; } /* Skip sections unneeded. */ if (strcmp(name, ".shstrtab") == 0 || strcmp(name, ".symtab") == 0 || strcmp(name, ".strtab") == 0) continue; if ((d = elf_getdata(scn, NULL)) == NULL) { warnx("elf_getdata() failed: %s", elf_errmsg(-1)); (void) elf_errno(); continue; } if (strcmp(name, ".text") == 0) { poh.oh_textbase = (uint32_t) sh.sh_addr; poh.oh_textsize = (uint32_t) roundup(sh.sh_size, poh.oh_filealign); } else { if (po == PE_O_PE32 && strcmp(name, ".data") == 0) poh.oh_database = sh.sh_addr; if (sh.sh_type == SHT_NOBITS) poh.oh_bsssize += (uint32_t) roundup(sh.sh_size, poh.oh_filealign); else if (sh.sh_flags & SHF_ALLOC) poh.oh_datasize += (uint32_t) roundup(sh.sh_size, poh.oh_filealign); } /* * Create PE/COFF section. */ if ((ps = pe_newscn(pe)) == NULL) { warn("pe_newscn() failed"); continue; } /* * Setup PE/COFF section header. The section name is not * NUL-terminated if its length happens to be 8. Long * section name should be truncated for PE image according * to the PE/COFF specification. */ memset(&psh, 0, sizeof(psh)); strncpy(psh.sh_name, name, sizeof(psh.sh_name)); psh.sh_addr = sh.sh_addr; psh.sh_virtsize = sh.sh_size; if (sh.sh_type != SHT_NOBITS) psh.sh_rawsize = roundup(sh.sh_size, poh.oh_filealign); else psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; /* * Translate ELF section flags to PE/COFF section flags. */ psh.sh_char |= IMAGE_SCN_MEM_READ; if (sh.sh_flags & SHF_WRITE) psh.sh_char |= IMAGE_SCN_MEM_WRITE; if (sh.sh_flags & SHF_EXECINSTR) psh.sh_char |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0) psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA; /* Mark relocation section "discardable". */ if (strcmp(name, ".reloc") == 0) psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE; if (pe_update_section_header(ps, &psh) < 0) { warn("pe_update_section_header() failed"); continue; } /* Copy section content. */ if ((pb = pe_newbuffer(ps)) == NULL) { warn("pe_newbuffer() failed"); continue; } pb->pb_align = 1; pb->pb_off = 0; - pb->pb_size = roundup(sh.sh_size, poh.oh_filealign); - if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) { - warn("calloc failed"); - continue; + if (sh.sh_type != SHT_NOBITS) { + pb->pb_size = roundup(sh.sh_size, poh.oh_filealign); + if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) { + warn("calloc failed"); + continue; + } + memcpy(pb->pb_buf, d->d_buf, sh.sh_size); } - memcpy(pb->pb_buf, d->d_buf, sh.sh_size); } elferr = elf_errno(); if (elferr != 0) warnx("elf_nextscn() failed: %s", elf_errmsg(elferr)); /* Update PE optional header. */ if (pe_update_opt_header(pe, &poh) < 0) err(EXIT_FAILURE, "pe_update_opt_header() failed"); /* Write out PE/COFF object. */ if (pe_update(pe) < 0) err(EXIT_FAILURE, "pe_update() failed"); pe_finish(pe); elf_end(e); } Index: vendor/elftoolchain/dist/elfcopy/symbols.c =================================================================== --- vendor/elftoolchain/dist/elfcopy/symbols.c (revision 317072) +++ vendor/elftoolchain/dist/elfcopy/symbols.c (revision 317073) @@ -1,1205 +1,1207 @@ /*- * Copyright (c) 2007-2013 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "elfcopy.h" -ELFTC_VCSID("$Id: symbols.c 3446 2016-05-03 01:31:17Z emaste $"); +ELFTC_VCSID("$Id: symbols.c 3520 2017-04-17 01:47:52Z kaiwang27 $"); /* 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_reloc_symbols(struct elfcopy *ecp, size_t sc); static void mark_section_group_symbols(struct elfcopy *ecp, size_t sc); 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 || GELF_ST_BIND(st_info) == STB_GNU_UNIQUE) 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); /* Symbols referred by COMDAT sections are needed. */ if (BIT_ISSET(ecp->v_grp, 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 */ }; /* * 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); /* Keep the symbol if specified by command line option -K. */ if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) return (0); if (ecp->strip == STRIP_ALL) return (1); /* Mark symbols used in relocation. */ if (ecp->v_rel == NULL) mark_reloc_symbols(ecp, sc); /* Mark symbols used in section groups. */ if (ecp->v_grp == NULL) mark_section_group_symbols(ecp, sc); /* * Strip the symbol if specified by command line option -N, * unless it's used in relocation. */ if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) { if (BIT_ISSET(ecp->v_rel, i)) { warnx("not stripping symbol `%s' because it is named" " in a relocation", name); return (0); } return (1); } 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 referred by relocation entries. */ static void mark_reloc_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 void mark_section_group_symbols(struct elfcopy *ecp, size_t sc) { const char *name; Elf_Scn *s; GElf_Shdr sh; size_t indx; int elferr; ecp->v_grp = calloc((sc + 7) / 8, 1); if (ecp->v_grp == 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_GROUP) continue; 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)) continue; if (sh.sh_info > 0 && sh.sh_info < sc) BIT_SET(ecp->v_grp, sh.sh_info); else if (sh.sh_info != 0) warnx("invalid symbox index"); } 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; gsym = NULL; /* * 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"); goto clean; } /* 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. */ 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)); goto clean; } } 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 && sym.st_shndx < SHN_LORESERVE) { assert(ecp->secndx[sym.st_shndx] < (uint64_t)ecp->nos); 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) goto clean; /* * 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); sym.st_other = STV_DEFAULT; /* * 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); clean: free(gsym); free_symtab(ecp); return (0); } void create_symtab(struct elfcopy *ecp) { struct section *s, *sy, *st; size_t maxndx, ndx; sy = ecp->symtab; st = ecp->strtab; + + assert(sy != NULL && st != NULL); /* * 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->buf); free(ecp->symtab); free(ecp->strtab->buf); 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); } } } if (ecp->symndx != NULL) { free(ecp->symndx); ecp->symndx = NULL; } if (ecp->v_rel != NULL) { free(ecp->v_rel); ecp->v_rel = NULL; } if (ecp->v_grp != NULL) { free(ecp->v_grp); ecp->v_grp = NULL; } if (ecp->v_secsym != NULL) { free(ecp->v_secsym); ecp->v_secsym = NULL; } } 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 _ST_NAME_EMPTY_l 0 #define _ST_NAME_EMPTY_g -1 #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 = \ (Elf##SZ##_Word)_ST_NAME_EMPTY_##B; \ 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 #undef _ST_NAME_EMPTY_l #undef _ST_NAME_EMPTY_g } 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) { if (sy_buf->g32[i].st_name == (Elf32_Word)-1) sy_buf->g32[i].st_name = 0; else sy_buf->g32[i].st_name += st_buf->l.sz; } else { if (sy_buf->g64[i].st_name == (Elf64_Word)-1) sy_buf->g64[i].st_name = 0; 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; assert (name != NULL); STAILQ_FOREACH(s, &ecp->v_symop, symop_list) if (!strcmp(name, s->name)) goto found; if ((s = calloc(1, sizeof(*s))) == NULL) errx(EXIT_FAILURE, "not enough memory"); STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list); s->name = name; found: if (op == SYMOP_REDEF) s->newname = newname; s->op |= op; } struct symop * lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op) { struct symop *s, *ret; const char *pattern; STAILQ_FOREACH(s, &ecp->v_symop, symop_list) { if ((s->op & op) == 0) continue; if (name == NULL || !strcmp(name, s->name)) return (s); if ((ecp->flags & WILDCARD) == 0) continue; /* Handle wildcards. */ pattern = s->name; if (pattern[0] == '!') { /* Negative match. */ pattern++; ret = NULL; } else { /* Regular wildcard match. */ ret = s; } if (!fnmatch(pattern, name, 0)) return (ret); } 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 = 2166136261UL; *s; s++) hash = (hash ^ *s) * 16777619; return (hash & (STHASHSIZE - 1)); } Index: vendor/elftoolchain/dist/elfdump/elfdump.c =================================================================== --- vendor/elftoolchain/dist/elfdump/elfdump.c (revision 317072) +++ vendor/elftoolchain/dist/elfdump/elfdump.c (revision 317073) @@ -1,2680 +1,2680 @@ /*- * 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 3482 2016-08-02 18:47:00Z emaste $"); +ELFTC_VCSID("$Id: elfdump.c 3497 2016-10-17 20:57:22Z 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) { static char unknown_buf[64]; switch (tag) { case DT_NULL: return "DT_NULL"; case DT_NEEDED: return "DT_NEEDED"; case DT_PLTRELSZ: return "DT_PLTRELSZ"; case DT_PLTGOT: return "DT_PLTGOT"; case DT_HASH: return "DT_HASH"; case DT_STRTAB: return "DT_STRTAB"; case DT_SYMTAB: return "DT_SYMTAB"; case DT_RELA: return "DT_RELA"; case DT_RELASZ: return "DT_RELASZ"; case DT_RELAENT: return "DT_RELAENT"; case DT_STRSZ: return "DT_STRSZ"; case DT_SYMENT: return "DT_SYMENT"; case DT_INIT: return "DT_INIT"; case DT_FINI: return "DT_FINI"; case DT_SONAME: return "DT_SONAME"; case DT_RPATH: return "DT_RPATH"; case DT_SYMBOLIC: return "DT_SYMBOLIC"; case DT_REL: return "DT_REL"; case DT_RELSZ: return "DT_RELSZ"; case DT_RELENT: return "DT_RELENT"; case DT_PLTREL: return "DT_PLTREL"; case DT_DEBUG: return "DT_DEBUG"; case DT_TEXTREL: return "DT_TEXTREL"; case DT_JMPREL: return "DT_JMPREL"; case DT_BIND_NOW: return "DT_BIND_NOW"; case DT_INIT_ARRAY: return "DT_INIT_ARRAY"; case DT_FINI_ARRAY: return "DT_FINI_ARRAY"; case DT_INIT_ARRAYSZ: return "DT_INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return "DT_FINI_ARRAYSZ"; case DT_RUNPATH: return "DT_RUNPATH"; case DT_FLAGS: return "DT_FLAGS"; case DT_PREINIT_ARRAY: return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */ case DT_PREINIT_ARRAYSZ: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 DT_PLTPADSZ: return "DT_PLTPADSZ"; case DT_MOVEENT: return "DT_MOVEENT"; case DT_MOVESZ: return "DT_MOVESZ"; case 0x6ffffdfc: return "DT_FEATURE"; case DT_POSFLAG_1: return "DT_POSFLAG_1"; case DT_SYMINSZ: return "DT_SYMINSZ"; case DT_SYMINENT: return "DT_SYMINENT (DT_VALRNGHI)"; case DT_ADDRRNGLO: return "DT_ADDRRNGLO"; case DT_GNU_HASH: return "DT_GNU_HASH"; case 0x6ffffef8: return "DT_GNU_CONFLICT"; case 0x6ffffef9: return "DT_GNU_LIBLIST"; case 0x6ffffefa: return "DT_CONFIG"; case 0x6ffffefb: return "DT_DEPAUDIT"; case 0x6ffffefc: return "DT_AUDIT"; case 0x6ffffefd: return "DT_PLTPAD"; case 0x6ffffefe: return "DT_MOVETAB"; case DT_SYMINFO: return "DT_SYMINFO (DT_ADDRRNGHI)"; case DT_RELACOUNT: return "DT_RELACOUNT"; case DT_RELCOUNT: return "DT_RELCOUNT"; case DT_FLAGS_1: return "DT_FLAGS_1"; case DT_VERDEF: return "DT_VERDEF"; case DT_VERDEFNUM: return "DT_VERDEFNUM"; case DT_VERNEED: return "DT_VERNEED"; case DT_VERNEEDNUM: 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"; + case DT_AUXILIARY: return "DT_AUXILIARY"; + case DT_USED: return "DT_USED"; + case DT_FILTER: return "DT_FILTER"; } snprintf(unknown_buf, sizeof(unknown_buf), "", (unsigned long long)tag); return (unknown_buf); } 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_IAMCU: return "EM_IAMCU"; case EM_860: return "EM_860"; case EM_MIPS: return "EM_MIPS"; case EM_PPC: return "EM_PPC"; case EM_PPC64: return "EM_PPC64"; 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"; case EM_AARCH64:return "EM_AARCH64"; case EM_RISCV: return "EM_RISCV"; } snprintf(machdesc, sizeof(machdesc), "(unknown machine) -- type 0x%x", mach); return (machdesc); } static const char * elf_type_str(unsigned int type) { static char s_type[32]; switch (type) { case ET_NONE: return "ET_NONE"; case ET_REL: return "ET_REL"; case ET_EXEC: return "ET_EXEC"; case ET_DYN: return "ET_DYN"; case ET_CORE: return "ET_CORE"; } 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), "", ver); return (s_ver); } static const char * elf_class_str(unsigned int class) { static char s_class[32]; switch (class) { case ELFCLASSNONE: return "ELFCLASSNONE"; case ELFCLASS32: return "ELFCLASS32"; case ELFCLASS64: return "ELFCLASS64"; } snprintf(s_class, sizeof(s_class), "", class); return (s_class); } static const char * elf_data_str(unsigned int data) { static char s_data[32]; switch (data) { case ELFDATANONE: return "ELFDATANONE"; case ELFDATA2LSB: return "ELFDATA2LSB"; case ELFDATA2MSB: return "ELFDATA2MSB"; } snprintf(s_data, sizeof(s_data), "", data); return (s_data); } static const char *ei_abis[256] = { "ELFOSABI_NONE", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD", [17] = "ELFOSABI_CLOUDABI", [64] = "ELFOSABI_ARM_AEABI", [97] = "ELFOSABI_ARM", [255] = "ELFOSABI_STANDALONE" }; static const char * elf_phdr_type_str(unsigned int type) { static char s_type[32]; switch (type) { case PT_NULL: return "PT_NULL"; case PT_LOAD: return "PT_LOAD"; case PT_DYNAMIC: return "PT_DYNAMIC"; case PT_INTERP: return "PT_INTERP"; case PT_NOTE: return "PT_NOTE"; case PT_SHLIB: return "PT_SHLIB"; case PT_PHDR: return "PT_PHDR"; case PT_TLS: return "PT_TLS"; case PT_GNU_EH_FRAME: return "PT_GNU_EH_FRAME"; case PT_GNU_STACK: return "PT_GNU_STACK"; case PT_GNU_RELRO: return "PT_GNU_RELRO"; } snprintf(s_type, sizeof(s_type), "", type); return (s_type); } 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(uint64_t mach, uint64_t sht) { static char unknown_buf[64]; if (sht < 0x60000000) { switch (sht) { case SHT_NULL: return "SHT_NULL"; case SHT_PROGBITS: return "SHT_PROGBITS"; case SHT_SYMTAB: return "SHT_SYMTAB"; case SHT_STRTAB: return "SHT_STRTAB"; case SHT_RELA: return "SHT_RELA"; case SHT_HASH: return "SHT_HASH"; case SHT_DYNAMIC: return "SHT_DYNAMIC"; case SHT_NOTE: return "SHT_NOTE"; case SHT_NOBITS: return "SHT_NOBITS"; case SHT_REL: return "SHT_REL"; case SHT_SHLIB: return "SHT_SHLIB"; case SHT_DYNSYM: return "SHT_DYNSYM"; case SHT_INIT_ARRAY: return "SHT_INIT_ARRAY"; case SHT_FINI_ARRAY: return "SHT_FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "SHT_PREINIT_ARRAY"; case SHT_GROUP: return "SHT_GROUP"; case SHT_SYMTAB_SHNDX: return "SHT_SYMTAB_SHNDX"; } } else if (sht < 0x70000000) { /* 0x60000000-0x6fffffff operating system-specific semantics */ switch (sht) { case 0x6ffffff0: return "XXX:VERSYM"; case SHT_SUNW_dof: return "SHT_SUNW_dof"; case SHT_GNU_HASH: return "SHT_GNU_HASH"; case 0x6ffffff7: return "SHT_GNU_LIBLIST"; case 0x6ffffffc: return "XXX:VERDEF"; case SHT_SUNW_verdef: return "SHT_SUNW(GNU)_verdef"; case SHT_SUNW_verneed: return "SHT_SUNW(GNU)_verneed"; case SHT_SUNW_versym: return "SHT_SUNW(GNU)_versym"; } } else if (sht < 0x80000000) { /* 0x70000000 - 0x7fffffff processor-specific semantics */ switch (mach) { case EM_ARM: switch (sht) { case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX"; case SHT_ARM_PREEMPTMAP: return "SHT_ARM_PREEMPTMAP"; case SHT_ARM_ATTRIBUTES: return "SHT_ARM_ATTRIBUTES"; case SHT_ARM_DEBUGOVERLAY: return "SHT_ARM_DEBUGOVERLAY"; case SHT_ARM_OVERLAYSECTION: return "SHT_ARM_OVERLAYSECTION"; } break; case EM_IA_64: switch (sht) { case 0x70000000: return "SHT_IA_64_EXT"; case 0x70000001: return "SHT_IA_64_UNWIND"; } break; case EM_MIPS: switch (sht) { case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO"; case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS"; case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS"; } break; } switch (sht) { case 0x7ffffffd: return "XXX:AUXILIARY"; case 0x7fffffff: return "XXX:FILTER"; } } /* 0x80000000 - 0xffffffff application programs */ snprintf(unknown_buf, sizeof(unknown_buf), "", (unsigned long long)sht); return (unknown_buf); } /* * 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) \ DEFINE_SHF(COMPRESSED) #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_type(unsigned int mach, unsigned int type) { static char s_type[32]; switch (type) { case STT_NOTYPE: return "STT_NOTYPE"; case STT_OBJECT: return "STT_OBJECT"; case STT_FUNC: return "STT_FUNC"; case STT_SECTION: return "STT_SECTION"; case STT_FILE: return "STT_FILE"; case STT_COMMON: return "STT_COMMON"; case STT_TLS: return "STT_TLS"; case 13: if (mach == EM_SPARCV9) return "STT_SPARC_REGISTER"; break; } snprintf(s_type, sizeof(s_type), "", type); return (s_type); } static const char * st_type_S(unsigned int type) { static char s_type[32]; switch (type) { case STT_NOTYPE: return "NOTY"; case STT_OBJECT: return "OBJT"; case STT_FUNC: return "FUNC"; case STT_SECTION: return "SECT"; case STT_FILE: return "FILE"; } snprintf(s_type, sizeof(s_type), "", type); return (s_type); } static const char * st_bindings(unsigned int sbind) { static char s_sbind[32]; switch (sbind) { case STB_LOCAL: return "STB_LOCAL"; case STB_GLOBAL: return "STB_GLOBAL"; case STB_WEAK: return "STB_WEAK"; case STB_GNU_UNIQUE: return "STB_GNU_UNIQUE"; 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_bindings_S(unsigned int sbind) { static char s_sbind[32]; switch (sbind) { case STB_LOCAL: return "LOCL"; case STB_GLOBAL: return "GLOB"; case STB_WEAK: return "WEAK"; case STB_GNU_UNIQUE: return "UNIQ"; 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), "<%#x>", sbind); return (s_sbind); } } static unsigned char st_others[] = { 'D', 'I', 'H', 'P' }; 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 int get_ent_count(const struct section *s, int *ent_count); static const char *get_symbol_name(struct elfdump *ed, uint32_t 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++) { 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, i; int 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; i < cnt; i++) { arsym[i].off = be32dec(b); b += sizeof(uint32_t); } for (i = 0; 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; 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, 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; 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), "[%zu]", 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: %zu\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, uint32_t symtab, int i) { static char sname[64]; struct section *s; const char *name; GElf_Sym sym; Elf_Data *data; int elferr; if (symtab >= ed->shnum) return (""); 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", elf_class_str(ed->ehdr.e_ident[EI_CLASS])); PRT(" ei_data: %s\n", elf_data_str(ed->ehdr.e_ident[EI_DATA])); PRT(" e_machine: %-18s", e_machines(ed->ehdr.e_machine)); PRT(" e_version: %s\n", elf_version_str(ed->ehdr.e_version)); PRT(" e_type: %s\n", elf_type_str(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", elf_class_str(ed->ehdr.e_ident[EI_CLASS]), elf_data_str(ed->ehdr.e_ident[EI_DATA]), ei_abis[ed->ehdr.e_ident[EI_OSABI]]); PRT("\te_type: %s\n", elf_type_str(ed->ehdr.e_type)); PRT("\te_machine: %s\n", e_machines(ed->ehdr.e_machine)); PRT("\te_version: %s\n", elf_version_str(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, i; int header; if (elf_getphnum(ed->elf, &phnum) == 0) { warnx("elf_getphnum failed: %s", elf_errmsg(-1)); return; } header = 0; for (i = 0; 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, elf_phdr_type_str(ph.p_type)) == NULL) continue; if (ed->flags & SOLARIS_FMT) { PRT("\nProgram Header[%zu]:\n", i); PRT(" p_vaddr: %#-14jx", (uintmax_t)ph.p_vaddr); PRT(" p_flags: [ %s ]\n", p_flags[ph.p_flags & 0x7]); PRT(" p_paddr: %#-14jx", (uintmax_t)ph.p_paddr); PRT(" p_type: [ %s ]\n", elf_phdr_type_str(ph.p_type)); 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: %zu\n", i); PRT("\tp_type: %s\n", elf_phdr_type_str(ph.p_type)); 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 & 0x7]); 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; size_t i; if (!STAILQ_EMPTY(&ed->snl)) return; if ((ed->flags & SOLARIS_FMT) == 0) PRT("\nsection header:\n"); for (i = 0; i < ed->shnum; i++) { s = &ed->sl[i]; if (ed->flags & SOLARIS_FMT) { if (i == 0) continue; PRT("\nSection Header[%zu]:", 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(ed->ehdr.e_machine, 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(ed->ehdr.e_machine, 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); } } } /* * Return number of entries in the given section. We'd prefer ent_count be a * size_t, but libelf APIs already use int for section indices. */ static int get_ent_count(const struct section *s, int *ent_count) { if (s->entsize == 0) { warnx("section %s has entry size 0", s->name); return (0); } else if (s->sz / s->entsize > INT_MAX) { warnx("section %s has invalid section count", s->name); return (0); } *ent_count = (int)(s->sz / s->entsize); return (1); } /* * 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; size_t j; int elferr; s = NULL; for (j = 0; j < ed->shnum; j++) { s = &ed->sl[j]; if (s->type == SHT_SUNW_versym && s->link == (uint32_t)i) break; } if (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; assert(data->d_size == s->sz); if (!get_ent_count(s, nvs)) *nvs = 0; } /* * 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; assert(data->d_size == s->sz); if (!get_ent_count(s, &len)) return; 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_type_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_type(ed->ehdr.e_machine, 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) { size_t i; for (i = 0; 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; } assert(data->d_size == s->sz); if (!get_ent_count(s, &len)) return; 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: case DT_RUNPATH: 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 ", elftc_reloc_type_str(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; assert(data->d_size == s->sz); if (!get_ent_count(s, &len)) return; 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; assert(data->d_size == s->sz); if (!get_ent_count(s, &len)) return; 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; size_t i; int elferr; for (i = 0; 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 filesize, i, phnum; if (!STAILQ_EMPTY(&ed->snl) && find_name(ed, "PT_INTERP") == NULL) return; if ((s = elf_rawfile(ed->elf, &filesize)) == 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; 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) { if (phdr.p_offset >= filesize) { warnx("invalid phdr offset"); continue; } PRT("\ninterp:\n"); PRT("\t%s\n", s + phdr.p_offset); } } } /* * Search the relocation sections for entries referring 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; size_t i; int elferr, j, k, len; for(i = 0; 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; assert(data->d_size == s->sz); if (!get_ent_count(s, &len)) return; 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 (!get_ent_count(s, &len)) return; if (ed->flags & SOLARIS_FMT) PRT("\nGlobal Offset Table Section: %s (%d entries)\n", s->name, len); 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 perform 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; } assert(dst.d_size == s->sz); 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 ", (uintmax_t) (s->addr + i * s->entsize)); PRT("%-8.8x ", *((uint32_t *)dst.d_buf + i)); } else { PRT("%-16.16jx ", (uintmax_t) (s->addr + i * s->entsize)); PRT("%-16.16jx ", (uintmax_t) *((uint64_t *)dst.d_buf + i)); } PRT("%-18s ", elftc_reloc_type_str(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", (uintmax_t) *((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; size_t i; if (!STAILQ_EMPTY(&ed->snl)) return; s = NULL; for (i = 0; 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; uint8_t *src; char 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 (roundup2(namesz, 4) + roundup2(descsz, 4) > count) { warnx("truncated note section"); return; } 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; uint32_t i, j; int 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 != ((uint64_t)nbucket + (uint64_t)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; i < nbucket; i++) for (j = bucket[i]; j > 0 && 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; i < nbucket; i++) c[bl[i]]++; PRT(" bucket symndx name\n"); for (i = 0; i < nbucket; i++) { first = 1; for (j = bucket[i]; j > 0 && 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; 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; i < nbucket; i++) PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]); for (i = 0; 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; uint64_t i, j; int 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; i < nbucket; i++) for (j = bucket[i]; j > 0 && 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; i < nbucket; i++) c[bl[i]]++; PRT(" bucket symndx name\n"); for (i = 0; i < nbucket; i++) { first = 1; for (j = bucket[i]; j > 0 && j < nchain; j = chain[j]) { if (first) { PRT("%10zu ", i); first = 0; } else PRT(" "); snprintf(idx, sizeof(idx), "[%zu]", (size_t)j); PRT("%-10s ", idx); PRT("%s\n", get_symbol_name(ed, s->link, j)); } } PRT("\n"); total = 0; for (i = 0; i <= maxl; i++) { total += c[i] * i; PRT("%10ju buckets contain %8zu 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; i < nbucket; i++) PRT("bucket[%zu]:\n\t%ju\n\n", i, (uintmax_t)bucket[i]); for (i = 0; i < nchain; i++) PRT("chain[%zu]:\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; uint32_t i, j; int 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; if (s->link >= ed->shnum) { warnx("Malformed .gnu.hash section"); return; } ds = &ed->sl[s->link]; if (!get_ent_count(ds, &dynsymcount)) return; if (symndx >= (uint32_t)dynsymcount) { warnx("Malformed .gnu.hash section"); return; } nchain = dynsymcount - symndx; if (data->d_size != 4 * sizeof(uint32_t) + maskwords * (ed->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) + ((uint64_t)nbucket + (uint64_t)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; i < nbucket; i++) for (j = bucket[i]; j > 0 && 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; i < nbucket; i++) c[bl[i]]++; PRT(" bucket symndx name\n"); for (i = 0; i < nbucket; i++) { first = 1; for (j = bucket[i]; j > 0 && 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; 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; i < nbucket; i++) PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]); for (i = 0; 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; size_t i; for (i = 0; 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; size_t i; for (i = 0; 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/libdwarf/dwarf.h =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf.h (revision 317072) +++ vendor/elftoolchain/dist/libdwarf/dwarf.h (revision 317073) @@ -1,599 +1,634 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *notice, this list of conditions and the following disclaimer in the *documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dwarf.h 3052 2014-05-26 20:36:24Z kaiwang27 $ + * $Id: dwarf.h 3494 2016-09-20 17:16:13Z emaste $ */ #ifndef _DWARF_H_ #define _DWARF_H_ #define DW_TAG_array_type 0x01 #define DW_TAG_class_type 0x02 #define DW_TAG_entry_point 0x03 #define DW_TAG_enumeration_type 0x04 #define DW_TAG_formal_parameter 0x05 #define DW_TAG_imported_declaration 0x08 #define DW_TAG_label 0x0a #define DW_TAG_lexical_block 0x0b #define DW_TAG_member 0x0d #define DW_TAG_pointer_type 0x0f #define DW_TAG_reference_type 0x10 #define DW_TAG_compile_unit 0x11 #define DW_TAG_string_type 0x12 #define DW_TAG_structure_type 0x13 #define DW_TAG_subroutine_type 0x15 #define DW_TAG_typedef 0x16 #define DW_TAG_union_type 0x17 #define DW_TAG_unspecified_parameters 0x18 #define DW_TAG_variant 0x19 #define DW_TAG_common_block 0x1a #define DW_TAG_common_inclusion 0x1b #define DW_TAG_inheritance 0x1c #define DW_TAG_inlined_subroutine 0x1d #define DW_TAG_module 0x1e #define DW_TAG_ptr_to_member_type 0x1f #define DW_TAG_set_type 0x20 #define DW_TAG_subrange_type 0x21 #define DW_TAG_with_stmt 0x22 #define DW_TAG_access_declaration 0x23 #define DW_TAG_base_type 0x24 #define DW_TAG_catch_block 0x25 #define DW_TAG_const_type 0x26 #define DW_TAG_constant 0x27 #define DW_TAG_enumerator 0x28 #define DW_TAG_friend 0x2a #define DW_TAG_namelist 0x2b #define DW_TAG_namelist_item 0x2c #define DW_TAG_packed_type 0x2d #define DW_TAG_subprogram 0x2e #define DW_TAG_template_type_parameter 0x2f #define DW_TAG_template_type_param 0x2f #define DW_TAG_template_value_parameter 0x30 #define DW_TAG_template_value_param 0x30 #define DW_TAG_thrown_type 0x31 #define DW_TAG_try_block 0x32 #define DW_TAG_variant_part 0x33 #define DW_TAG_variable 0x34 #define DW_TAG_volatile_type 0x35 #define DW_TAG_dwarf_procedure 0x36 #define DW_TAG_restrict_type 0x37 #define DW_TAG_interface_type 0x38 #define DW_TAG_namespace 0x39 #define DW_TAG_imported_module 0x3a #define DW_TAG_unspecified_type 0x3b #define DW_TAG_partial_unit 0x3c #define DW_TAG_imported_unit 0x3d #define DW_TAG_condition 0x3f #define DW_TAG_shared_type 0x40 #define DW_TAG_type_unit 0x41 #define DW_TAG_rvalue_reference_type 0x42 #define DW_TAG_template_alias 0x43 #define DW_TAG_lo_user 0x4080 #define DW_TAG_hi_user 0xffff /* GNU extensions. */ #define DW_TAG_format_label 0x4101 #define DW_TAG_function_template 0x4102 #define DW_TAG_class_template 0x4103 #define DW_TAG_GNU_BINCL 0x4104 #define DW_TAG_GNU_EINCL 0x4105 #define DW_TAG_GNU_template_template_parameter 0x4106 #define DW_TAG_GNU_template_template_param 0x4106 #define DW_TAG_GNU_template_parameter_pack 0x4107 #define DW_TAG_GNU_formal_parameter_pack 0x4108 #define DW_TAG_GNU_call_site 0x4109 #define DW_TAG_GNU_call_site_parameter 0x410a #define DW_CHILDREN_no 0x00 #define DW_CHILDREN_yes 0x01 #define DW_AT_sibling 0x01 #define DW_AT_location 0x02 #define DW_AT_name 0x03 #define DW_AT_ordering 0x09 #define DW_AT_subscr_data 0x0a #define DW_AT_byte_size 0x0b #define DW_AT_bit_offset 0x0c #define DW_AT_bit_size 0x0d #define DW_AT_element_list 0x0f #define DW_AT_stmt_list 0x10 #define DW_AT_low_pc 0x11 #define DW_AT_high_pc 0x12 #define DW_AT_language 0x13 #define DW_AT_member 0x14 #define DW_AT_discr 0x15 #define DW_AT_discr_value 0x16 #define DW_AT_visibility 0x17 #define DW_AT_import 0x18 #define DW_AT_string_length 0x19 #define DW_AT_common_reference 0x1a #define DW_AT_comp_dir 0x1b #define DW_AT_const_value 0x1c #define DW_AT_containing_type 0x1d #define DW_AT_default_value 0x1e #define DW_AT_inline 0x20 #define DW_AT_is_optional 0x21 #define DW_AT_lower_bound 0x22 #define DW_AT_producer 0x25 #define DW_AT_prototyped 0x27 #define DW_AT_return_addr 0x2a #define DW_AT_start_scope 0x2c #define DW_AT_bit_stride 0x2e #define DW_AT_stride_size 0x2e #define DW_AT_upper_bound 0x2f #define DW_AT_abstract_origin 0x31 #define DW_AT_accessibility 0x32 #define DW_AT_address_class 0x33 #define DW_AT_artificial 0x34 #define DW_AT_base_types 0x35 #define DW_AT_calling_convention 0x36 #define DW_AT_count 0x37 #define DW_AT_data_member_location 0x38 #define DW_AT_decl_column 0x39 #define DW_AT_decl_file 0x3a #define DW_AT_decl_line 0x3b #define DW_AT_declaration 0x3c #define DW_AT_discr_list 0x3d #define DW_AT_encoding 0x3e #define DW_AT_external 0x3f #define DW_AT_frame_base 0x40 #define DW_AT_friend 0x41 #define DW_AT_identifier_case 0x42 #define DW_AT_macro_info 0x43 #define DW_AT_namelist_item 0x44 #define DW_AT_priority 0x45 #define DW_AT_segment 0x46 #define DW_AT_specification 0x47 #define DW_AT_static_link 0x48 #define DW_AT_type 0x49 #define DW_AT_use_location 0x4a #define DW_AT_variable_parameter 0x4b #define DW_AT_virtuality 0x4c #define DW_AT_vtable_elem_location 0x4d #define DW_AT_allocated 0x4e #define DW_AT_associated 0x4f #define DW_AT_data_location 0x50 #define DW_AT_byte_stride 0x51 #define DW_AT_entry_pc 0x52 #define DW_AT_use_UTF8 0x53 #define DW_AT_extension 0x54 #define DW_AT_ranges 0x55 #define DW_AT_trampoline 0x56 #define DW_AT_call_column 0x57 #define DW_AT_call_file 0x58 #define DW_AT_call_line 0x59 #define DW_AT_description 0x5a #define DW_AT_binary_scale 0x5b #define DW_AT_decimal_scale 0x5c #define DW_AT_small 0x5d #define DW_AT_decimal_sign 0x5e #define DW_AT_digit_count 0x5f #define DW_AT_picture_string 0x60 #define DW_AT_mutable 0x61 #define DW_AT_threads_scaled 0x62 #define DW_AT_explicit 0x63 #define DW_AT_object_pointer 0x64 #define DW_AT_endianity 0x65 #define DW_AT_elemental 0x66 #define DW_AT_pure 0x67 #define DW_AT_recursive 0x68 #define DW_AT_signature 0x69 #define DW_AT_main_subprogram 0x6a #define DW_AT_data_bit_offset 0x6b #define DW_AT_const_expr 0x6c #define DW_AT_enum_class 0x6d #define DW_AT_linkage_name 0x6e #define DW_AT_lo_user 0x2000 #define DW_AT_hi_user 0x3fff +/* SGI/MIPS extensions. */ +#define DW_AT_MIPS_fde 0x2001 +#define DW_AT_MIPS_loop_begin 0x2002 +#define DW_AT_MIPS_tail_loop_begin 0x2003 +#define DW_AT_MIPS_epilog_begin 0x2004 +#define DW_AT_MIPS_loop_unroll_factor 0x2005 +#define DW_AT_MIPS_software_pipeline_depth 0x2006 +#define DW_AT_MIPS_linkage_name 0x2007 +#define DW_AT_MIPS_stride 0x2008 +#define DW_AT_MIPS_abstract_name 0x2009 +#define DW_AT_MIPS_clone_origin 0x200a +#define DW_AT_MIPS_has_inlines 0x200b +#define DW_AT_MIPS_stride_byte 0x200c +#define DW_AT_MIPS_stride_elem 0x200d +#define DW_AT_MIPS_ptr_dopetype 0x200e +#define DW_AT_MIPS_allocatable_dopetype 0x200f +#define DW_AT_MIPS_assumed_shape_dopetype 0x2010 +#define DW_AT_MIPS_assumed_size 0x2011 + /* GNU extensions. */ #define DW_AT_sf_names 0x2101 #define DW_AT_src_info 0x2102 #define DW_AT_mac_info 0x2103 #define DW_AT_src_coords 0x2104 #define DW_AT_body_begin 0x2105 #define DW_AT_body_end 0x2106 #define DW_AT_GNU_vector 0x2107 #define DW_AT_GNU_guarded_by 0x2108 #define DW_AT_GNU_pt_guarded_by 0x2109 #define DW_AT_GNU_guarded 0x210a #define DW_AT_GNU_pt_guarded 0x210b #define DW_AT_GNU_locks_excluded 0x210c #define DW_AT_GNU_exclusive_locks_required 0x210d #define DW_AT_GNU_shared_locks_required 0x210e #define DW_AT_GNU_odr_signature 0x210f #define DW_AT_GNU_template_name 0x2110 #define DW_AT_GNU_call_site_value 0x2111 #define DW_AT_GNU_call_site_data_value 0x2112 #define DW_AT_GNU_call_site_target 0x2113 #define DW_AT_GNU_call_site_target_clobbered 0x2114 #define DW_AT_GNU_tail_call 0x2115 #define DW_AT_GNU_all_tail_call_sites 0x2116 #define DW_AT_GNU_all_call_sites 0x2117 #define DW_AT_GNU_all_source_call_sites 0x2118 +/* Apple extensions. */ +#define DW_AT_APPLE_optimized 0x3fe1 +#define DW_AT_APPLE_flags 0x3fe2 +#define DW_AT_APPLE_isa 0x3fe3 +#define DW_AT_APPLE_block 0x3fe4 +#define DW_AT_APPLE_major_runtime_vers 0x3fe5 +#define DW_AT_APPLE_runtime_class 0x3fe6 +#define DW_AT_APPLE_omit_frame_ptr 0x3fe7 +#define DW_AT_APPLE_property_name 0x3fe8 +#define DW_AT_APPLE_property_getter 0x3fe9 +#define DW_AT_APPLE_property_setter 0x3fea +#define DW_AT_APPLE_property_attribute 0x3feb +#define DW_AT_APPLE_objc_complete_type 0x3fec +#define DW_AT_APPLE_property 0x3fed + #define DW_FORM_addr 0x01 #define DW_FORM_block2 0x03 #define DW_FORM_block4 0x04 #define DW_FORM_data2 0x05 #define DW_FORM_data4 0x06 #define DW_FORM_data8 0x07 #define DW_FORM_string 0x08 #define DW_FORM_block 0x09 #define DW_FORM_block1 0x0a #define DW_FORM_data1 0x0b #define DW_FORM_flag 0x0c #define DW_FORM_sdata 0x0d #define DW_FORM_strp 0x0e #define DW_FORM_udata 0x0f #define DW_FORM_ref_addr 0x10 #define DW_FORM_ref1 0x11 #define DW_FORM_ref2 0x12 #define DW_FORM_ref4 0x13 #define DW_FORM_ref8 0x14 #define DW_FORM_ref_udata 0x15 #define DW_FORM_indirect 0x16 #define DW_FORM_sec_offset 0x17 #define DW_FORM_exprloc 0x18 #define DW_FORM_flag_present 0x19 #define DW_FORM_ref_sig8 0x20 #define DW_FORM_GNU_ref_alt 0x1f20 #define DW_FORM_GNU_strp_alt 0x1f21 #define DW_OP_addr 0x03 #define DW_OP_deref 0x06 #define DW_OP_const1u 0x08 #define DW_OP_const1s 0x09 #define DW_OP_const2u 0x0a #define DW_OP_const2s 0x0b #define DW_OP_const4u 0x0c #define DW_OP_const4s 0x0d #define DW_OP_const8u 0x0e #define DW_OP_const8s 0x0f #define DW_OP_constu 0x10 #define DW_OP_consts 0x11 #define DW_OP_dup 0x12 #define DW_OP_drop 0x13 #define DW_OP_over 0x14 #define DW_OP_pick 0x15 #define DW_OP_swap 0x16 #define DW_OP_rot 0x17 #define DW_OP_xderef 0x18 #define DW_OP_abs 0x19 #define DW_OP_and 0x1a #define DW_OP_div 0x1b #define DW_OP_minus 0x1c #define DW_OP_mod 0x1d #define DW_OP_mul 0x1e #define DW_OP_neg 0x1f #define DW_OP_not 0x20 #define DW_OP_or 0x21 #define DW_OP_plus 0x22 #define DW_OP_plus_uconst 0x23 #define DW_OP_shl 0x24 #define DW_OP_shr 0x25 #define DW_OP_shra 0x26 #define DW_OP_xor 0x27 #define DW_OP_bra 0x28 #define DW_OP_eq 0x29 #define DW_OP_ge 0x2a #define DW_OP_gt 0x2b #define DW_OP_le 0x2c #define DW_OP_lt 0x2d #define DW_OP_ne 0x2e #define DW_OP_skip 0x2f #define DW_OP_lit0 0x30 #define DW_OP_lit1 0x31 #define DW_OP_lit2 0x32 #define DW_OP_lit3 0x33 #define DW_OP_lit4 0x34 #define DW_OP_lit5 0x35 #define DW_OP_lit6 0x36 #define DW_OP_lit7 0x37 #define DW_OP_lit8 0x38 #define DW_OP_lit9 0x39 #define DW_OP_lit10 0x3a #define DW_OP_lit11 0x3b #define DW_OP_lit12 0x3c #define DW_OP_lit13 0x3d #define DW_OP_lit14 0x3e #define DW_OP_lit15 0x3f #define DW_OP_lit16 0x40 #define DW_OP_lit17 0x41 #define DW_OP_lit18 0x42 #define DW_OP_lit19 0x43 #define DW_OP_lit20 0x44 #define DW_OP_lit21 0x45 #define DW_OP_lit22 0x46 #define DW_OP_lit23 0x47 #define DW_OP_lit24 0x48 #define DW_OP_lit25 0x49 #define DW_OP_lit26 0x4a #define DW_OP_lit27 0x4b #define DW_OP_lit28 0x4c #define DW_OP_lit29 0x4d #define DW_OP_lit30 0x4e #define DW_OP_lit31 0x4f #define DW_OP_reg0 0x50 #define DW_OP_reg1 0x51 #define DW_OP_reg2 0x52 #define DW_OP_reg3 0x53 #define DW_OP_reg4 0x54 #define DW_OP_reg5 0x55 #define DW_OP_reg6 0x56 #define DW_OP_reg7 0x57 #define DW_OP_reg8 0x58 #define DW_OP_reg9 0x59 #define DW_OP_reg10 0x5a #define DW_OP_reg11 0x5b #define DW_OP_reg12 0x5c #define DW_OP_reg13 0x5d #define DW_OP_reg14 0x5e #define DW_OP_reg15 0x5f #define DW_OP_reg16 0x60 #define DW_OP_reg17 0x61 #define DW_OP_reg18 0x62 #define DW_OP_reg19 0x63 #define DW_OP_reg20 0x64 #define DW_OP_reg21 0x65 #define DW_OP_reg22 0x66 #define DW_OP_reg23 0x67 #define DW_OP_reg24 0x68 #define DW_OP_reg25 0x69 #define DW_OP_reg26 0x6a #define DW_OP_reg27 0x6b #define DW_OP_reg28 0x6c #define DW_OP_reg29 0x6d #define DW_OP_reg30 0x6e #define DW_OP_reg31 0x6f #define DW_OP_breg0 0x70 #define DW_OP_breg1 0x71 #define DW_OP_breg2 0x72 #define DW_OP_breg3 0x73 #define DW_OP_breg4 0x74 #define DW_OP_breg5 0x75 #define DW_OP_breg6 0x76 #define DW_OP_breg7 0x77 #define DW_OP_breg8 0x78 #define DW_OP_breg9 0x79 #define DW_OP_breg10 0x7a #define DW_OP_breg11 0x7b #define DW_OP_breg12 0x7c #define DW_OP_breg13 0x7d #define DW_OP_breg14 0x7e #define DW_OP_breg15 0x7f #define DW_OP_breg16 0x80 #define DW_OP_breg17 0x81 #define DW_OP_breg18 0x82 #define DW_OP_breg19 0x83 #define DW_OP_breg20 0x84 #define DW_OP_breg21 0x85 #define DW_OP_breg22 0x86 #define DW_OP_breg23 0x87 #define DW_OP_breg24 0x88 #define DW_OP_breg25 0x89 #define DW_OP_breg26 0x8a #define DW_OP_breg27 0x8b #define DW_OP_breg28 0x8c #define DW_OP_breg29 0x8d #define DW_OP_breg30 0x8e #define DW_OP_breg31 0x8f #define DW_OP_regx 0x90 #define DW_OP_fbreg 0x91 #define DW_OP_bregx 0x92 #define DW_OP_piece 0x93 #define DW_OP_deref_size 0x94 #define DW_OP_xderef_size 0x95 #define DW_OP_nop 0x96 #define DW_OP_push_object_address 0x97 #define DW_OP_call2 0x98 #define DW_OP_call4 0x99 #define DW_OP_call_ref 0x9a #define DW_OP_form_tls_address 0x9b #define DW_OP_call_frame_cfa 0x9c #define DW_OP_bit_piece 0x9d #define DW_OP_implicit_value 0x9e #define DW_OP_stack_value 0x9f #define DW_OP_lo_user 0xe0 #define DW_OP_hi_user 0xff /* GNU extensions. */ #define DW_OP_GNU_push_tls_address 0xe0 #define DW_OP_GNU_uninit 0xf0 #define DW_OP_GNU_encoded_addr 0xf1 #define DW_OP_GNU_implicit_pointer 0xf2 #define DW_OP_GNU_entry_value 0xf3 #define DW_OP_GNU_const_type 0xf4 #define DW_OP_GNU_regval_type 0xf5 #define DW_OP_GNU_deref_type 0xf6 #define DW_OP_GNU_convert 0xf7 #define DW_OP_GNU_reinterpret 0xf9 #define DW_OP_GNU_parameter_ref 0xfa #define DW_OP_GNU_addr_index 0xfb #define DW_OP_GNU_const_index 0xfc #define DW_ATE_address 0x1 #define DW_ATE_boolean 0x2 #define DW_ATE_complex_float 0x3 #define DW_ATE_float 0x4 #define DW_ATE_signed 0x5 #define DW_ATE_signed_char 0x6 #define DW_ATE_unsigned 0x7 #define DW_ATE_unsigned_char 0x8 #define DW_ATE_imaginary_float 0x9 #define DW_ATE_packed_decimal 0xa #define DW_ATE_numeric_string 0xb #define DW_ATE_edited 0xc #define DW_ATE_signed_fixed 0xd #define DW_ATE_unsigned_fixed 0xe #define DW_ATE_decimal_float 0xf #define DW_ATE_lo_user 0x80 #define DW_ATE_hi_user 0xff #define DW_ACCESS_public 0x01 #define DW_ACCESS_protected 0x02 #define DW_ACCESS_private 0x03 #define DW_END_default 0x00 #define DW_END_big 0x01 #define DW_END_little 0x02 #define DW_END_lo_user 0x40 #define DW_END_high_user 0xff #define DW_VIS_local 0x01 #define DW_VIS_exported 0x02 #define DW_VIS_qualified 0x03 #define DW_VIRTUALITY_none 0x00 #define DW_VIRTUALITY_virtual 0x01 #define DW_VIRTUALITY_pure_virtual 0x02 #define DW_LANG_C89 0x0001 #define DW_LANG_C 0x0002 #define DW_LANG_Ada83 0x0003 #define DW_LANG_C_plus_plus 0x0004 #define DW_LANG_Cobol74 0x0005 #define DW_LANG_Cobol85 0x0006 #define DW_LANG_Fortran77 0x0007 #define DW_LANG_Fortran90 0x0008 #define DW_LANG_Pascal83 0x0009 #define DW_LANG_Modula2 0x000a #define DW_LANG_Java 0x000b #define DW_LANG_C99 0x000c #define DW_LANG_Ada95 0x000d #define DW_LANG_Fortran95 0x000e #define DW_LANG_PLI 0x000f #define DW_LANG_ObjC 0x0010 #define DW_LANG_ObjC_plus_plus 0x0011 #define DW_LANG_UPC 0x0012 #define DW_LANG_D 0x0013 #define DW_LANG_lo_user 0x8000 +#define DW_LANG_Mips_Assembler 0x8001 #define DW_LANG_hi_user 0xffff #define DW_ID_case_sensitive 0x00 #define DW_ID_up_case 0x01 #define DW_ID_down_case 0x02 #define DW_ID_case_insensitive 0x03 #define DW_CC_normal 0x01 #define DW_CC_program 0x02 #define DW_CC_nocall 0x03 #define DW_CC_lo_user 0x40 #define DW_CC_hi_user 0xff #define DW_INL_not_inlined 0x00 #define DW_INL_inlined 0x01 #define DW_INL_declared_not_inlined 0x02 #define DW_INL_declared_inlined 0x03 #define DW_ORD_row_major 0x00 #define DW_ORD_col_major 0x01 #define DW_DS_unsigned 0x01 #define DW_DS_leading_overpunch 0x02 #define DW_DS_trailing_overpunch 0x03 #define DW_DS_leading_separate 0x04 #define DW_DS_trailing_separate 0x05 #define DW_DSC_label 0x00 #define DW_DSC_range 0x01 #define DW_LNS_copy 0x01 #define DW_LNS_advance_pc 0x02 #define DW_LNS_advance_line 0x03 #define DW_LNS_set_file 0x04 #define DW_LNS_set_column 0x05 #define DW_LNS_negate_stmt 0x06 #define DW_LNS_set_basic_block 0x07 #define DW_LNS_const_add_pc 0x08 #define DW_LNS_fixed_advance_pc 0x09 #define DW_LNS_set_prologue_end 0x0a #define DW_LNS_set_epilogue_begin 0x0b #define DW_LNS_set_isa 0x0c #define DW_LNE_end_sequence 0x01 #define DW_LNE_set_address 0x02 #define DW_LNE_define_file 0x03 #define DW_LNE_lo_user 0x80 #define DW_LNE_hi_user 0xff #define DW_MACINFO_define 0x01 #define DW_MACINFO_undef 0x02 #define DW_MACINFO_start_file 0x03 #define DW_MACINFO_end_file 0x04 #define DW_MACINFO_vendor_ext 0xff #define DW_CFA_advance_loc 0x40 #define DW_CFA_offset 0x80 #define DW_CFA_restore 0xc0 #define DW_CFA_extended 0 #define DW_CFA_nop 0x00 #define DW_CFA_set_loc 0x01 #define DW_CFA_advance_loc1 0x02 #define DW_CFA_advance_loc2 0x03 #define DW_CFA_advance_loc4 0x04 #define DW_CFA_offset_extended 0x05 #define DW_CFA_restore_extended 0x06 #define DW_CFA_undefined 0x07 #define DW_CFA_same_value 0x08 #define DW_CFA_register 0x09 #define DW_CFA_remember_state 0x0a #define DW_CFA_restore_state 0x0b #define DW_CFA_def_cfa 0x0c #define DW_CFA_def_cfa_register 0x0d #define DW_CFA_def_cfa_offset 0x0e #define DW_CFA_def_cfa_expression 0x0f #define DW_CFA_expression 0x10 #define DW_CFA_offset_extended_sf 0x11 #define DW_CFA_def_cfa_sf 0x12 #define DW_CFA_def_cfa_offset_sf 0x13 #define DW_CFA_val_offset 0x14 #define DW_CFA_val_offset_sf 0x15 #define DW_CFA_val_expression 0x16 #define DW_CFA_lo_user 0x1c #define DW_CFA_high_user 0x3f /* * LSB(Linux Standard Base) extension to DWARF2. */ #define DW_EH_PE_absptr 0x00 #define DW_EH_PE_uleb128 0x01 #define DW_EH_PE_udata2 0x02 #define DW_EH_PE_udata4 0x03 #define DW_EH_PE_udata8 0x04 #define DW_EH_PE_sleb128 0x09 #define DW_EH_PE_sdata2 0x0a #define DW_EH_PE_sdata4 0x0b #define DW_EH_PE_sdata8 0x0c #define DW_EH_PE_pcrel 0x10 #define DW_EH_PE_textrel 0x20 #define DW_EH_PE_datarel 0x30 #define DW_EH_PE_funcrel 0x40 #define DW_EH_PE_aligned 0x50 #define DW_EH_PE_omit 0xff #endif /* !_DWARF_H_ */ Index: vendor/elftoolchain/dist/libdwarf/dwarf_attrval.c =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_attrval.c (revision 317072) +++ vendor/elftoolchain/dist/libdwarf/dwarf_attrval.c (revision 317073) @@ -1,212 +1,222 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_attrval.c 3159 2015-02-15 21:43:27Z emaste $"); +ELFTC_VCSID("$Id: dwarf_attrval.c 3509 2016-12-29 03:58:41Z emaste $"); int dwarf_attrval_flag(Dwarf_Die die, Dwarf_Half attr, Dwarf_Bool *valp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || valp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *valp = 0; if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_flag: case DW_FORM_flag_present: *valp = (Dwarf_Bool) (!!at->u[0].u64); break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } return (DW_DLV_OK); } int dwarf_attrval_string(Dwarf_Die die, Dwarf_Half attr, const char **strp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || strp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *strp = NULL; if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_strp: *strp = at->u[1].s; break; case DW_FORM_string: *strp = at->u[0].s; break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } return (DW_DLV_OK); } int dwarf_attrval_signed(Dwarf_Die die, Dwarf_Half attr, Dwarf_Signed *valp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Debug dbg; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || valp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *valp = 0; if ((at = _dwarf_attr_find(die, attr)) == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_data1: *valp = (int8_t) at->u[0].s64; break; case DW_FORM_data2: *valp = (int16_t) at->u[0].s64; break; case DW_FORM_data4: *valp = (int32_t) at->u[0].s64; break; case DW_FORM_data8: case DW_FORM_sdata: *valp = at->u[0].s64; break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } return (DW_DLV_OK); } int dwarf_attrval_unsigned(Dwarf_Die die, Dwarf_Half attr, Dwarf_Unsigned *valp, Dwarf_Error *err) { Dwarf_Attribute at; Dwarf_Die die1; Dwarf_Unsigned val; Dwarf_Debug dbg; + int first; dbg = die != NULL ? die->die_dbg : NULL; if (die == NULL || valp == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT); return (DW_DLV_ERROR); } *valp = 0; - if ((at = _dwarf_attr_find(die, attr)) == NULL && attr != DW_AT_type) { - DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); - return (DW_DLV_NO_ENTRY); - } - die1 = NULL; - if (at == NULL && - (at = _dwarf_attr_find(die, DW_AT_abstract_origin)) != NULL) { + for (;;) { + if ((at = _dwarf_attr_find(die, attr)) != NULL || + attr != DW_AT_type) + break; + if ((at = _dwarf_attr_find(die, DW_AT_abstract_origin)) == + NULL && + (at = _dwarf_attr_find(die, DW_AT_specification)) == NULL) + break; + switch (at->at_form) { case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: val = at->u[0].u64; - if ((die1 = _dwarf_die_find(die, val)) == NULL || - (at = _dwarf_attr_find(die1, attr)) == NULL) { - if (die1 != NULL) - dwarf_dealloc(dbg, die1, DW_DLA_DIE); + first = (die1 == NULL); + die1 = _dwarf_die_find(die, val); + if (!first) + dwarf_dealloc(dbg, die, DW_DLA_DIE); + if (die1 == NULL) { DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); return (DW_DLV_NO_ENTRY); } + die = die1; break; default: DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } + } + + if (at == NULL) { + DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY); + return (DW_DLV_NO_ENTRY); } switch (at->at_form) { case DW_FORM_addr: case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_udata: case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: *valp = at->u[0].u64; break; default: if (die1 != NULL) dwarf_dealloc(dbg, die1, DW_DLA_DIE); DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); } if (die1 != NULL) dwarf_dealloc(dbg, die1, DW_DLA_DIE); return (DW_DLV_OK); } Index: vendor/elftoolchain/dist/libdwarf/dwarf_attrval_signed.3 =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_attrval_signed.3 (revision 317072) +++ vendor/elftoolchain/dist/libdwarf/dwarf_attrval_signed.3 (revision 317073) @@ -1,220 +1,225 @@ .\" Copyright (c) 2011 Kai Wang .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dwarf_attrval_signed.3 2980 2014-01-21 20:15:54Z kaiwang27 $ +.\" $Id: dwarf_attrval_signed.3 3509 2016-12-29 03:58:41Z emaste $ .\" -.Dd January 18, 2014 +.Dd December 26, 2016 .Os .Dt DWARF_ATTRVAL_SIGNED 3 .Sh NAME .Nm dwarf_attrval_flag , .Nm dwarf_attrval_signed , .Nm dwarf_attrval_string , .Nm dwarf_attrval_unsigned .Nd retrieve the value of an attribute within a DWARF debugging information entry .Sh LIBRARY .Lb libdwarf .Sh SYNOPSIS .In libdwarf.h .Ft int .Fo dwarf_attrval_flag .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Bool *ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_attrval_signed .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Signed *ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_attrval_string .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "const char **ret" .Fa "Dwarf_Error *err" .Fc .Ft int .Fo dwarf_attrval_unsigned .Fa "Dwarf_Die die" .Fa "Dwarf_Half attr" .Fa "Dwarf_Unsigned *ret" .Fa "Dwarf_Error *err" .Fc .Sh DESCRIPTION These functions search the debugging information entry referenced by argument .Ar die for the attribute named by argument .Ar attr . If the named attribute is found, the functions set the location pointed to by argument .Ar ret to the value of the attribute. The argument .Ar err , if non NULL, will be used to return an error descriptor in case of an error. .Pp Function .Fn dwarf_attrval_flag sets the location pointed to by argument .Ar ret to either 0 or 1. If the form of the attribute named by argument .Ar attr is .Dv DW_FORM_flag , function .Fn dwarf_attrval_flag sets the location pointed to by argument .Ar ret to 1 if the attribute has a non-zero value, or to 0 otherwise. If the form of the attribute named by argument .Ar attr is .Dv DW_FORM_flag_present , function .Fn dwarf_attrval_flag unconditionally sets the location pointed to by argument .Ar ret to 1. The form of the attribute must be one of .Dv DW_FORM_flag or .Dv DW_FORM_flag_present . .Pp Function .Fn dwarf_attrval_signed stores the value for the attribute named by argument .Ar attr , into the location pointed to by argument .Ar ret . The attribute's value is treated as a signed integral quantity and is sign-extended as needed. The attribute named by the argument .Ar attr must belong to the .Dv CONSTANT class and must have one of the following forms: .Dv DW_FORM_data1 , .Dv DW_FORM_data2 , .Dv DW_FORM_data4 , .Dv DW_FORM_data8 or .Dv DW_FORM_sdata . .Pp Function .Fn dwarf_attrval_string sets the location pointed to by argument .Ar ret to a pointer to a NUL-terminated string that is the value of the attribute named by argument .Ar attr . The form of the attribute must be one of .Dv DW_FORM_string or .Dv DW_FORM_strp . .Pp Function .Fn dwarf_attrval_unsigned stores the value for the attribute named by argument .Ar attr into the location pointed to by argument .Ar ret . The attribute's value is treated as an unsigned integral quantity, and is zero-extended as needed. The named attribute must belong to one of the .Dv CONSTANT , .Dv ADDRESS or .Dv REFERENCE classes and must have one of the following forms: .Dv DW_FORM_addr , .Dv DW_FORM_data1 , .Dv DW_FORM_data2 , .Dv DW_FORM_data4 , .Dv DW_FORM_data8 , .Dv DW_FORM_udata , .Dv DW_FORM_ref1 , .Dv DW_FORM_ref2 , .Dv DW_FORM_ref4 , .Dv DW_FORM_ref8 , or .Dv DW_FORM_ref_udata . .Pp If the attribute named by argument .Ar attr -is not present in the debugging information entry referenced by -argument +is +.Dv DW_AT_type +and is not present in the debugging information entry referenced by argument .Ar die , and if a .Dv DW_AT_abstract_origin +or +.Dv DW_AT_specification attribute is present in the debugging information entry, function .Fn dwarf_attrval_unsigned will search for the named attribute in the debugging information entry referenced by the .Dv DW_AT_abstract_origin +or +.Dv DW_AT_specification attribute. .Sh RETURN VALUES On success, these functions returns .Dv DW_DLV_OK . If the named attribute was not found in the specified debugging information entry descriptor these functions return .Dv DW_DLV_NO_ENTRY and set argument .Ar err . For other errors, these functions return .Dv DW_DLV_ERROR and set argument .Ar err . .Sh COMPATIBILITY These functions are extensions added by this implementation of the DWARF(3) API. .Sh ERRORS These functions may fail with the following errors: .Bl -tag -width ".Bq Er DW_DLE_ATTR_FORM_BAD" .It Bq Er DW_DLE_ARGUMENT Either of the arguments .Va die or .Va ret was NULL. .It Bq Er DW_DLE_NO_ENTRY Argument .Ar die did not contain an attribute corresponding to the value in argument .Ar attr . .It Bq Er DW_DLE_ATTR_FORM_BAD The attribute named by argument .Ar attr was not of a permitted form. .El .Sh SEE ALSO .Xr dwarf 3 , .Xr dwarf_attr 3 , .Xr dwarf_hasattr 3 Index: vendor/elftoolchain/dist/libdwarf/dwarf_dump.c =================================================================== --- vendor/elftoolchain/dist/libdwarf/dwarf_dump.c (revision 317072) +++ vendor/elftoolchain/dist/libdwarf/dwarf_dump.c (revision 317073) @@ -1,1384 +1,1446 @@ /*- * Copyright (c) 2007 John Birrell (jb@freebsd.org) * Copyright (c) 2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "_libdwarf.h" -ELFTC_VCSID("$Id: dwarf_dump.c 3052 2014-05-26 20:36:24Z kaiwang27 $"); +ELFTC_VCSID("$Id: dwarf_dump.c 3494 2016-09-20 17:16:13Z emaste $"); int dwarf_get_ACCESS_name(unsigned access, const char **s) { assert(s != NULL); switch (access) { case DW_ACCESS_public: *s = "DW_ACCESS_public"; break; case DW_ACCESS_protected: *s = "DW_ACCESS_protected"; break; case DW_ACCESS_private: *s = "DW_ACCESS_private"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_AT_name(unsigned attr, const char **s) { assert(s != NULL); switch (attr) { case DW_AT_abstract_origin: *s = "DW_AT_abstract_origin"; break; case DW_AT_accessibility: *s = "DW_AT_accessibility"; break; case DW_AT_address_class: *s = "DW_AT_address_class"; break; case DW_AT_artificial: *s = "DW_AT_artificial"; break; case DW_AT_allocated: *s = "DW_AT_allocated"; break; case DW_AT_associated: *s = "DW_AT_associated"; break; case DW_AT_base_types: *s = "DW_AT_base_types"; break; case DW_AT_binary_scale: *s = "DW_AT_binary_scale"; break; case DW_AT_bit_offset: *s = "DW_AT_bit_offset"; break; case DW_AT_bit_size: *s = "DW_AT_bit_size"; break; case DW_AT_bit_stride: *s = "DW_AT_bit_stride"; break; case DW_AT_byte_size: *s = "DW_AT_byte_size"; break; case DW_AT_byte_stride: *s = "DW_AT_byte_stride"; break; case DW_AT_calling_convention: *s = "DW_AT_calling_convention"; break; case DW_AT_common_reference: *s = "DW_AT_common_reference"; break; case DW_AT_comp_dir: *s = "DW_AT_comp_dir"; break; case DW_AT_const_expr: *s = "DW_AT_const_expr"; break; case DW_AT_const_value: *s = "DW_AT_const_value"; break; case DW_AT_containing_type: *s = "DW_AT_containing_type"; break; case DW_AT_count: *s = "DW_AT_count"; break; case DW_AT_call_column: *s = "DW_AT_call_column"; break; case DW_AT_call_file: *s = "DW_AT_call_file"; break; case DW_AT_call_line: *s = "DW_AT_call_line"; break; case DW_AT_data_bit_offset: *s = "DW_AT_data_bit_offset"; break; case DW_AT_data_location: *s = "DW_AT_data_location"; break; case DW_AT_data_member_location: *s = "DW_AT_data_member_location"; break; case DW_AT_decl_column: *s = "DW_AT_decl_column"; break; case DW_AT_decl_file: *s = "DW_AT_decl_file"; break; case DW_AT_decl_line: *s = "DW_AT_decl_line"; break; case DW_AT_declaration: *s = "DW_AT_declaration"; break; case DW_AT_default_value: *s = "DW_AT_default_value"; break; case DW_AT_decimal_scale: *s = "DW_AT_decimal_scale"; break; case DW_AT_decimal_sign: *s = "DW_AT_decimal_sign"; break; case DW_AT_description: *s = "DW_AT_description"; break; case DW_AT_digit_count: *s = "DW_AT_digit_count"; break; case DW_AT_discr: *s = "DW_AT_discr"; break; case DW_AT_discr_list: *s = "DW_AT_discr_list"; break; case DW_AT_discr_value: *s = "DW_AT_discr_value"; break; case DW_AT_element_list: *s = "DW_AT_element_list"; break; case DW_AT_encoding: *s = "DW_AT_encoding"; break; case DW_AT_enum_class: *s = "DW_AT_enum_class"; break; case DW_AT_external: *s = "DW_AT_external"; break; case DW_AT_entry_pc: *s = "DW_AT_entry_pc"; break; case DW_AT_extension: *s = "DW_AT_extension"; break; case DW_AT_explicit: *s = "DW_AT_explicit"; break; case DW_AT_endianity: *s = "DW_AT_endianity"; break; case DW_AT_elemental: *s = "DW_AT_elemental"; break; case DW_AT_frame_base: *s = "DW_AT_frame_base"; break; case DW_AT_friend: *s = "DW_AT_friend"; break; case DW_AT_high_pc: *s = "DW_AT_high_pc"; break; case DW_AT_hi_user: *s = "DW_AT_hi_user"; break; case DW_AT_identifier_case: *s = "DW_AT_identifier_case"; break; case DW_AT_import: *s = "DW_AT_import"; break; case DW_AT_inline: *s = "DW_AT_inline"; break; case DW_AT_is_optional: *s = "DW_AT_is_optional"; break; case DW_AT_language: *s = "DW_AT_language"; break; case DW_AT_linkage_name: *s = "DW_AT_linkage_name"; break; case DW_AT_lo_user: *s = "DW_AT_lo_user"; break; case DW_AT_location: *s = "DW_AT_location"; break; case DW_AT_low_pc: *s = "DW_AT_low_pc"; break; case DW_AT_lower_bound: *s = "DW_AT_lower_bound"; break; case DW_AT_macro_info: *s = "DW_AT_macro_info"; break; case DW_AT_main_subprogram: *s = "DW_AT_main_subprogram"; break; case DW_AT_mutable: *s = "DW_AT_mutable"; break; case DW_AT_member: *s = "DW_AT_member"; break; case DW_AT_name: *s = "DW_AT_name"; break; case DW_AT_namelist_item: *s = "DW_AT_namelist_item"; break; case DW_AT_ordering: *s = "DW_AT_ordering"; break; case DW_AT_object_pointer: *s = "DW_AT_object_pointer"; break; case DW_AT_priority: *s = "DW_AT_priority"; break; case DW_AT_producer: *s = "DW_AT_producer"; break; case DW_AT_prototyped: *s = "DW_AT_prototyped"; break; case DW_AT_picture_string: *s = "DW_AT_picture_string"; break; case DW_AT_pure: *s = "DW_AT_pure"; break; case DW_AT_return_addr: *s = "DW_AT_return_addr"; break; case DW_AT_ranges: *s = "DW_AT_ranges"; break; case DW_AT_recursive: *s = "DW_AT_recursive"; break; case DW_AT_segment: *s = "DW_AT_segment"; break; case DW_AT_sibling: *s = "DW_AT_sibling"; break; case DW_AT_signature: *s = "DW_AT_signature"; break; case DW_AT_specification: *s = "DW_AT_specification"; break; case DW_AT_start_scope: *s = "DW_AT_start_scope"; break; case DW_AT_static_link: *s = "DW_AT_static_link"; break; case DW_AT_stmt_list: *s = "DW_AT_stmt_list"; break; case DW_AT_string_length: *s = "DW_AT_string_length"; break; case DW_AT_subscr_data: *s = "DW_AT_subscr_data"; break; case DW_AT_small: *s = "DW_AT_small"; break; case DW_AT_type: *s = "DW_AT_type"; break; case DW_AT_trampoline: *s = "DW_AT_trampoline"; break; case DW_AT_threads_scaled: *s = "DW_AT_threads_scaled"; break; case DW_AT_upper_bound: *s = "DW_AT_upper_bound"; break; case DW_AT_use_location: *s = "DW_AT_use_location"; break; case DW_AT_use_UTF8: *s = "DW_AT_use_UTF8"; break; case DW_AT_variable_parameter: *s = "DW_AT_variable_parameter"; break; case DW_AT_virtuality: *s = "DW_AT_virtuality"; break; case DW_AT_visibility: *s = "DW_AT_visibility"; break; case DW_AT_vtable_elem_location: *s = "DW_AT_vtable_elem_location"; break; case DW_AT_sf_names: *s = "DW_AT_sf_names"; break; case DW_AT_src_info: *s = "DW_AT_src_info"; break; case DW_AT_mac_info: *s = "DW_AT_mac_info"; break; case DW_AT_src_coords: *s = "DW_AT_src_coords"; break; case DW_AT_body_begin: *s = "DW_AT_body_begin"; break; case DW_AT_body_end: *s = "DW_AT_body_end"; break; + case DW_AT_MIPS_fde: + *s = "DW_AT_MIPS_fde"; break; + case DW_AT_MIPS_loop_begin: + *s = "DW_AT_MIPS_loop_begin"; break; + case DW_AT_MIPS_tail_loop_begin: + *s = "DW_AT_MIPS_tail_loop_begin"; break; + case DW_AT_MIPS_epilog_begin: + *s = "DW_AT_MIPS_epilog_begin"; break; + case DW_AT_MIPS_loop_unroll_factor: + *s = "DW_AT_MIPS_loop_unroll_factor"; break; + case DW_AT_MIPS_software_pipeline_depth: + *s = "DW_AT_MIPS_software_pipeline_depth"; break; + case DW_AT_MIPS_linkage_name: + *s = "DW_AT_MIPS_linkage_name"; break; + case DW_AT_MIPS_stride: + *s = "DW_AT_MIPS_stride"; break; + case DW_AT_MIPS_abstract_name: + *s = "DW_AT_MIPS_abstract_name"; break; + case DW_AT_MIPS_clone_origin: + *s = "DW_AT_MIPS_clone_origin"; break; + case DW_AT_MIPS_has_inlines: + *s = "DW_AT_MIPS_has_inlines"; break; + case DW_AT_MIPS_stride_byte: + *s = "DW_AT_MIPS_stride_byte"; break; + case DW_AT_MIPS_stride_elem: + *s = "DW_AT_MIPS_stride_elem"; break; + case DW_AT_MIPS_ptr_dopetype: + *s = "DW_AT_MIPS_ptr_dopetype"; break; + case DW_AT_MIPS_allocatable_dopetype: + *s = "DW_AT_MIPS_allocatable_dopetype"; break; + case DW_AT_MIPS_assumed_shape_dopetype: + *s = "DW_AT_MIPS_assumed_shape_dopetype"; break; + case DW_AT_MIPS_assumed_size: + *s = "DW_AT_MIPS_assumed_size"; break; case DW_AT_GNU_vector: *s = "DW_AT_GNU_vector"; break; case DW_AT_GNU_guarded_by: *s = "DW_AT_GNU_guarded_by"; break; case DW_AT_GNU_pt_guarded_by: *s = "DW_AT_GNU_pt_guarded_by"; break; case DW_AT_GNU_guarded: *s = "DW_AT_GNU_guarded"; break; case DW_AT_GNU_pt_guarded: *s = "DW_AT_GNU_pt_guarded"; break; case DW_AT_GNU_locks_excluded: *s = "DW_AT_GNU_locks_excluded"; break; case DW_AT_GNU_exclusive_locks_required: *s = "DW_AT_GNU_exclusive_locks_required"; break; case DW_AT_GNU_shared_locks_required: *s = "DW_AT_GNU_shared_locks_required"; break; case DW_AT_GNU_odr_signature: *s = "DW_AT_GNU_odr_signature"; break; case DW_AT_GNU_template_name: *s = "DW_AT_GNU_template_name"; break; case DW_AT_GNU_call_site_value: *s = "DW_AT_GNU_call_site_value"; break; case DW_AT_GNU_call_site_data_value: *s = "DW_AT_GNU_call_site_data_value"; break; case DW_AT_GNU_call_site_target: *s = "DW_AT_GNU_call_site_target"; break; case DW_AT_GNU_call_site_target_clobbered: *s = "DW_AT_GNU_call_site_target_clobbered"; break; case DW_AT_GNU_tail_call: *s = "DW_AT_GNU_tail_call"; break; case DW_AT_GNU_all_tail_call_sites: *s = "DW_AT_GNU_all_tail_call_sites"; break; case DW_AT_GNU_all_call_sites: *s = "DW_AT_GNU_all_call_sites"; break; case DW_AT_GNU_all_source_call_sites: *s = "DW_AT_GNU_all_source_call_sites"; break; + case DW_AT_APPLE_optimized: + *s = "DW_AT_APPLE_optimized"; break; + case DW_AT_APPLE_flags: + *s = "DW_AT_APPLE_flags"; break; + case DW_AT_APPLE_isa: + *s = "DW_AT_APPLE_isa"; break; + case DW_AT_APPLE_block: + *s = "DW_AT_APPLE_block"; break; + case DW_AT_APPLE_major_runtime_vers: + *s = "DW_AT_APPLE_major_runtime_vers"; break; + case DW_AT_APPLE_runtime_class: + *s = "DW_AT_APPLE_runtime_class"; break; + case DW_AT_APPLE_omit_frame_ptr: + *s = "DW_AT_APPLE_omit_frame_ptr"; break; + case DW_AT_APPLE_property_name: + *s = "DW_AT_APPLE_property_name"; break; + case DW_AT_APPLE_property_getter: + *s = "DW_AT_APPLE_property_getter"; break; + case DW_AT_APPLE_property_setter: + *s = "DW_AT_APPLE_property_setter"; break; + case DW_AT_APPLE_property_attribute: + *s = "DW_AT_APPLE_property_attribute"; break; + case DW_AT_APPLE_objc_complete_type: + *s = "DW_AT_APPLE_objc_complete_type"; break; + case DW_AT_APPLE_property: + *s = "DW_AT_APPLE_property"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_ATE_name(unsigned ate, const char **s) { assert(s != NULL); switch(ate) { case DW_ATE_address: *s = "DW_ATE_address"; break; case DW_ATE_boolean: *s = "DW_ATE_boolean"; break; case DW_ATE_complex_float: *s = "DW_ATE_complex_float"; break; case DW_ATE_float: *s = "DW_ATE_float"; break; case DW_ATE_signed: *s = "DW_ATE_signed"; break; case DW_ATE_signed_char: *s = "DW_ATE_signed_char"; break; case DW_ATE_unsigned: *s = "DW_ATE_unsigned"; break; case DW_ATE_unsigned_char: *s = "DW_ATE_unsigned_char"; break; case DW_ATE_imaginary_float: *s = "DW_ATE_imaginary_float"; break; case DW_ATE_packed_decimal: *s = "DW_ATE_packed_decimal"; break; case DW_ATE_numeric_string: *s = "DW_ATE_numeric_string"; break; case DW_ATE_edited: *s = "DW_ATE_edited"; break; case DW_ATE_signed_fixed: *s = "DW_ATE_signed_fixed"; break; case DW_ATE_unsigned_fixed: *s = "DW_ATE_unsigned_fixed"; break; case DW_ATE_decimal_float: *s = "DW_ATE_decimal_float"; break; case DW_ATE_lo_user: *s = "DW_ATE_lo_user"; break; case DW_ATE_hi_user: *s = "DW_ATE_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_CC_name(unsigned cc, const char **s) { assert(s != NULL); switch (cc) { case DW_CC_normal: *s = "DW_CC_normal"; break; case DW_CC_program: *s = "DW_CC_program"; break; case DW_CC_nocall: *s = "DW_CC_nocall"; break; case DW_CC_lo_user: *s = "DW_CC_lo_user"; break; case DW_CC_hi_user: *s = "DW_CC_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_CFA_name(unsigned cfa, const char **s) { assert(s != NULL); switch (cfa) { case DW_CFA_advance_loc: *s = "DW_CFA_advance_loc"; break; case DW_CFA_offset: *s = "DW_CFA_offset"; break; case DW_CFA_restore: *s = "DW_CFA_restore"; break; case DW_CFA_nop: *s = "DW_CFA_nop"; break; case DW_CFA_set_loc: *s = "DW_CFA_set_loc"; break; case DW_CFA_advance_loc1: *s = "DW_CFA_advance_loc1"; break; case DW_CFA_advance_loc2: *s = "DW_CFA_advance_loc2"; break; case DW_CFA_advance_loc4: *s = "DW_CFA_advance_loc4"; break; case DW_CFA_offset_extended: *s = "DW_CFA_offset_extended"; break; case DW_CFA_restore_extended: *s = "DW_CFA_restore_extended"; break; case DW_CFA_undefined: *s = "DW_CFA_undefined"; break; case DW_CFA_same_value: *s = "DW_CFA_same_value"; break; case DW_CFA_register: *s = "DW_CFA_register"; break; case DW_CFA_remember_state: *s = "DW_CFA_remember_state"; break; case DW_CFA_restore_state: *s = "DW_CFA_restore_state"; break; case DW_CFA_def_cfa: *s = "DW_CFA_def_cfa"; break; case DW_CFA_def_cfa_register: *s = "DW_CFA_def_cfa_register"; break; case DW_CFA_def_cfa_offset: *s = "DW_CFA_def_cfa_offset"; break; case DW_CFA_def_cfa_expression: *s = "DW_CFA_def_cfa_expression"; break; case DW_CFA_expression: *s = "DW_CFA_expression"; break; case DW_CFA_offset_extended_sf: *s = "DW_CFA_offset_extended_sf"; break; case DW_CFA_def_cfa_sf: *s = "DW_CFA_def_cfa_sf"; break; case DW_CFA_def_cfa_offset_sf: *s = "DW_CFA_def_cfa_offset_sf"; break; case DW_CFA_val_offset: *s = "DW_CFA_val_offset"; break; case DW_CFA_val_offset_sf: *s = "DW_CFA_val_offset_sf"; break; case DW_CFA_val_expression: *s = "DW_CFA_val_expression"; break; case DW_CFA_lo_user: *s = "DW_CFA_lo_user"; break; case DW_CFA_high_user: *s = "DW_CFA_high_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_CHILDREN_name(unsigned children, const char **s) { assert(s != NULL); switch (children) { case DW_CHILDREN_no: *s = "DW_CHILDREN_no"; break; case DW_CHILDREN_yes: *s = "DW_CHILDREN_yes"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_FORM_name(unsigned form, const char **s) { assert(s != NULL); switch (form) { case DW_FORM_addr: *s = "DW_FORM_addr"; break; case DW_FORM_block: *s = "DW_FORM_block"; break; case DW_FORM_block1: *s = "DW_FORM_block1"; break; case DW_FORM_block2: *s = "DW_FORM_block2"; break; case DW_FORM_block4: *s = "DW_FORM_block4"; break; case DW_FORM_data1: *s = "DW_FORM_data1"; break; case DW_FORM_data2: *s = "DW_FORM_data2"; break; case DW_FORM_data4: *s = "DW_FORM_data4"; break; case DW_FORM_data8: *s = "DW_FORM_data8"; break; case DW_FORM_exprloc: *s = "DW_FORM_exprloc"; break; case DW_FORM_flag: *s = "DW_FORM_flag"; break; case DW_FORM_flag_present: *s = "DW_FORM_flag_present"; break; case DW_FORM_indirect: *s = "DW_FORM_indirect"; break; case DW_FORM_ref1: *s = "DW_FORM_ref1"; break; case DW_FORM_ref2: *s = "DW_FORM_ref2"; break; case DW_FORM_ref4: *s = "DW_FORM_ref4"; break; case DW_FORM_ref8: *s = "DW_FORM_ref8"; break; case DW_FORM_ref_addr: *s = "DW_FORM_ref_addr"; break; case DW_FORM_ref_sig8: *s = "DW_FORM_ref_sig8"; break; case DW_FORM_ref_udata: *s = "DW_FORM_ref_udata"; break; case DW_FORM_sdata: *s = "DW_FORM_sdata"; break; case DW_FORM_sec_offset: *s = "DW_FORM_sec_offset"; break; case DW_FORM_string: *s = "DW_FORM_string"; break; case DW_FORM_strp: *s = "DW_FORM_strp"; break; case DW_FORM_udata: *s = "DW_FORM_udata"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_DS_name(unsigned ds, const char **s) { assert(s != NULL); switch (ds) { case DW_DS_unsigned: *s = "DW_DS_unsigned"; break; case DW_DS_leading_overpunch: *s = "DW_DS_leading_overpunch"; break; case DW_DS_trailing_overpunch: *s = "DW_DS_trailing_overpunch"; break; case DW_DS_leading_separate: *s = "DW_DS_leading_separate"; break; case DW_DS_trailing_separate: *s = "DW_DS_trailing_separate"; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_DSC_name(unsigned dsc, const char **s) { assert(s != NULL); switch (dsc) { case DW_DSC_label: *s = "DW_DSC_label"; break; case DW_DSC_range: *s = "DW_DSC_range"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_EH_name(unsigned eh, const char **s) { assert(s != NULL); switch (eh) { case DW_EH_PE_absptr: *s = "DW_EH_PE_absptr"; break; case DW_EH_PE_uleb128: *s = "DW_EH_PE_uleb128"; break; case DW_EH_PE_udata2: *s = "DW_EH_PE_udata2"; break; case DW_EH_PE_udata4: *s = "DW_EH_PE_udata4"; break; case DW_EH_PE_udata8: *s = "DW_EH_PE_udata8"; break; case DW_EH_PE_sleb128: *s = "DW_EH_PE_sleb128"; break; case DW_EH_PE_sdata2: *s = "DW_EH_PE_sdata2"; break; case DW_EH_PE_sdata4: *s = "DW_EH_PE_sdata4"; break; case DW_EH_PE_sdata8: *s = "DW_EH_PE_sdata8"; break; case DW_EH_PE_pcrel: *s = "DW_EH_PE_pcrel"; break; case DW_EH_PE_textrel: *s = "DW_EH_PE_textrel"; break; case DW_EH_PE_datarel: *s = "DW_EH_PE_datarel"; break; case DW_EH_PE_funcrel: *s = "DW_EH_PE_funcrel"; break; case DW_EH_PE_aligned: *s = "DW_EH_PE_aligned"; break; case DW_EH_PE_omit: *s = "DW_EH_PE_omit"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_END_name(unsigned end, const char **s) { assert(s != NULL); switch (end) { case DW_END_default: *s = "DW_END_default"; break; case DW_END_big: *s = "DW_END_big"; break; case DW_END_little: *s = "DW_END_little"; break; case DW_END_lo_user: *s = "DW_END_lo_user"; break; case DW_END_high_user: *s = "DW_END_high_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_ID_name(unsigned id, const char **s) { assert(s != NULL); switch (id) { case DW_ID_case_sensitive: *s = "DW_ID_case_sensitive"; break; case DW_ID_up_case: *s = "DW_ID_up_case"; break; case DW_ID_down_case: *s = "DW_ID_down_case"; break; case DW_ID_case_insensitive: *s = "DW_ID_case_insensitive"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_INL_name(unsigned inl, const char **s) { assert(s != NULL); switch (inl) { case DW_INL_not_inlined: *s = "DW_INL_not_inlined"; break; case DW_INL_inlined: *s = "DW_INL_inlined"; break; case DW_INL_declared_not_inlined: *s = "DW_INL_declared_not_inlined"; break; case DW_INL_declared_inlined: *s = "DW_INL_declared_inlined"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_LANG_name(unsigned lang, const char **s) { assert(s != NULL); switch (lang) { case DW_LANG_C89: *s = "DW_LANG_C89"; break; case DW_LANG_C: *s = "DW_LANG_C"; break; case DW_LANG_Ada83: *s = "DW_LANG_Ada83"; break; case DW_LANG_C_plus_plus: *s = "DW_LANG_C_plus_plus"; break; case DW_LANG_Cobol74: *s = "DW_LANG_Cobol74"; break; case DW_LANG_Cobol85: *s = "DW_LANG_Cobol85"; break; case DW_LANG_Fortran77: *s = "DW_LANG_Fortran77"; break; case DW_LANG_Fortran90: *s = "DW_LANG_Fortran90"; break; case DW_LANG_Pascal83: *s = "DW_LANG_Pascal83"; break; case DW_LANG_Modula2: *s = "DW_LANG_Modula2"; break; case DW_LANG_Java: *s = "DW_LANG_Java"; break; case DW_LANG_C99: *s = "DW_LANG_C99"; break; case DW_LANG_Ada95: *s = "DW_LANG_Ada95"; break; case DW_LANG_Fortran95: *s = "DW_LANG_Fortran95"; break; case DW_LANG_PLI: *s = "DW_LANG_PLI"; break; case DW_LANG_ObjC: *s = "DW_LANG_ObjC"; break; case DW_LANG_ObjC_plus_plus: *s = "DW_LANG_ObjC_plus_plus"; break; case DW_LANG_UPC: *s = "DW_LANG_UPC"; break; case DW_LANG_D: *s = "DW_LANG_D"; break; case DW_LANG_lo_user: *s = "DW_LANG_lo_user"; break; + case DW_LANG_Mips_Assembler: + *s = "DW_LANG_Mips_Assembler"; break; case DW_LANG_hi_user: *s = "DW_LANG_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_LNE_name(unsigned lne, const char **s) { assert(s != NULL); switch (lne) { case DW_LNE_end_sequence: *s = "DW_LNE_end_sequence"; break; case DW_LNE_set_address: *s = "DW_LNE_set_address"; break; case DW_LNE_define_file: *s = "DW_LNE_define_file"; break; case DW_LNE_lo_user: *s = "DW_LNE_lo_user"; break; case DW_LNE_hi_user: *s = "DW_LNE_hi_user"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_LNS_name(unsigned lns, const char **s) { assert(s != NULL); switch (lns) { case DW_LNS_copy: *s = "DW_LNS_copy"; break; case DW_LNS_advance_pc: *s = "DW_LNS_advance_pc"; break; case DW_LNS_advance_line: *s = "DW_LNS_advance_line"; break; case DW_LNS_set_file: *s = "DW_LNS_set_file"; break; case DW_LNS_set_column: *s = "DW_LNS_set_column"; break; case DW_LNS_negate_stmt: *s = "DW_LNS_negate_stmt"; break; case DW_LNS_set_basic_block: *s = "DW_LNS_set_basic_block"; break; case DW_LNS_const_add_pc: *s = "DW_LNS_const_add_pc"; break; case DW_LNS_fixed_advance_pc: *s = "DW_LNS_fixed_advance_pc"; break; case DW_LNS_set_prologue_end: *s = "DW_LNS_set_prologue_end"; break; case DW_LNS_set_epilogue_begin: *s = "DW_LNS_set_epilogue_begin"; break; case DW_LNS_set_isa: *s = "DW_LNS_set_isa"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_MACINFO_name(unsigned mi, const char **s) { assert(s != NULL); switch (mi) { case DW_MACINFO_define: *s = "DW_MACINFO_define"; break; case DW_MACINFO_undef: *s = "DW_MACINFO_undef"; break; case DW_MACINFO_start_file: *s = "DW_MACINFO_start_file"; break; case DW_MACINFO_end_file: *s = "DW_MACINFO_end_file"; break; case DW_MACINFO_vendor_ext: *s = "DW_MACINFO_vendor_ext"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_OP_name(unsigned op, const char **s) { assert(s != NULL); switch (op) { case DW_OP_deref: *s = "DW_OP_deref"; break; case DW_OP_reg0: *s = "DW_OP_reg0"; break; case DW_OP_reg1: *s = "DW_OP_reg1"; break; case DW_OP_reg2: *s = "DW_OP_reg2"; break; case DW_OP_reg3: *s = "DW_OP_reg3"; break; case DW_OP_reg4: *s = "DW_OP_reg4"; break; case DW_OP_reg5: *s = "DW_OP_reg5"; break; case DW_OP_reg6: *s = "DW_OP_reg6"; break; case DW_OP_reg7: *s = "DW_OP_reg7"; break; case DW_OP_reg8: *s = "DW_OP_reg8"; break; case DW_OP_reg9: *s = "DW_OP_reg9"; break; case DW_OP_reg10: *s = "DW_OP_reg10"; break; case DW_OP_reg11: *s = "DW_OP_reg11"; break; case DW_OP_reg12: *s = "DW_OP_reg12"; break; case DW_OP_reg13: *s = "DW_OP_reg13"; break; case DW_OP_reg14: *s = "DW_OP_reg14"; break; case DW_OP_reg15: *s = "DW_OP_reg15"; break; case DW_OP_reg16: *s = "DW_OP_reg16"; break; case DW_OP_reg17: *s = "DW_OP_reg17"; break; case DW_OP_reg18: *s = "DW_OP_reg18"; break; case DW_OP_reg19: *s = "DW_OP_reg19"; break; case DW_OP_reg20: *s = "DW_OP_reg20"; break; case DW_OP_reg21: *s = "DW_OP_reg21"; break; case DW_OP_reg22: *s = "DW_OP_reg22"; break; case DW_OP_reg23: *s = "DW_OP_reg23"; break; case DW_OP_reg24: *s = "DW_OP_reg24"; break; case DW_OP_reg25: *s = "DW_OP_reg25"; break; case DW_OP_reg26: *s = "DW_OP_reg26"; break; case DW_OP_reg27: *s = "DW_OP_reg27"; break; case DW_OP_reg28: *s = "DW_OP_reg28"; break; case DW_OP_reg29: *s = "DW_OP_reg29"; break; case DW_OP_reg30: *s = "DW_OP_reg30"; break; case DW_OP_reg31: *s = "DW_OP_reg31"; break; case DW_OP_lit0: *s = "DW_OP_lit0"; break; case DW_OP_lit1: *s = "DW_OP_lit1"; break; case DW_OP_lit2: *s = "DW_OP_lit2"; break; case DW_OP_lit3: *s = "DW_OP_lit3"; break; case DW_OP_lit4: *s = "DW_OP_lit4"; break; case DW_OP_lit5: *s = "DW_OP_lit5"; break; case DW_OP_lit6: *s = "DW_OP_lit6"; break; case DW_OP_lit7: *s = "DW_OP_lit7"; break; case DW_OP_lit8: *s = "DW_OP_lit8"; break; case DW_OP_lit9: *s = "DW_OP_lit9"; break; case DW_OP_lit10: *s = "DW_OP_lit10"; break; case DW_OP_lit11: *s = "DW_OP_lit11"; break; case DW_OP_lit12: *s = "DW_OP_lit12"; break; case DW_OP_lit13: *s = "DW_OP_lit13"; break; case DW_OP_lit14: *s = "DW_OP_lit14"; break; case DW_OP_lit15: *s = "DW_OP_lit15"; break; case DW_OP_lit16: *s = "DW_OP_lit16"; break; case DW_OP_lit17: *s = "DW_OP_lit17"; break; case DW_OP_lit18: *s = "DW_OP_lit18"; break; case DW_OP_lit19: *s = "DW_OP_lit19"; break; case DW_OP_lit20: *s = "DW_OP_lit20"; break; case DW_OP_lit21: *s = "DW_OP_lit21"; break; case DW_OP_lit22: *s = "DW_OP_lit22"; break; case DW_OP_lit23: *s = "DW_OP_lit23"; break; case DW_OP_lit24: *s = "DW_OP_lit24"; break; case DW_OP_lit25: *s = "DW_OP_lit25"; break; case DW_OP_lit26: *s = "DW_OP_lit26"; break; case DW_OP_lit27: *s = "DW_OP_lit27"; break; case DW_OP_lit28: *s = "DW_OP_lit28"; break; case DW_OP_lit29: *s = "DW_OP_lit29"; break; case DW_OP_lit30: *s = "DW_OP_lit30"; break; case DW_OP_lit31: *s = "DW_OP_lit31"; break; case DW_OP_dup: *s = "DW_OP_dup"; break; case DW_OP_drop: *s = "DW_OP_drop"; break; case DW_OP_over: *s = "DW_OP_over"; break; case DW_OP_swap: *s = "DW_OP_swap"; break; case DW_OP_rot: *s = "DW_OP_rot"; break; case DW_OP_xderef: *s = "DW_OP_xderef"; break; case DW_OP_abs: *s = "DW_OP_abs"; break; case DW_OP_and: *s = "DW_OP_and"; break; case DW_OP_div: *s = "DW_OP_div"; break; case DW_OP_minus: *s = "DW_OP_minus"; break; case DW_OP_mod: *s = "DW_OP_mod"; break; case DW_OP_mul: *s = "DW_OP_mul"; break; case DW_OP_neg: *s = "DW_OP_neg"; break; case DW_OP_not: *s = "DW_OP_not"; break; case DW_OP_or: *s = "DW_OP_or"; break; case DW_OP_plus: *s = "DW_OP_plus"; break; case DW_OP_shl: *s = "DW_OP_shl"; break; case DW_OP_shr: *s = "DW_OP_shr"; break; case DW_OP_shra: *s = "DW_OP_shra"; break; case DW_OP_xor: *s = "DW_OP_xor"; break; case DW_OP_eq: *s = "DW_OP_eq"; break; case DW_OP_ge: *s = "DW_OP_ge"; break; case DW_OP_gt: *s = "DW_OP_gt"; break; case DW_OP_le: *s = "DW_OP_le"; break; case DW_OP_lt: *s = "DW_OP_lt"; break; case DW_OP_ne: *s = "DW_OP_ne"; break; case DW_OP_nop: *s = "DW_OP_nop"; break; case DW_OP_const1u: *s = "DW_OP_const1u"; break; case DW_OP_const1s: *s = "DW_OP_const1s"; break; case DW_OP_pick: *s = "DW_OP_pick"; break; case DW_OP_deref_size: *s = "DW_OP_deref_size"; break; case DW_OP_xderef_size: *s = "DW_OP_xderef_size"; break; case DW_OP_const2u: *s = "DW_OP_const2u"; break; case DW_OP_const2s: *s = "DW_OP_const2s"; break; case DW_OP_bra: *s = "DW_OP_bra"; break; case DW_OP_skip: *s = "DW_OP_skip"; break; case DW_OP_const4u: *s = "DW_OP_const4u"; break; case DW_OP_const4s: *s = "DW_OP_const4s"; break; case DW_OP_const8u: *s = "DW_OP_const8u"; break; case DW_OP_const8s: *s = "DW_OP_const8s"; break; case DW_OP_constu: *s = "DW_OP_constu"; break; case DW_OP_plus_uconst: *s = "DW_OP_plus_uconst"; break; case DW_OP_regx: *s = "DW_OP_regx"; break; case DW_OP_piece: *s = "DW_OP_piece"; break; case DW_OP_consts: *s = "DW_OP_consts"; break; case DW_OP_breg0: *s = "DW_OP_breg0"; break; case DW_OP_breg1: *s = "DW_OP_breg1"; break; case DW_OP_breg2: *s = "DW_OP_breg2"; break; case DW_OP_breg3: *s = "DW_OP_breg3"; break; case DW_OP_breg4: *s = "DW_OP_breg4"; break; case DW_OP_breg5: *s = "DW_OP_breg5"; break; case DW_OP_breg6: *s = "DW_OP_breg6"; break; case DW_OP_breg7: *s = "DW_OP_breg7"; break; case DW_OP_breg8: *s = "DW_OP_breg8"; break; case DW_OP_breg9: *s = "DW_OP_breg9"; break; case DW_OP_breg10: *s = "DW_OP_breg10"; break; case DW_OP_breg11: *s = "DW_OP_breg11"; break; case DW_OP_breg12: *s = "DW_OP_breg12"; break; case DW_OP_breg13: *s = "DW_OP_breg13"; break; case DW_OP_breg14: *s = "DW_OP_breg14"; break; case DW_OP_breg15: *s = "DW_OP_breg15"; break; case DW_OP_breg16: *s = "DW_OP_breg16"; break; case DW_OP_breg17: *s = "DW_OP_breg17"; break; case DW_OP_breg18: *s = "DW_OP_breg18"; break; case DW_OP_breg19: *s = "DW_OP_breg19"; break; case DW_OP_breg20: *s = "DW_OP_breg20"; break; case DW_OP_breg21: *s = "DW_OP_breg21"; break; case DW_OP_breg22: *s = "DW_OP_breg22"; break; case DW_OP_breg23: *s = "DW_OP_breg23"; break; case DW_OP_breg24: *s = "DW_OP_breg24"; break; case DW_OP_breg25: *s = "DW_OP_breg25"; break; case DW_OP_breg26: *s = "DW_OP_breg26"; break; case DW_OP_breg27: *s = "DW_OP_breg27"; break; case DW_OP_breg28: *s = "DW_OP_breg28"; break; case DW_OP_breg29: *s = "DW_OP_breg29"; break; case DW_OP_breg30: *s = "DW_OP_breg30"; break; case DW_OP_breg31: *s = "DW_OP_breg31"; break; case DW_OP_fbreg: *s = "DW_OP_fbreg"; break; case DW_OP_bregx: *s = "DW_OP_bregx"; break; case DW_OP_addr: *s = "DW_OP_addr"; break; case DW_OP_push_object_address: *s = "DW_OP_push_object_address"; break; case DW_OP_call2: *s = "DW_OP_call2"; break; case DW_OP_call4: *s = "DW_OP_call4"; break; case DW_OP_call_ref: *s = "DW_OP_call_ref"; break; case DW_OP_form_tls_address: *s = "DW_OP_form_tls_address"; break; case DW_OP_call_frame_cfa: *s = "DW_OP_call_frame_cfa"; break; case DW_OP_bit_piece: *s = "DW_OP_bit_piece"; break; case DW_OP_implicit_value: *s = "DW_OP_implicit_value"; break; case DW_OP_stack_value: *s = "DW_OP_stack_value"; break; case DW_OP_GNU_push_tls_address: *s = "DW_OP_GNU_push_tls_address"; break; case DW_OP_GNU_uninit: *s = "DW_OP_GNU_uninit"; break; case DW_OP_GNU_encoded_addr: *s = "DW_OP_GNU_encoded_addr"; break; case DW_OP_GNU_implicit_pointer: *s = "DW_OP_GNU_implicit_pointer"; break; case DW_OP_GNU_entry_value: *s = "DW_OP_GNU_entry_value"; break; case DW_OP_GNU_const_type: *s = "DW_OP_GNU_const_type"; break; case DW_OP_GNU_regval_type: *s = "DW_OP_GNU_regval_type"; break; case DW_OP_GNU_deref_type: *s = "DW_OP_GNU_deref_type"; break; case DW_OP_GNU_convert: *s = "DW_OP_GNU_convert"; break; case DW_OP_GNU_reinterpret: *s = "DW_OP_GNU_reinterpret"; break; case DW_OP_GNU_parameter_ref: *s = "DW_OP_GNU_parameter_ref"; break; case DW_OP_GNU_addr_index: *s = "DW_OP_GNU_addr_index"; break; case DW_OP_GNU_const_index: *s = "DW_OP_GNU_const_index"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_ORD_name(unsigned ord, const char **s) { assert(s != NULL); switch (ord) { case DW_ORD_row_major: *s = "DW_ORD_row_major"; break; case DW_ORD_col_major: *s = "DW_ORD_col_major"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_TAG_name(unsigned tag, const char **s) { assert(s != NULL); switch (tag) { case DW_TAG_access_declaration: *s = "DW_TAG_access_declaration"; break; case DW_TAG_array_type: *s = "DW_TAG_array_type"; break; case DW_TAG_base_type: *s = "DW_TAG_base_type"; break; case DW_TAG_catch_block: *s = "DW_TAG_catch_block"; break; case DW_TAG_class_type: *s = "DW_TAG_class_type"; break; case DW_TAG_common_block: *s = "DW_TAG_common_block"; break; case DW_TAG_common_inclusion: *s = "DW_TAG_common_inclusion"; break; case DW_TAG_compile_unit: *s = "DW_TAG_compile_unit"; break; case DW_TAG_condition: *s = "DW_TAG_condition"; break; case DW_TAG_const_type: *s = "DW_TAG_const_type"; break; case DW_TAG_constant: *s = "DW_TAG_constant"; break; case DW_TAG_dwarf_procedure: *s = "DW_TAG_dwarf_procedure"; break; case DW_TAG_entry_point: *s = "DW_TAG_entry_point"; break; case DW_TAG_enumeration_type: *s = "DW_TAG_enumeration_type"; break; case DW_TAG_enumerator: *s = "DW_TAG_enumerator"; break; case DW_TAG_formal_parameter: *s = "DW_TAG_formal_parameter"; break; case DW_TAG_friend: *s = "DW_TAG_friend"; break; case DW_TAG_imported_declaration: *s = "DW_TAG_imported_declaration"; break; case DW_TAG_imported_module: *s = "DW_TAG_imported_module"; break; case DW_TAG_imported_unit: *s = "DW_TAG_imported_unit"; break; case DW_TAG_inheritance: *s = "DW_TAG_inheritance"; break; case DW_TAG_inlined_subroutine: *s = "DW_TAG_inlined_subroutine"; break; case DW_TAG_interface_type: *s = "DW_TAG_interface_type"; break; case DW_TAG_label: *s = "DW_TAG_label"; break; case DW_TAG_lexical_block: *s = "DW_TAG_lexical_block"; break; case DW_TAG_member: *s = "DW_TAG_member"; break; case DW_TAG_module: *s = "DW_TAG_module"; break; case DW_TAG_namelist: *s = "DW_TAG_namelist"; break; case DW_TAG_namelist_item: *s = "DW_TAG_namelist_item"; break; case DW_TAG_namespace: *s = "DW_TAG_namespace"; break; case DW_TAG_packed_type: *s = "DW_TAG_packed_type"; break; case DW_TAG_partial_unit: *s = "DW_TAG_partial_unit"; break; case DW_TAG_pointer_type: *s = "DW_TAG_pointer_type"; break; case DW_TAG_ptr_to_member_type: *s = "DW_TAG_ptr_to_member_type"; break; case DW_TAG_reference_type: *s = "DW_TAG_reference_type"; break; case DW_TAG_restrict_type: *s = "DW_TAG_restrict_type"; break; case DW_TAG_rvalue_reference_type: *s = "DW_TAG_rvalue_reference_type"; break; case DW_TAG_set_type: *s = "DW_TAG_set_type"; break; case DW_TAG_shared_type: *s = "DW_TAG_shared_type"; break; case DW_TAG_string_type: *s = "DW_TAG_string_type"; break; case DW_TAG_structure_type: *s = "DW_TAG_structure_type"; break; case DW_TAG_subprogram: *s = "DW_TAG_subprogram"; break; case DW_TAG_subrange_type: *s = "DW_TAG_subrange_type"; break; case DW_TAG_subroutine_type: *s = "DW_TAG_subroutine_type"; break; case DW_TAG_template_alias: *s = "DW_TAG_template_alias"; break; case DW_TAG_template_type_parameter: *s = "DW_TAG_template_type_parameter"; break; case DW_TAG_template_value_parameter: *s = "DW_TAG_template_value_parameter"; break; case DW_TAG_thrown_type: *s = "DW_TAG_thrown_type"; break; case DW_TAG_try_block: *s = "DW_TAG_try_block"; break; case DW_TAG_type_unit: *s = "DW_TAG_type_unit"; break; case DW_TAG_typedef: *s = "DW_TAG_typedef"; break; case DW_TAG_union_type: *s = "DW_TAG_union_type"; break; case DW_TAG_unspecified_parameters: *s = "DW_TAG_unspecified_parameters"; break; case DW_TAG_unspecified_type: *s = "DW_TAG_unspecified_type"; break; case DW_TAG_variable: *s = "DW_TAG_variable"; break; case DW_TAG_variant: *s = "DW_TAG_variant"; break; case DW_TAG_variant_part: *s = "DW_TAG_variant_part"; break; case DW_TAG_volatile_type: *s = "DW_TAG_volatile_type"; break; case DW_TAG_with_stmt: *s = "DW_TAG_with_stmt"; break; case DW_TAG_format_label: *s = "DW_TAG_format_label"; break; case DW_TAG_function_template: *s = "DW_TAG_function_template"; break; case DW_TAG_class_template: *s = "DW_TAG_class_template"; break; case DW_TAG_GNU_BINCL: *s = "DW_TAG_GNU_BINCL"; break; case DW_TAG_GNU_EINCL: *s = "DW_TAG_GNU_EINCL"; break; case DW_TAG_GNU_template_template_param: *s = "DW_TAG_GNU_template_template_param"; break; case DW_TAG_GNU_template_parameter_pack: *s = "DW_TAG_GNU_template_parameter_pack"; break; case DW_TAG_GNU_formal_parameter_pack: *s = "DW_TAG_GNU_formal_parameter_pack"; break; case DW_TAG_GNU_call_site: *s = "DW_TAG_GNU_call_site"; break; case DW_TAG_GNU_call_site_parameter: *s = "DW_TAG_GNU_call_site_parameter"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_VIRTUALITY_name(unsigned vir, const char **s) { assert(s != NULL); switch (vir) { case DW_VIRTUALITY_none: *s = "DW_VIRTUALITY_none"; break; case DW_VIRTUALITY_virtual: *s = "DW_VIRTUALITY_virtual"; break; case DW_VIRTUALITY_pure_virtual: *s = "DW_VIRTUALITY_pure_virtual"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } int dwarf_get_VIS_name(unsigned vis, const char **s) { assert(s != NULL); switch (vis) { case DW_VIS_local: *s = "DW_VIS_local"; break; case DW_VIS_exported: *s = "DW_VIS_exported"; break; case DW_VIS_qualified: *s = "DW_VIS_qualified"; break; default: return (DW_DLV_NO_ENTRY); } return (DW_DLV_OK); } Index: vendor/elftoolchain/dist/libelf/gelf_newehdr.3 =================================================================== --- vendor/elftoolchain/dist/libelf/gelf_newehdr.3 (revision 317072) +++ vendor/elftoolchain/dist/libelf/gelf_newehdr.3 (revision 317073) @@ -1,185 +1,194 @@ .\" 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_newehdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" $Id: gelf_newehdr.3 3500 2016-12-04 11:08:44Z jkoshy $ .\" .Dd October 22, 2007 .Os .Dt GELF_NEWEHDR 3 .Sh NAME .Nm elf32_newehdr , .Nm elf64_newehdr , .Nm gelf_newehdr .Nd retrieve or allocate the object file header .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Ft "Elf32_Ehdr *" .Fn elf32_newehdr "Elf *elf" .Ft "Elf64_Ehdr *" .Fn elf64_newehdr "Elf *elf" .In gelf.h .Ft "void *" .Fn gelf_newehdr "Elf *elf" "int elfclass" .Sh DESCRIPTION These functions retrieve the ELF header from the ELF descriptor .Ar elf , allocating a new header if needed. File data structures are translated to their in-memory representations as described in .Xr elf 3 . .Pp Function .Fn elf32_newehdr returns a pointer to a 32 bit .Vt Elf32_Ehdr structure. Function .Fn elf64_newehdr returns a pointer to a 64 bit .Vt Elf64_Ehdr structure. .Pp When argument .Ar elfclass has value .Dv ELFCLASS32 , function .Fn gelf_newehdr returns the value returned by .Fn elf32_newehdr "elf" . When argument .Ar elfclass has value .Dv ELFCLASS64 it returns the value returned by .Fn elf64_newehdr "elf" . .Pp If a fresh header structure is allocated, the members of the structure are initialized as follows: .Bl -tag -width indent .It Va "e_ident[EI_MAG0..EI_MAG3]" Identification bytes at offsets .Dv EI_MAG0 , .Dv EI_MAG1 , .Dv EI_MAG2 and .Dv EI_MAG3 are set to the ELF signature. .It Va "e_ident[EI_CLASS]" The identification byte at offset .Dv EI_CLASS is set to the ELF class associated with the function being called or to argument .Ar elfclass for function .Fn gelf_newehdr . .It Va "e_ident[EI_DATA]" The identification byte at offset .Dv EI_DATA is set to .Dv ELFDATANONE . .It Va "e_ident[EI_VERSION]" The identification byte at offset .Dv EI_VERSION is set to the ELF library's operating version set by a prior call to .Xr elf_version 3 . .It Va e_machine is set to .Dv EM_NONE . .It Va e_type is set to .Dv ELF_K_NONE . .It Va e_version is set to the ELF library's operating version set by a prior call to .Xr elf_version 3 . .El .Pp Other members of the header are set to zero. The application is responsible for changing these values as needed before calling .Fn elf_update . .Pp If successful, these three functions set the .Dv ELF_F_DIRTY flag on ELF descriptor .Ar elf . .Sh RETURN VALUES These functions return a pointer to a translated header descriptor if successful, or NULL on failure. +.Sh COMPATIBILITY +The +.Fn gelf_newehdr +function uses a type of +.Ft "void *" +for its returned value. +This differs from some other implementations of the ELF(3) API, which use an +.Ft "unsigned long" +return type. .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 elf was null. .It Bq Er ELF_E_ARGUMENT Argument .Ar elf was not a descriptor for an ELF object. .It Bq Er ELF_E_ARGUMENT Argument .Ar elfclass had an unsupported value. .It Bq Er ELF_E_ARGUMENT The class of the ELF descriptor .Ar elf did not match that of the requested operation. .It Bq Er ELF_E_ARGUMENT For function .Fn gelf_newehdr , the class of argument .Ar elf was not .Dv ELFCLASSNONE and did not match the argument .Ar elfclass . .It Bq Er ELF_E_CLASS The ELF class of descriptor .Ar elf did not match that of the API function being called. .It Bq Er ELF_E_HEADER A malformed ELF header was detected. .It Bq Er ELF_E_RESOURCE An out of memory condition was detected during execution. .It Bq Er ELF_E_SECTION The ELF descriptor in argument .Ar elf did not adhere to the conventions used for extended numbering. .It Bq Er ELF_E_VERSION The ELF descriptor .Ar elf had an unsupported ELF version number. .El .Sh SEE ALSO .Xr elf 3 , .Xr elf32_getehdr 3 , .Xr elf64_getehdr 3 , .Xr elf_flagdata 3 , .Xr elf_getident 3 , .Xr elf_update 3 , .Xr elf_version 3 , .Xr gelf 3 , .Xr gelf_getehdr 3 , .Xr elf 5 Index: vendor/elftoolchain/dist/libelf/gelf_newphdr.3 =================================================================== --- vendor/elftoolchain/dist/libelf/gelf_newphdr.3 (revision 317072) +++ vendor/elftoolchain/dist/libelf/gelf_newphdr.3 (revision 317073) @@ -1,133 +1,142 @@ .\" 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_newphdr.3 189 2008-07-20 10:38:08Z jkoshy $ +.\" $Id: gelf_newphdr.3 3500 2016-12-04 11:08:44Z jkoshy $ .\" .Dd October 22, 2007 .Os .Dt GELF_NEWPHDR 3 .Sh NAME .Nm elf32_newphdr , .Nm elf64_newphdr , .Nm gelf_newphdr .Nd allocate an ELF program header table .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In libelf.h .Ft "Elf32_Phdr *" .Fn elf32_newphdr "Elf *elf" "size_t count" .Ft "Elf64_Phdr *" .Fn elf64_newphdr "Elf *elf" "size_t count" .In gelf.h .Ft "void *" .Fn gelf_newphdr "Elf *elf" "size_t count" .Sh DESCRIPTION These functions allocate an ELF Program Header table for an ELF descriptor. .Vt Elf32_Phdr and .Vt Elf64_Phdr descriptors are described further in .Xr elf 5 . .Pp Functions .Fn elf32_newphdr and .Fn elf64_newphdr allocate a table of .Ar count .Vt Elf32_Phdr and .Vt Elf64_Phdr descriptors respectively, discarding any existing program header table already present in the ELF descriptor .Ar elf . A value of zero for argument .Ar count may be used to delete an existing program header table from an ELF descriptor. .Pp Function .Fn gelf_newphdr will return a table of .Vt Elf32_Phdr or .Vt Elf64_Phdr with .Ar count elements depending on the ELF class of ELF descriptor .Ar elf . .Pp The functions set the .Dv ELF_F_DIRTY flag on the program header table. All members of the returned array of Phdr structures will be initialized to zero. .Pp After a successful call to these functions, the pointer returned by a prior call to .Fn elf32_getphdr or .Fn elf64_getphdr on the same descriptor .Ar elf will no longer be valid. .Sh RETURN VALUES The functions a valid pointer if successful, or NULL in case an error was encountered. +.Sh COMPATIBILITY +The +.Fn gelf_newphdr +function uses a type of +.Ft "void *" +for its returned value. +This differs from some other implementations of the ELF(3) API, which use an +.Ft "unsigned long" +return type. .Sh ERRORS These functions may fail with the following errors: .Bl -tag -width "[ELF_E_RESOURCE]" .It Bq Er ELF_E_ARGUMENT Argument .Ar elf was NULL. .It Bq Er ELF_E_ARGUMENT Argument .Ar elf was not a descriptor for an ELF object. .It Bq Er ELF_E_CLASS ELF descriptor .Ar elf was of an unrecognized class. .It Bq Er ELF_E_RESOURCE An out of memory condition was detected. .It Bq Er ELF_E_SEQUENCE An executable header was not allocated for ELF descriptor .Ar elf before using these APIs. .El .Sh SEE ALSO .Xr elf 3 , .Xr elf32_getphdr 3 , .Xr elf32_newehdr 3 , .Xr elf64_getphdr 3 , .Xr elf64_newehdr 3 , .Xr elf_flagphdr 3 , .Xr elf_getphnum 3 , .Xr gelf 3 , .Xr gelf_getphdr 3 , .Xr gelf_newehdr 3 , .Xr elf 5 Index: vendor/elftoolchain/dist/libelftc/elftc_bfd_find_target.3 =================================================================== --- vendor/elftoolchain/dist/libelftc/elftc_bfd_find_target.3 (revision 317072) +++ vendor/elftoolchain/dist/libelftc/elftc_bfd_find_target.3 (revision 317073) @@ -1,194 +1,200 @@ .\" 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. .\" 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_bfd_find_target.3 3488 2016-08-24 18:15:57Z emaste $ +.\" $Id: elftc_bfd_find_target.3 3516 2017-02-10 02:33:08Z emaste $ .\" .Dd November 30, 2011 .Os .Dt ELFTC_BFD_FIND_TARGET .Sh NAME .Nm elftc_bfd_find_target , .Nm elftc_bfd_target_byteorder , .Nm elftc_bfd_target_class , .Nm elftc_bfd_target_flavor , .Nm elftc_bfd_target_machine .Nd binary object descriptor handling .Sh LIBRARY .Lb libelftc .Sh SYNOPSIS .In libelftc.h .Vt struct Elftc_Bfd_Target; .Ft "Elftc_Bfd_Target *" .Fn elftc_bfd_find_target "const char *target_name" .Ft "unsigned int" .Fn elftc_bfd_target_class "Elftc_Bfd_Target *target" .Ft "unsigned int" .Fn elftc_bfd_target_byteorder "Elftc_Bfd_Target *target" .Ft Elftc_Bfd_Target_Flavor .Fn elftc_bfd_target_flavor "Elftc_Bfd_Target *target" .Ft "unsigned int" .Fn elftc_bfd_target_machine "Elftc_Bfd_Target *target" .Sh DESCRIPTION Function .Fn elftc_bfd_find_target locates a binary object descriptor corresponding to the descriptor name in argument .Ar "target_name" . Binary object descriptors encapsulate properties of an object format such as its file representation, ELF class, and byte endianness. .Pp Known descriptor names and their properties include: .Bl -column -offset "XXXX" ".Li elf32-x86-64-freebsd" "Object format" "Byte Order" "Bit Width" .It Em Name Ta Em "Object Format" Ta Em "Byte Order" Ta Em "Bit Width" .It Li binary Ta Binary Ta - Ta - .It Li efi-app-ia32 Ta PE Ta LSB Ta 32 .It Li efi-app-x86_64 Ta PE Ta LSB Ta 64 .It Li elf32-avr Ta ELF Ta LSB Ta 32 .It Li elf32-big Ta ELF Ta MSB Ta 32 .It Li elf32-bigarm Ta ELF Ta MSB Ta 32 .It Li elf32-bigmips Ta ELF Ta MSB Ta 32 .It Li elf32-i386 Ta ELF Ta LSB Ta 32 .It Li elf32-i386-freebsd Ta ELF Ta LSB Ta 32 .It Li elf32-ia64-big Ta ELF Ta MSB Ta 32 .It Li elf32-little Ta ELF Ta LSB Ta 32 .It Li elf32-littlearm Ta ELF Ta LSB Ta 32 .It Li elf32-littlemips Ta ELF Ta LSB Ta 32 .It Li elf32-powerpc Ta ELF Ta MSB Ta 32 +.It Li elf32-powerpc-freebsd Ta ELF Ta MSB Ta 32 .It Li elf32-powerpcle Ta ELF Ta LSB Ta 32 .It Li elf32-sh Ta ELF Ta MSB Ta 32 .It Li elf32-shl Ta ELF Ta LSB Ta 32 .It Li elf32-sh-nbsd Ta ELF Ta MSB Ta 32 .It Li elf32-shl-nbsd Ta ELF Ta LSB Ta 32 .It Li elf32-shbig-linux Ta ELF Ta MSB Ta 32 .It Li elf32-shl-linux Ta ELF Ta LSB Ta 32 .It Li elf32-sparc Ta ELF Ta MSB Ta 32 +.It Li elf32-tradbigmips Ta ELF Ta MSB Ta 32 +.It Li elf32-tradlittlemips Ta ELF Ta LSB Ta 32 .It Li elf64-alpha Ta ELF Ta LSB Ta 64 .It Li elf64-alpha-freebsd Ta ELF Ta LSB Ta 64 .It Li elf64-big Ta ELF Ta MSB Ta 64 .It Li elf64-bigmips Ta ELF Ta MSB Ta 64 .It Li elf64-ia64-big Ta ELF Ta MSB Ta 64 .It Li elf64-ia64-little Ta ELF Ta LSB Ta 64 .It Li elf64-little Ta ELF Ta LSB Ta 64 .It Li elf64-littleaarch64 Ta ELF Ta LSB Ta 64 .It Li elf64-littlemips Ta ELF Ta LSB Ta 64 .It Li elf64-powerpc Ta ELF Ta MSB Ta 64 +.It Li elf64-powerpc-freebsd Ta ELF Ta MSB Ta 64 .It Li elf64-powerpcle Ta ELF Ta LSB Ta 64 .It Li elf64-sh64 Ta ELF Ta MSB Ta 64 .It Li elf64-sh64l Ta ELF Ta LSB Ta 64 .It Li elf64-sh64-nbsd Ta ELF Ta MSB Ta 64 .It Li elf64-sh64l-nbsd Ta ELF Ta LSB Ta 64 .It Li elf64-sh64big-linux Ta ELF Ta MSB Ta 64 .It Li elf64-sh64-linux Ta ELF Ta LSB Ta 64 .It Li elf64-sparc Ta ELF Ta MSB Ta 64 .It Li elf64-sparc-freebsd Ta ELF Ta MSB Ta 64 +.It Li elf64-tradbigmips Ta ELF Ta MSB Ta 64 +.It Li elf64-tradlittlemips Ta ELF Ta LSB Ta 64 .It Li elf64-x86-64 Ta ELF Ta LSB Ta 64 .It Li elf64-x86-64-freebsd Ta ELF Ta LSB Ta 64 .It Li ihex Ta IHEX Ta - Ta - .It Li pei-i386 Ta PE Ta LSB Ta 32 .It Li pei-x86-64 Ta PE Ta LSB Ta 64 .It Li srec Ta SREC Ta - Ta - .It Li symbolsrec Ta SREC Ta - Ta - .El .Pp Function .Fn elftc_bfd_target_byteorder returns the ELF byte order associated with target descriptor .Ar target . .Pp Function .Fn elftc_bfd_target_class returns the ELF class associated with target descriptor .Ar target . .Pp Function .Fn elftc_bfd_target_flavor returns the object format associated with target descriptor .Ar target . The known object formats are: .Bl -tag -offset "XXXX" -width ".Dv ETF_BINARY" -compact .It Dv ETF_ELF An ELF object. .It Dv ETF_BINARY Raw binary. .It Dv ETF_IHEX An object encoded in .Tn Intel hex format. .It Dv ETF_NONE An unknown object format. .It Dv ETF_SREC An object encoded as S-records. .El .Sh RETURN VALUES Function .Fn elftc_bfd_find_target returns a valid pointer to an opaque binary target descriptor if successful, or NULL in case of an error. .Pp Function .Fn elftc_bfd_target_byteorder returns the ELF byte order associated with the target descriptor; one of .Dv ELFDATA2MSB or .Dv ELFDATA2LSB . .Pp Function .Fn elftc_bfd_target_class returns the ELF class associated with the target descriptor; one of .Dv ELFCLASS32 or .Dv ELFCLASS64 . .Pp Function .Fn elftc_bfd_target_machine returns the ELF architecture associated with the target descriptor. .Pp Function .Fn elftc_bfd_target_flavor returns one of .Dv ETF_BINARY , .Dv ETF_ELF , .Dv ETF_IHEX or .Dv ETF_SREC if successful or .Dv ETF_NONE in case of error. .Sh EXAMPLES To return descriptor information associated with target name .Dq elf64-big use: .Bd -literal -offset indent struct Elftc_Bfd_Target *t; if ((t = elftc_bfd_find_target("elf64-big")) == NULL) errx(EXIT_FAILURE, "Cannot find target descriptor"); printf("Class: %s\\n", elftc_bfd_target_class(t) == ELFCLASS32 ? "ELFCLASS32" : "ELFCLASS64"); printf("Byteorder: %s\\n", elftc_bfd_target_byteorder(t) == ELFDATA2LSB ? "LSB" : "MSB"); printf("Flavor: %d\\n", elftc_bfd_target_flavor(t)); .Ed .Sh SEE ALSO .Xr elf 3 Index: vendor/elftoolchain/dist/libelftc/libelftc_bfdtarget.c =================================================================== --- vendor/elftoolchain/dist/libelftc/libelftc_bfdtarget.c (revision 317072) +++ vendor/elftoolchain/dist/libelftc/libelftc_bfdtarget.c (revision 317073) @@ -1,413 +1,463 @@ /*- * Copyright (c) 2008,2009 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "_libelftc.h" -ELFTC_VCSID("$Id: libelftc_bfdtarget.c 3488 2016-08-24 18:15:57Z emaste $"); +ELFTC_VCSID("$Id: libelftc_bfdtarget.c 3516 2017-02-10 02:33:08Z emaste $"); struct _Elftc_Bfd_Target _libelftc_targets[] = { { .bt_name = "binary", .bt_type = ETF_BINARY, }, { .bt_name = "elf32-avr", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_AVR, }, { .bt_name = "elf32-big", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, }, { .bt_name = "elf32-bigarm", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_ARM, }, { .bt_name = "elf32-bigmips", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_MIPS, }, { .bt_name = "elf32-i386", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_386, }, { .bt_name = "elf32-i386-freebsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_386, .bt_osabi = ELFOSABI_FREEBSD, }, { .bt_name = "elf32-ia64-big", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_IA_64, }, { .bt_name = "elf32-little", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, }, { .bt_name = "elf32-littlearm", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_ARM, }, { .bt_name = "elf32-littlemips", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_MIPS, }, { .bt_name = "elf32-powerpc", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_PPC, }, { + .bt_name = "elf32-powerpc-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_PPC, + .bt_osabi = ELFOSABI_FREEBSD, + }, + + { .bt_name = "elf32-powerpcle", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_PPC, }, { .bt_name = "elf32-sh", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SH, }, { .bt_name = "elf32-shl", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SH, }, { .bt_name = "elf32-sh-nbsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_NETBSD, }, { .bt_name = "elf32-shl-nbsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_NETBSD, }, { .bt_name = "elf32-shbig-linux", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_LINUX, }, { .bt_name = "elf32-sh-linux", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_LINUX, }, { .bt_name = "elf32-sparc", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS32, .bt_machine = EM_SPARC, }, { + .bt_name = "elf32-tradbigmips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf32-tradlittlemips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_MIPS, + }, + + { .bt_name = "elf64-alpha", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_ALPHA, }, { .bt_name = "elf64-alpha-freebsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_ALPHA, .bt_osabi = ELFOSABI_FREEBSD }, { .bt_name = "elf64-big", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, }, { .bt_name = "elf64-bigmips", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_MIPS, }, { .bt_name = "elf64-ia64-big", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_IA_64, }, { .bt_name = "elf64-ia64-little", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_IA_64, }, { .bt_name = "elf64-little", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, }, { .bt_name = "elf64-littleaarch64", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_AARCH64, }, { .bt_name = "elf64-littlemips", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_MIPS, }, { .bt_name = "elf64-powerpc", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_PPC64, }, { + .bt_name = "elf64-powerpc-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_PPC64, + .bt_osabi = ELFOSABI_FREEBSD, + }, + + { .bt_name = "elf64-powerpcle", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_PPC64, }, { .bt_name = "elf64-sh64", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SH, }, { .bt_name = "elf64-sh64l", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SH, }, { .bt_name = "elf64-sh64-nbsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_NETBSD, }, { .bt_name = "elf64-sh64l-nbsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_NETBSD, }, { .bt_name = "elf64-sh64big-linux", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_LINUX, }, { .bt_name = "elf64-sh64-linux", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SH, .bt_osabi = ELFOSABI_LINUX, }, { .bt_name = "elf64-sparc", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SPARCV9, }, { .bt_name = "elf64-sparc-freebsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2MSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_SPARCV9, .bt_osabi = ELFOSABI_FREEBSD + }, + + { + .bt_name = "elf64-tradbigmips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf64-tradlittlemips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_MIPS, }, { .bt_name = "elf64-x86-64", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_X86_64, }, { .bt_name = "elf64-x86-64-freebsd", .bt_type = ETF_ELF, .bt_byteorder = ELFDATA2LSB, .bt_elfclass = ELFCLASS64, .bt_machine = EM_X86_64, .bt_osabi = ELFOSABI_FREEBSD }, { .bt_name = "ihex", .bt_type = ETF_IHEX, }, { .bt_name = "srec", .bt_type = ETF_SREC, }, { .bt_name = "symbolsrec", .bt_type = ETF_SREC, }, { .bt_name = "efi-app-ia32", .bt_type = ETF_EFI, .bt_machine = EM_386, }, { .bt_name = "efi-app-x86_64", .bt_type = ETF_EFI, .bt_machine = EM_X86_64, }, { .bt_name = "pei-i386", .bt_type = ETF_PE, .bt_machine = EM_386, }, { .bt_name = "pei-x86-64", .bt_type = ETF_PE, .bt_machine = EM_X86_64, }, { .bt_name = NULL, .bt_type = ETF_NONE, }, }; Index: vendor/elftoolchain/dist/libelftc/libelftc_dem_arm.c =================================================================== --- vendor/elftoolchain/dist/libelftc/libelftc_dem_arm.c (revision 317072) +++ vendor/elftoolchain/dist/libelftc/libelftc_dem_arm.c (revision 317073) @@ -1,1227 +1,1216 @@ /*- * Copyright (c) 2008 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_arm.c 3447 2016-05-03 13:32:23Z emaste $"); +ELFTC_VCSID("$Id: libelftc_dem_arm.c 3513 2016-12-29 07:04:22Z kaiwang27 $"); /** * @file cpp_demangle_arm.c * @brief Decode function name encoding in ARM. * * Function name encoding in "The Annotated C++ Reference Manual". * * Ref : "The Annotated C++ Reference Manual", Margaet A.Ellis, * Bjarne Stroustrup, AT&T Bell Laboratories 1990, pp 122-126. */ enum encode_type { ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER }; struct cstring { char *buf; size_t size; }; struct demangle_data { bool ptr, ref, cnst, array; struct cstring array_str; const char *p; enum encode_type type; struct vector_str vec; struct vector_str arg; }; #define SIMPLE_HASH(x,y) (64 * x + y) +#define VEC_PUSH_STR(d,s) vector_str_push((d), (s), strlen((s))) #define CPP_DEMANGLE_ARM_TRY 128 static void dest_cstring(struct cstring *); static void dest_demangle_data(struct demangle_data *); static bool init_cstring(struct cstring *, size_t); static bool init_demangle_data(struct demangle_data *); static bool push_CTDT(const char *, size_t, struct vector_str *); static bool read_array(struct demangle_data *); static bool read_class(struct demangle_data *); static bool read_func(struct demangle_data *); static bool read_func_name(struct demangle_data *); static bool read_func_ptr(struct demangle_data *); static bool read_memptr(struct demangle_data *); static bool read_op(struct demangle_data *); static bool read_op_user(struct demangle_data *); static bool read_qual_name(struct demangle_data *); static int read_subst(struct demangle_data *); static int read_subst_iter(struct demangle_data *); static bool read_type(struct demangle_data *); /** * @brief Decode the input string by the ARM style. * * @return New allocated demangled string or NULL if failed. */ char * cpp_demangle_ARM(const char *org) { struct demangle_data d; size_t arg_begin, arg_len; unsigned int try; char *rtn, *arg; if (org == NULL) return (NULL); if (init_demangle_data(&d) == false) return (NULL); try = 0; rtn = NULL; d.p = org; if (read_func_name(&d) == false) goto clean; if (d.type == ENCODE_OP_CT) { if (push_CTDT("::", 2, &d.vec) == false) goto clean; goto flat; } if (d.type == ENCODE_OP_DT) { if (push_CTDT("::~", 3, &d.vec) == false) goto clean; goto flat; } if (d.type == ENCODE_OP_USER) goto flat; /* function type */ if (*d.p != 'F') goto clean; ++d.p; /* start argument types */ - if (vector_str_push(&d.vec, "(", 1) == false) + if (VEC_PUSH_STR(&d.vec, "(") == false) goto clean; for (;;) { if (*d.p == 'T') { const int rtn_subst = read_subst(&d); if (rtn_subst == -1) goto clean; else if (rtn_subst == 1) break; continue; } if (*d.p == 'N') { const int rtn_subst_iter = read_subst_iter(&d); if (rtn_subst_iter == -1) goto clean; else if(rtn_subst_iter == 1) break; continue; } arg_begin = d.vec.size; if (read_type(&d) == false) goto clean; if (d.ptr == true) { - if (vector_str_push(&d.vec, "*", 1) == false) + if (VEC_PUSH_STR(&d.vec, "*") == false) goto clean; d.ptr = false; } if (d.ref == true) { - if (vector_str_push(&d.vec, "&", 1) == false) + if (VEC_PUSH_STR(&d.vec, "&") == false) goto clean; d.ref = false; } if (d.cnst == true) { - if (vector_str_push(&d.vec, " const", 6) == false) + if (VEC_PUSH_STR(&d.vec, " const") == false) goto clean; d.cnst = false; } if (d.array == true) { if (vector_str_push(&d.vec, d.array_str.buf, d.array_str.size) == false) goto clean; dest_cstring(&d.array_str); d.array = false; } if (*d.p == '\0') break; if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1, &arg_len)) == NULL) goto clean; if (vector_str_push(&d.arg, arg, arg_len) == false) goto clean; free(arg); - if (vector_str_push(&d.vec, ", ", 2) == false) + if (VEC_PUSH_STR(&d.vec, ", ") == false) goto clean; if (++try > CPP_DEMANGLE_ARM_TRY) goto clean; } /* end argument types */ - if (vector_str_push(&d.vec, ")", 1) == false) + if (VEC_PUSH_STR(&d.vec, ")") == false) goto clean; flat: rtn = vector_str_get_flat(&d.vec, NULL); clean: dest_demangle_data(&d); return (rtn); } /** * @brief Test input string is encoded by the ARM style. * * @return True if input string is encoded by the ARM style. */ bool is_cpp_mangled_ARM(const char *org) { if (org == NULL) return (false); return (strstr(org, "__") != NULL); } static void dest_cstring(struct cstring *s) { if (s == NULL) return; free(s->buf); s->buf = NULL; s->size = 0; } static void dest_demangle_data(struct demangle_data *d) { if (d != NULL) { vector_str_dest(&d->arg); vector_str_dest(&d->vec); dest_cstring(&d->array_str); } } static bool init_cstring(struct cstring *s, size_t len) { if (s == NULL || len <= 1) return (false); if ((s->buf = malloc(sizeof(char) * len)) == NULL) return (false); s->size = len - 1; return (true); } static bool init_demangle_data(struct demangle_data *d) { if (d == NULL) return (false); d->ptr = false; d->ref = false; d->cnst = false; d->array = false; d->array_str.buf = NULL; d->array_str.size = 0; d->type = ENCODE_FUNC; if (vector_str_init(&d->vec) == false) return (false); if (vector_str_init(&d->arg) == false) { vector_str_dest(&d->vec); return (false); } return (true); } static bool push_CTDT(const char *s, size_t l, struct vector_str *v) { if (s == NULL || l == 0 || v == NULL) return (false); if (vector_str_push(v, s, l) == false) return (false); assert(v->size > 1); - if (vector_str_push(v, v->container[v->size - 2], - strlen(v->container[v->size - 2])) == false) + if (VEC_PUSH_STR(v, v->container[v->size - 2]) == false) return (false); - if (vector_str_push(v, "()", 2) == false) + if (VEC_PUSH_STR(v, "()") == false) return (false); return (true); } static bool read_array(struct demangle_data *d) { size_t len; const char *end; if (d == NULL || d->p == NULL) return (false); end = d->p; assert(end != NULL); for (;;) { if (*end == '\0') return (false); if (ELFTC_ISDIGIT(*end) == 0) break; ++end; } if (*end != '_') return (false); len = end - d->p; assert(len > 0); dest_cstring(&d->array_str); if (init_cstring(&d->array_str, len + 3) == false) return (false); strncpy(d->array_str.buf + 1, d->p, len); *d->array_str.buf = '['; *(d->array_str.buf + len + 1) = ']'; d->array = true; d->p = end + 1; return (true); } static bool read_class(struct demangle_data *d) { size_t len; char *str; if (d == NULL) return (false); len = strtol(d->p, &str, 10); if (len == 0 && (errno == EINVAL || errno == ERANGE)) return (false); assert(len > 0); assert(str != NULL); if (vector_str_push(&d->vec, str, len) == false) return (false); d->p = str + len; return (true); } static bool read_func(struct demangle_data *d) { size_t len; const char *name; char *delim; if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); if ((delim = strstr(d->p, "__")) == NULL) return (false); len = delim - d->p; assert(len != 0); name = d->p; d->p = delim + 2; if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; if (read_qual_name(d) == false) return (false); } else if (ELFTC_ISDIGIT(*d->p)) { if (read_class(d) == false) return (false); - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) return (false); } if (vector_str_push(&d->vec, name, len) == false) return (false); return (true); } static bool read_func_name(struct demangle_data *d) { size_t len; bool rtn; char *op_name; if (d == NULL) return (false); rtn = false; op_name = NULL; assert(d->p != NULL && "d->p (org str) is NULL"); if (*d->p == '_' && *(d->p + 1) == '_') { d->p += 2; d->type = ENCODE_OP; if (read_op(d) == false) return (false); if (d->type == ENCODE_OP_CT || d->type == ENCODE_OP_DT || d->type == ENCODE_OP_USER) return (true); /* skip "__" */ d->p += 2; /* assume delimiter is removed */ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; assert(d->vec.size > 0); len = strlen(d->vec.container[d->vec.size - 1]); if ((op_name = malloc(sizeof(char) * (len + 1))) == NULL) return (false); snprintf(op_name, len + 1, "%s", d->vec.container[d->vec.size - 1]); vector_str_pop(&d->vec); if (read_qual_name(d) == false) goto clean; - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) goto clean; if (vector_str_push(&d->vec, op_name, len) == false) goto clean; rtn = true; } else if (ELFTC_ISDIGIT(*d->p)) { assert(d->vec.size > 0); len = strlen(d->vec.container[d->vec.size - 1]); if ((op_name = malloc(sizeof(char) * (len + 1))) == NULL) return (false); snprintf(op_name, len + 1, "%s", d->vec.container[d->vec.size - 1]); vector_str_pop(&d->vec); if (read_class(d) == false) goto clean; - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) goto clean; if (vector_str_push(&d->vec, op_name, len) == false) goto clean; rtn = true; } } else return (read_func(d)); clean: free(op_name); return (rtn); } /* Read function ptr type */ static bool read_func_ptr(struct demangle_data *d) { struct demangle_data fptr; size_t arg_len, rtn_len; char *arg_type, *rtn_type; int lim; if (d == NULL) return (false); if (init_demangle_data(&fptr) == false) return (false); fptr.p = d->p + 1; lim = 0; arg_type = NULL; rtn_type = NULL; for (;;) { if (read_type(&fptr) == false) { dest_demangle_data(&fptr); return (false); } if (fptr.ptr == true) { - if (vector_str_push(&fptr.vec, "*", 1) == false) { + if (VEC_PUSH_STR(&fptr.vec, "*") == false) { dest_demangle_data(&fptr); return (false); } fptr.ptr = false; } if (fptr.ref == true) { - if (vector_str_push(&fptr.vec, "&", 1) == false) { + if (VEC_PUSH_STR(&fptr.vec, "&") == false) { dest_demangle_data(&fptr); return (false); } fptr.ref = false; } if (fptr.cnst == true) { - if (vector_str_push(&fptr.vec, " const", 6) == false) { + if (VEC_PUSH_STR(&fptr.vec, " const") == false) { dest_demangle_data(&fptr); return (false); } fptr.cnst = false; } if (*fptr.p == '_') break; - if (vector_str_push(&fptr.vec, ", ", 2) == false) { + if (VEC_PUSH_STR(&fptr.vec, ", ") == false) { dest_demangle_data(&fptr); return (false); } if (++lim > CPP_DEMANGLE_ARM_TRY) { dest_demangle_data(&fptr); return (false); } } arg_type = vector_str_get_flat(&fptr.vec, &arg_len); /* skip '_' */ d->p = fptr.p + 1; dest_demangle_data(&fptr); if (init_demangle_data(&fptr) == false) { free(arg_type); return (false); } fptr.p = d->p; lim = 0; if (read_type(&fptr) == false) { free(arg_type); dest_demangle_data(&fptr); return (false); } rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len); d->p = fptr.p; dest_demangle_data(&fptr); if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) { free(rtn_type); free(arg_type); return (false); } free(rtn_type); - if (vector_str_push(&d->vec, " (*)(", 5) == false) { + if (VEC_PUSH_STR(&d->vec, " (*)(") == false) { free(arg_type); return (false); } if (vector_str_push(&d->vec, arg_type, arg_len) == false) { free(arg_type); return (false); } free(arg_type); - return (vector_str_push(&d->vec, ")", 1)); + return (VEC_PUSH_STR(&d->vec, ")")); } static bool read_memptr(struct demangle_data *d) { struct demangle_data mptr; size_t len; bool rtn; char *mptr_str; if (d == NULL || d->p == NULL) return (false); if (init_demangle_data(&mptr) == false) return (false); rtn = false; mptr_str = NULL; mptr.p = d->p; if (*mptr.p == 'Q') { ++mptr.p; if (read_qual_name(&mptr) == false) goto clean; } else { if (read_class(&mptr) == false) goto clean; } d->p = mptr.p; if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL) goto clean; if (vector_str_push(&d->vec, mptr_str, len) == false) goto clean; - if (vector_str_push(&d->vec, "::*", 3) == false) + if (VEC_PUSH_STR(&d->vec, "::*") == false) goto clean; rtn = true; clean: free(mptr_str); dest_demangle_data(&mptr); return (rtn); } static bool read_op(struct demangle_data *d) { if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); switch (SIMPLE_HASH(*(d->p), *(d->p+1))) { case SIMPLE_HASH('m', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "operator*", 9)); + return (VEC_PUSH_STR(&d->vec, "operator*")); case SIMPLE_HASH('d', 'v') : d->p += 2; - return (vector_str_push(&d->vec, "operator/", 9)); + return (VEC_PUSH_STR(&d->vec, "operator/")); case SIMPLE_HASH('m', 'd') : d->p += 2; - return (vector_str_push(&d->vec, "operator%", 9)); + return (VEC_PUSH_STR(&d->vec, "operator%")); case SIMPLE_HASH('p', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "operator+", 9)); + return (VEC_PUSH_STR(&d->vec, "operator+")); case SIMPLE_HASH('m', 'i') : d->p += 2; - return (vector_str_push(&d->vec, "operator-", 9)); + return (VEC_PUSH_STR(&d->vec, "operator-")); case SIMPLE_HASH('l', 's') : d->p += 2; - return (vector_str_push(&d->vec, "operator<<", 10)); + return (VEC_PUSH_STR(&d->vec, "operator<<")); case SIMPLE_HASH('r', 's') : d->p += 2; - return (vector_str_push(&d->vec, "operator>>", 10)); + return (VEC_PUSH_STR(&d->vec, "operator>>")); case SIMPLE_HASH('e', 'q') : d->p += 2; - return (vector_str_push(&d->vec, "operator==", 10)); + return (VEC_PUSH_STR(&d->vec, "operator==")); case SIMPLE_HASH('n', 'e') : d->p += 2; - return (vector_str_push(&d->vec, "operator!=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator!=")); case SIMPLE_HASH('l', 't') : d->p += 2; - return (vector_str_push(&d->vec, "operator<", 9)); + return (VEC_PUSH_STR(&d->vec, "operator<")); case SIMPLE_HASH('g', 't') : d->p += 2; - return (vector_str_push(&d->vec, "operator>", 9)); + return (VEC_PUSH_STR(&d->vec, "operator>")); case SIMPLE_HASH('l', 'e') : d->p += 2; - return (vector_str_push(&d->vec, "operator<=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator<=")); case SIMPLE_HASH('g', 'e') : d->p += 2; - return (vector_str_push(&d->vec, "operator>=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator>=")); case SIMPLE_HASH('a', 'd') : d->p += 2; if (*d->p == 'v') { ++d->p; - return (vector_str_push(&d->vec, "operator/=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator/=")); } else - return (vector_str_push(&d->vec, "operator&", 9)); + return (VEC_PUSH_STR(&d->vec, "operator&")); case SIMPLE_HASH('o', 'r') : d->p += 2; - return (vector_str_push(&d->vec, "operator|", 9)); + return (VEC_PUSH_STR(&d->vec, "operator|")); case SIMPLE_HASH('e', 'r') : d->p += 2; - return (vector_str_push(&d->vec, "operator^", 9)); + return (VEC_PUSH_STR(&d->vec, "operator^")); case SIMPLE_HASH('a', 'a') : d->p += 2; if (*d->p == 'd') { ++d->p; - return (vector_str_push(&d->vec, "operator&=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator&=")); } else - return (vector_str_push(&d->vec, "operator&&", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator&&")); case SIMPLE_HASH('o', 'o') : d->p += 2; - return (vector_str_push(&d->vec, "operator||", 10)); + return (VEC_PUSH_STR(&d->vec, "operator||")); case SIMPLE_HASH('n', 't') : d->p += 2; - return (vector_str_push(&d->vec, "operator!", 9)); + return (VEC_PUSH_STR(&d->vec, "operator!")); case SIMPLE_HASH('c', 'o') : d->p += 2; - return (vector_str_push(&d->vec, "operator~", 9)); + return (VEC_PUSH_STR(&d->vec, "operator~")); case SIMPLE_HASH('p', 'p') : d->p += 2; - return (vector_str_push(&d->vec, "operator++", 10)); + return (VEC_PUSH_STR(&d->vec, "operator++")); case SIMPLE_HASH('m', 'm') : d->p += 2; - return (vector_str_push(&d->vec, "operator--", 10)); + return (VEC_PUSH_STR(&d->vec, "operator--")); case SIMPLE_HASH('a', 's') : d->p += 2; - return (vector_str_push(&d->vec, "operator=", 9)); + return (VEC_PUSH_STR(&d->vec, "operator=")); case SIMPLE_HASH('r', 'f') : d->p += 2; - return (vector_str_push(&d->vec, "operator->", 10)); + return (VEC_PUSH_STR(&d->vec, "operator->")); case SIMPLE_HASH('a', 'p') : /* apl */ if (*(d->p + 2) != 'l') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator+=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator+=")); case SIMPLE_HASH('a', 'm') : d->p += 2; if (*d->p == 'i') { ++d->p; - return (vector_str_push(&d->vec, "operator-=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator-=")); } else if (*d->p == 'u') { ++d->p; - return (vector_str_push(&d->vec, "operator*=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator*=")); } else if (*d->p == 'd') { ++d->p; - return (vector_str_push(&d->vec, "operator%=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator%=")); } return (false); case SIMPLE_HASH('a', 'l') : /* als */ if (*(d->p + 2) != 's') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator<<=", 11)); + return (VEC_PUSH_STR(&d->vec, "operator<<=")); case SIMPLE_HASH('a', 'r') : /* ars */ if (*(d->p + 2) != 's') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator>>=", 11)); + return (VEC_PUSH_STR(&d->vec, "operator>>=")); case SIMPLE_HASH('a', 'o') : /* aor */ if (*(d->p + 2) != 'r') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator|=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator|=")); case SIMPLE_HASH('a', 'e') : /* aer */ if (*(d->p + 2) != 'r') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator^=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator^=")); case SIMPLE_HASH('c', 'm') : d->p += 2; - return (vector_str_push(&d->vec, "operator,", 9)); + return (VEC_PUSH_STR(&d->vec, "operator,")); case SIMPLE_HASH('r', 'm') : d->p += 2; - return (vector_str_push(&d->vec, "operator->*", 11)); + return (VEC_PUSH_STR(&d->vec, "operator->*")); case SIMPLE_HASH('c', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "()", 2)); + return (VEC_PUSH_STR(&d->vec, "()")); case SIMPLE_HASH('v', 'c') : d->p += 2; - return (vector_str_push(&d->vec, "[]", 2)); + return (VEC_PUSH_STR(&d->vec, "[]")); case SIMPLE_HASH('c', 't') : d->p += 4; d->type = ENCODE_OP_CT; if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; return (read_qual_name(d)); } else if (ELFTC_ISDIGIT(*d->p)) return (read_class(d)); return (false); case SIMPLE_HASH('d', 't') : d->p += 4; d->type = ENCODE_OP_DT; if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; return (read_qual_name(d)); } else if (ELFTC_ISDIGIT(*d->p)) return (read_class(d)); return (false); case SIMPLE_HASH('n', 'w') : d->p += 2; - return (vector_str_push(&d->vec, "operator new()", 14)); + return (VEC_PUSH_STR(&d->vec, "operator new()")); case SIMPLE_HASH('d', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "operator delete()", - 17)); + return (VEC_PUSH_STR(&d->vec, "operator delete()")); case SIMPLE_HASH('o', 'p') : /* __op__ */ d->p += 2; d->type = ENCODE_OP_USER; return (read_op_user(d)); default : return (false); }; } static bool read_op_user(struct demangle_data *d) { struct demangle_data from, to; size_t from_len, to_len; bool rtn; char *from_str, *to_str; if (d == NULL) return (false); if (init_demangle_data(&from) == false) return (false); rtn = false; from_str = NULL; to_str = NULL; if (init_demangle_data(&to) == false) goto clean; to.p = d->p; if (*to.p == 'Q') { ++to.p; if (read_qual_name(&to) == false) goto clean; /* pop last '::' */ if (vector_str_pop(&to.vec) == false) goto clean; } else { if (read_class(&to) == false) goto clean; /* skip '__' */ to.p += 2; } if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL) goto clean; from.p = to.p; if (*from.p == 'Q') { ++from.p; if (read_qual_name(&from) == false) goto clean; /* pop last '::' */ if (vector_str_pop(&from.vec) == false) goto clean; } else { if (read_class(&from) == false) goto clean; } if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL) goto clean; if (vector_str_push(&d->vec, from_str, from_len) == false) goto clean; - if (vector_str_push(&d->vec, "::operator ", 11) == false) + if (VEC_PUSH_STR(&d->vec, "::operator ") == false) return (false); if (vector_str_push(&d->vec, to_str, to_len) == false) goto clean; - rtn = vector_str_push(&d->vec, "()", 2); + rtn = VEC_PUSH_STR(&d->vec, "()"); clean: free(to_str); free(from_str); dest_demangle_data(&to); dest_demangle_data(&from); return (rtn); } /* single digit + class names */ static bool read_qual_name(struct demangle_data *d) { int i; char num; if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); num = *d->p - 48; assert(num > 0); ++d->p; for (i = 0; i < num ; ++i) { if (read_class(d) == false) return (false); - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) return (false); } if (*d->p != '\0') d->p = d->p + 2; return (true); } /* Return -1 at fail, 0 at success, and 1 at end */ static int read_subst(struct demangle_data *d) { size_t idx; char *str; if (d == NULL) return (-1); idx = strtol(d->p + 1, &str, 10); if (idx == 0 && (errno == EINVAL || errno == ERANGE)) return (-1); assert(idx > 0); assert(str != NULL); d->p = str; - if (vector_str_push(&d->vec, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) return (-1); - if (vector_str_push(&d->arg, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) return (-1); if (*d->p == '\0') return (1); return (0); } static int read_subst_iter(struct demangle_data *d) { int i; size_t idx; char repeat; char *str; if (d == NULL) return (-1); ++d->p; assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); repeat = *d->p - 48; assert(repeat > 1); ++d->p; idx = strtol(d->p, &str, 10); if (idx == 0 && (errno == EINVAL || errno == ERANGE)) return (-1); assert(idx > 0); assert(str != NULL); d->p = str; for (i = 0; i < repeat ; ++i) { - if (vector_str_push(&d->vec, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) return (-1); - if (vector_str_push(&d->arg, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) return (-1); if (i != repeat - 1 && - vector_str_push(&d->vec, ", ", 2) == false) + VEC_PUSH_STR(&d->vec, ", ") == false) return (-1); } if (*d->p == '\0') return (1); return (0); } static bool read_type(struct demangle_data *d) { if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' || *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' || *d->p == 'M') { switch (*d->p) { case 'U' : ++d->p; - if (vector_str_push(&d->vec, "unsigned ", 9) == false) + if (VEC_PUSH_STR(&d->vec, "unsigned ") == false) return (false); break; case 'C' : ++d->p; if (*d->p == 'P') d->cnst = true; else { - if (vector_str_push(&d->vec, "const ", 6) == + if (VEC_PUSH_STR(&d->vec, "const ") == false) return (false); } break; case 'V' : ++d->p; - if (vector_str_push(&d->vec, "volatile ", 9) == false) + if (VEC_PUSH_STR(&d->vec, "volatile ") == false) return (false); break; case 'S' : ++d->p; - if (vector_str_push(&d->vec, "signed ", 7) == false) + if (VEC_PUSH_STR(&d->vec, "signed ") == false) return (false); break; case 'P' : ++d->p; if (*d->p == 'F') return (read_func_ptr(d)); else d->ptr = true; break; case 'R' : ++d->p; d->ref = true; break; case 'F' : break; case 'A' : ++d->p; if (read_array(d) == false) return (false); break; case 'M' : ++d->p; if (read_memptr(d) == false) return (false); break; default : break; } } if (ELFTC_ISDIGIT(*d->p)) return (read_class(d)); switch (*d->p) { case 'Q' : ++d->p; return (read_qual_name(d)); case 'v' : ++d->p; - return (vector_str_push(&d->vec, "void", 4)); + return (VEC_PUSH_STR(&d->vec, "void")); case 'c' : ++d->p; - return (vector_str_push(&d->vec, "char", 4)); + return (VEC_PUSH_STR(&d->vec, "char")); case 's' : ++d->p; - return (vector_str_push(&d->vec, "short", 5)); + return (VEC_PUSH_STR(&d->vec, "short")); case 'i' : ++d->p; - return (vector_str_push(&d->vec, "int", 3)); + return (VEC_PUSH_STR(&d->vec, "int")); case 'l' : ++d->p; - return (vector_str_push(&d->vec, "long", 4)); + return (VEC_PUSH_STR(&d->vec, "long")); case 'f' : ++d->p; - return (vector_str_push(&d->vec, "float", 5)); + return (VEC_PUSH_STR(&d->vec, "float")); case 'd': ++d->p; - return (vector_str_push(&d->vec, "double", 6)); + return (VEC_PUSH_STR(&d->vec, "double")); case 'r': ++d->p; - return (vector_str_push(&d->vec, "long double", 11)); + return (VEC_PUSH_STR(&d->vec, "long double")); case 'e': ++d->p; - return (vector_str_push(&d->vec, "...", 3)); + return (VEC_PUSH_STR(&d->vec, "...")); default: return (false); }; /* NOTREACHED */ return (false); } Index: vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu2.c =================================================================== --- vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu2.c (revision 317072) +++ vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu2.c (revision 317073) @@ -1,1376 +1,1365 @@ /*- * Copyright (c) 2008 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_gnu2.c 3447 2016-05-03 13:32:23Z emaste $"); +ELFTC_VCSID("$Id: libelftc_dem_gnu2.c 3513 2016-12-29 07:04:22Z kaiwang27 $"); /** * @file cpp_demangle_gnu2.c * @brief Decode function name encoding in GNU 2. * * Function name encoding in GNU 2 based on ARM style. */ enum encode_type { ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER, ENCODE_OP_TF, ENCODE_OP_TI, ENCODE_OP_VT }; struct cstring { char *buf; size_t size; }; struct demangle_data { bool ptr, ref, cnst, array, cnst_fn, class_name; struct cstring array_str; const char *p; enum encode_type type; struct vector_str vec; struct vector_str arg; }; #define SIMPLE_HASH(x,y) (64 * x + y) +#define VEC_PUSH_STR(d,s) vector_str_push((d), (s), strlen((s))) #define CPP_DEMANGLE_GNU2_TRY 128 static void dest_cstring(struct cstring *); static void dest_demangle_data(struct demangle_data *); static bool init_cstring(struct cstring *, size_t); static bool init_demangle_data(struct demangle_data *); static bool push_CTDT(const char *, size_t, struct vector_str *); static bool read_array(struct demangle_data *); static bool read_class(struct demangle_data *); static bool read_func(struct demangle_data *); static bool read_func_name(struct demangle_data *); static bool read_func_ptr(struct demangle_data *); static bool read_memptr(struct demangle_data *); static bool read_op(struct demangle_data *); static bool read_op_user(struct demangle_data *); static bool read_qual_name(struct demangle_data *); static int read_subst(struct demangle_data *); static int read_subst_iter(struct demangle_data *); static bool read_type(struct demangle_data *); /** * @brief Decode the input string by the GNU 2 style. * * @return New allocated demangled string or NULL if failed. */ char * cpp_demangle_gnu2(const char *org) { struct demangle_data d; size_t arg_begin, arg_len; unsigned int try; char *rtn, *arg; if (org == NULL) return (NULL); if (init_demangle_data(&d) == false) return (NULL); try = 0; rtn = NULL; d.p = org; if (read_func_name(&d) == false) goto clean; switch (d.type) { case ENCODE_FUNC : case ENCODE_OP : break; case ENCODE_OP_CT : if (push_CTDT("::", 2, &d.vec) == false) goto clean; break; case ENCODE_OP_DT : if (push_CTDT("::~", 3, &d.vec) == false) goto clean; - if (vector_str_push(&d.vec, "(void)", 6) == false) + if (VEC_PUSH_STR(&d.vec, "(void)") == false) goto clean; goto flat; case ENCODE_OP_USER : case ENCODE_OP_TF : case ENCODE_OP_TI : case ENCODE_OP_VT : goto flat; } if (*d.p == 'F') ++d.p; else if (*d.p == '\0') { if (d.class_name == true) { - if (vector_str_push(&d.vec, "(void)", 6) == false) + if (VEC_PUSH_STR(&d.vec, "(void)") == false) goto clean; goto flat; } else goto clean; } /* start argument types */ - if (vector_str_push(&d.vec, "(", 1) == false) + if (VEC_PUSH_STR(&d.vec, "(") == false) goto clean; for (;;) { if (*d.p == 'T') { const int rtn_subst = read_subst(&d); if (rtn_subst == -1) goto clean; else if (rtn_subst == 1) break; continue; } if (*d.p == 'N') { const int rtn_subst_iter = read_subst_iter(&d); if (rtn_subst_iter == -1) goto clean; else if(rtn_subst_iter == 1) break; continue; } arg_begin = d.vec.size; if (read_type(&d) == false) goto clean; if (d.ptr == true) { - if (vector_str_push(&d.vec, "*", 1) == false) + if (VEC_PUSH_STR(&d.vec, "*") == false) goto clean; d.ptr = false; } if (d.ref == true) { - if (vector_str_push(&d.vec, "&", 1) == false) + if (VEC_PUSH_STR(&d.vec, "&") == false) goto clean; d.ref = false; } if (d.cnst == true) { - if (vector_str_push(&d.vec, " const", 6) == false) + if (VEC_PUSH_STR(&d.vec, " const") == false) goto clean; d.cnst = false; } if (d.array == true) { if (vector_str_push(&d.vec, d.array_str.buf, d.array_str.size) == false) goto clean; dest_cstring(&d.array_str); d.array = false; } if (*d.p == '\0') break; if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1, &arg_len)) == NULL) goto clean; if (vector_str_push(&d.arg, arg, arg_len) == false) goto clean; free(arg); - if (vector_str_push(&d.vec, ", ", 2) == false) + if (VEC_PUSH_STR(&d.vec, ", ") == false) goto clean; if (++try > CPP_DEMANGLE_GNU2_TRY) goto clean; } /* end argument types */ - if (vector_str_push(&d.vec, ")", 1) == false) + if (VEC_PUSH_STR(&d.vec, ")") == false) goto clean; flat: - if (d.cnst_fn == true && vector_str_push(&d.vec, " const", 6) == false) + if (d.cnst_fn == true && VEC_PUSH_STR(&d.vec, " const") == false) goto clean; rtn = vector_str_get_flat(&d.vec, NULL); clean: dest_demangle_data(&d); return (rtn); } /** * @brief Test input string is encoded by the GNU 2 style. * * @return True if input string is encoded by the GNU 2 style. */ bool is_cpp_mangled_gnu2(const char *org) { char *str; bool rtn = false; if (org == NULL) return (false); /* search valid text to end */ str = strstr(org, "__"); while (str != NULL) { if (*(str + 2) != '\0') { if (*(str + 2) == 'C' || *(str + 2) == 'F' || *(str + 2) == 'Q' || ELFTC_ISDIGIT(*(str + 2))) { rtn |= true; break; } if (*(str + 3) != '\0') { switch (SIMPLE_HASH(*(str + 2), *(str + 3))) { case SIMPLE_HASH('m', 'l') : case SIMPLE_HASH('d', 'v') : case SIMPLE_HASH('m', 'd') : case SIMPLE_HASH('p', 'l') : case SIMPLE_HASH('m', 'i') : case SIMPLE_HASH('l', 's') : case SIMPLE_HASH('r', 's') : case SIMPLE_HASH('e', 'q') : case SIMPLE_HASH('n', 'e') : case SIMPLE_HASH('l', 't') : case SIMPLE_HASH('g', 't') : case SIMPLE_HASH('l', 'e') : case SIMPLE_HASH('g', 'e') : case SIMPLE_HASH('a', 'd') : case SIMPLE_HASH('o', 'r') : case SIMPLE_HASH('e', 'r') : case SIMPLE_HASH('a', 'a') : case SIMPLE_HASH('o', 'o') : case SIMPLE_HASH('n', 't') : case SIMPLE_HASH('c', 'o') : case SIMPLE_HASH('p', 'p') : case SIMPLE_HASH('m', 'm') : case SIMPLE_HASH('a', 's') : case SIMPLE_HASH('r', 'f') : case SIMPLE_HASH('a', 'p') : case SIMPLE_HASH('a', 'm') : case SIMPLE_HASH('a', 'l') : case SIMPLE_HASH('a', 'r') : case SIMPLE_HASH('a', 'o') : case SIMPLE_HASH('a', 'e') : case SIMPLE_HASH('c', 'm') : case SIMPLE_HASH('r', 'm') : case SIMPLE_HASH('c', 'l') : case SIMPLE_HASH('v', 'c') : case SIMPLE_HASH('n', 'w') : case SIMPLE_HASH('d', 'l') : case SIMPLE_HASH('o', 'p') : case SIMPLE_HASH('t', 'f') : case SIMPLE_HASH('t', 'i') : rtn |= true; break; } } } str = strstr(str + 2, "__"); } rtn |= strstr(org, "_$_") != NULL; rtn |= strstr(org, "_vt$") != NULL; return (rtn); } static void dest_cstring(struct cstring *s) { if (s == NULL) return; free(s->buf); s->buf = NULL; s->size = 0; } static void dest_demangle_data(struct demangle_data *d) { if (d != NULL) { vector_str_dest(&d->arg); vector_str_dest(&d->vec); dest_cstring(&d->array_str); } } static bool init_cstring(struct cstring *s, size_t len) { if (s == NULL || len <= 1) return (false); if ((s->buf = malloc(sizeof(char) * len)) == NULL) return (false); s->size = len - 1; return (true); } static bool init_demangle_data(struct demangle_data *d) { if (d == NULL) return (false); d->ptr = false; d->ref = false; d->cnst = false; d->array = false; d->cnst_fn = false; d->class_name = false; d->array_str.buf = NULL; d->array_str.size = 0; d->type = ENCODE_FUNC; if (vector_str_init(&d->vec) == false) return (false); if (vector_str_init(&d->arg) == false) { vector_str_dest(&d->vec); return (false); } return (true); } static bool push_CTDT(const char *s, size_t l, struct vector_str *v) { if (s == NULL || l == 0 || v == NULL) return (false); if (vector_str_push(v, s, l) == false) return (false); assert(v->size > 1); - return (vector_str_push(v, v->container[v->size - 2], - strlen(v->container[v->size - 2]))); + return (VEC_PUSH_STR(v, v->container[v->size - 2])); } static bool read_array(struct demangle_data *d) { size_t len; const char *end; if (d == NULL || d->p == NULL) return (false); end = d->p; assert(end != NULL); for (;;) { if (*end == '\0') return (false); if (ELFTC_ISDIGIT(*end) == 0) break; ++end; } if (*end != '_') return (false); len = end - d->p; assert(len > 0); dest_cstring(&d->array_str); if (init_cstring(&d->array_str, len + 3) == false) return (false); strncpy(d->array_str.buf + 1, d->p, len); *d->array_str.buf = '['; *(d->array_str.buf + len + 1) = ']'; d->array = true; d->p = end + 1; return (true); } static bool read_class(struct demangle_data *d) { size_t len; char *str; if (d == NULL) return (false); len = strtol(d->p, &str, 10); if (len == 0 && (errno == EINVAL || errno == ERANGE)) return (false); assert(len > 0); assert(str != NULL); if (vector_str_push(&d->vec, str, len) == false) return (false); d->p = str + len; d->class_name = true; return (true); } static bool read_func(struct demangle_data *d) { size_t len; const char *name; char *delim; if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); if ((delim = strstr(d->p, "__")) == NULL) return (false); len = delim - d->p; assert(len != 0); name = d->p; d->p = delim + 2; if (*d->p == 'C') { ++d->p; d->cnst_fn = true; } if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; if (read_qual_name(d) == false) return (false); } else if (ELFTC_ISDIGIT(*d->p)) { if (read_class(d) == false) return (false); - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) return (false); } return (vector_str_push(&d->vec, name, len)); } static bool read_func_name(struct demangle_data *d) { size_t len; bool rtn; char *op_name; if (d == NULL) return (false); rtn = false; op_name = NULL; assert(d->p != NULL && "d->p (org str) is NULL"); if (*d->p == '_' && *(d->p + 1) == '_') { d->p += 2; /* CTOR */ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; d->type = ENCODE_OP_CT; if (read_qual_name(d) == false) return (false); return (vector_str_pop(&d->vec)); } else if (ELFTC_ISDIGIT(*d->p)) { d->type = ENCODE_OP_CT; return (read_class(d)); } d->type = ENCODE_OP; if (read_op(d) == false) { /* not good condition, start function name with '__' */ d->type = ENCODE_FUNC; - if (vector_str_push(&d->vec, "__", 2) == false) + if (VEC_PUSH_STR(&d->vec, "__") == false) return (false); return (read_func(d)); } if (d->type == ENCODE_OP_USER || d->type == ENCODE_OP_TF || d->type == ENCODE_OP_TI) return (true); /* skip "__" */ d->p += 2; if (*d->p == 'C') { ++d->p; d->cnst_fn = true; } /* assume delimiter is removed */ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; assert(d->vec.size > 0); len = strlen(d->vec.container[d->vec.size - 1]); if ((op_name = malloc(sizeof(char) * (len + 1))) == NULL) return (false); snprintf(op_name, len + 1, "%s", d->vec.container[d->vec.size - 1]); vector_str_pop(&d->vec); if (read_qual_name(d) == false) goto clean; - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) goto clean; if (vector_str_push(&d->vec, op_name, len) == false) goto clean; rtn = true; } else if (ELFTC_ISDIGIT(*d->p)) { assert(d->vec.size > 0); len = strlen(d->vec.container[d->vec.size - 1]); if ((op_name = malloc(sizeof(char) * (len + 1))) == NULL) return (false); snprintf(op_name, len + 1, "%s", d->vec.container[d->vec.size - 1]); vector_str_pop(&d->vec); if (read_class(d) == false) goto clean; - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) goto clean; if (vector_str_push(&d->vec, op_name, len) == false) goto clean; rtn = true; } } else if (memcmp(d->p, "_$_", 3) == 0) { /* DTOR */ d->p += 3; d->type = ENCODE_OP_DT; if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; if (read_qual_name(d) == false) return (false); return (vector_str_pop(&d->vec)); } else if (ELFTC_ISDIGIT(*d->p)) return (read_class(d)); return (false); } else if (memcmp(d->p, "_vt$", 4) == 0) { /* vtable */ d->p += 4; d->type = ENCODE_OP_VT; if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { ++d->p; if (read_qual_name(d) == false) return (false); if (vector_str_pop(&d->vec) == false) return (false); } else if (ELFTC_ISDIGIT(*d->p)) { if (read_class(d) == false) return (false); } - return (vector_str_push(&d->vec, " virtual table", 14)); + return (VEC_PUSH_STR(&d->vec, " virtual table")); } else return (read_func(d)); clean: free(op_name); return (rtn); } /* Read function ptr type */ static bool read_func_ptr(struct demangle_data *d) { struct demangle_data fptr; size_t arg_len, rtn_len; char *arg_type, *rtn_type; int lim; if (d == NULL) return (false); if (init_demangle_data(&fptr) == false) return (false); fptr.p = d->p + 1; lim = 0; arg_type = NULL; rtn_type = NULL; for (;;) { if (read_type(&fptr) == false) { dest_demangle_data(&fptr); return (false); } if (fptr.ptr == true) { - if (vector_str_push(&fptr.vec, "*", 1) == false) { + if (VEC_PUSH_STR(&fptr.vec, "*") == false) { dest_demangle_data(&fptr); return (false); } fptr.ptr = false; } if (fptr.ref == true) { - if (vector_str_push(&fptr.vec, "&", 1) == false) { + if (VEC_PUSH_STR(&fptr.vec, "&") == false) { dest_demangle_data(&fptr); return (false); } fptr.ref = false; } if (fptr.cnst == true) { - if (vector_str_push(&fptr.vec, " const", 6) == false) { + if (VEC_PUSH_STR(&fptr.vec, " const") == false) { dest_demangle_data(&fptr); return (false); } fptr.cnst = false; } if (*fptr.p == '_') break; - if (vector_str_push(&fptr.vec, ", ", 2) == false) { + if (VEC_PUSH_STR(&fptr.vec, ", ") == false) { dest_demangle_data(&fptr); return (false); } if (++lim > CPP_DEMANGLE_GNU2_TRY) { dest_demangle_data(&fptr); return (false); } } arg_type = vector_str_get_flat(&fptr.vec, &arg_len); /* skip '_' */ d->p = fptr.p + 1; dest_demangle_data(&fptr); if (init_demangle_data(&fptr) == false) { free(arg_type); return (false); } fptr.p = d->p; lim = 0; if (read_type(&fptr) == false) { free(arg_type); dest_demangle_data(&fptr); return (false); } rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len); d->p = fptr.p; dest_demangle_data(&fptr); if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) { free(rtn_type); free(arg_type); return (false); } free(rtn_type); - if (vector_str_push(&d->vec, " (*)(", 5) == false) { + if (VEC_PUSH_STR(&d->vec, " (*)(") == false) { free(arg_type); return (false); } if (vector_str_push(&d->vec, arg_type, arg_len) == false) { free(arg_type); return (false); } free(arg_type); - return (vector_str_push(&d->vec, ")", 1)); + return (VEC_PUSH_STR(&d->vec, ")")); } static bool read_memptr(struct demangle_data *d) { struct demangle_data mptr; size_t len; bool rtn; char *mptr_str; if (d == NULL || d->p == NULL) return (false); if (init_demangle_data(&mptr) == false) return (false); rtn = false; mptr_str = NULL; mptr.p = d->p; if (*mptr.p == 'Q') { ++mptr.p; if (read_qual_name(&mptr) == false) goto clean; } else if (read_class(&mptr) == false) goto clean; d->p = mptr.p; if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL) goto clean; if (vector_str_push(&d->vec, mptr_str, len) == false) goto clean; - if (vector_str_push(&d->vec, "::*", 3) == false) + if (VEC_PUSH_STR(&d->vec, "::*") == false) goto clean; rtn = true; clean: free(mptr_str); dest_demangle_data(&mptr); return (rtn); } static bool read_op(struct demangle_data *d) { if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); switch (SIMPLE_HASH(*(d->p), *(d->p+1))) { case SIMPLE_HASH('m', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "operator*", 9)); + return (VEC_PUSH_STR(&d->vec, "operator*")); case SIMPLE_HASH('d', 'v') : d->p += 2; - return (vector_str_push(&d->vec, "operator/", 9)); + return (VEC_PUSH_STR(&d->vec, "operator/")); case SIMPLE_HASH('m', 'd') : d->p += 2; - return (vector_str_push(&d->vec, "operator%", 9)); + return (VEC_PUSH_STR(&d->vec, "operator%")); case SIMPLE_HASH('p', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "operator+", 9)); + return (VEC_PUSH_STR(&d->vec, "operator+")); case SIMPLE_HASH('m', 'i') : d->p += 2; - return (vector_str_push(&d->vec, "operator-", 9)); + return (VEC_PUSH_STR(&d->vec, "operator-")); case SIMPLE_HASH('l', 's') : d->p += 2; - return (vector_str_push(&d->vec, "operator<<", 10)); + return (VEC_PUSH_STR(&d->vec, "operator<<")); case SIMPLE_HASH('r', 's') : d->p += 2; - return (vector_str_push(&d->vec, "operator>>", 10)); + return (VEC_PUSH_STR(&d->vec, "operator>>")); case SIMPLE_HASH('e', 'q') : d->p += 2; - return (vector_str_push(&d->vec, "operator==", 10)); + return (VEC_PUSH_STR(&d->vec, "operator==")); case SIMPLE_HASH('n', 'e') : d->p += 2; - return (vector_str_push(&d->vec, "operator!=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator!=")); case SIMPLE_HASH('l', 't') : d->p += 2; - return (vector_str_push(&d->vec, "operator<", 9)); + return (VEC_PUSH_STR(&d->vec, "operator<")); case SIMPLE_HASH('g', 't') : d->p += 2; - return (vector_str_push(&d->vec, "operator>", 9)); + return (VEC_PUSH_STR(&d->vec, "operator>")); case SIMPLE_HASH('l', 'e') : d->p += 2; - return (vector_str_push(&d->vec, "operator<=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator<=")); case SIMPLE_HASH('g', 'e') : d->p += 2; - return (vector_str_push(&d->vec, "operator>=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator>=")); case SIMPLE_HASH('a', 'd') : d->p += 2; if (*d->p == 'v') { ++d->p; - return (vector_str_push(&d->vec, "operator/=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator/=")); } else - return (vector_str_push(&d->vec, "operator&", 9)); + return (VEC_PUSH_STR(&d->vec, "operator&")); case SIMPLE_HASH('o', 'r') : d->p += 2; - return (vector_str_push(&d->vec, "operator|", 9)); + return (VEC_PUSH_STR(&d->vec, "operator|")); case SIMPLE_HASH('e', 'r') : d->p += 2; - return (vector_str_push(&d->vec, "operator^", 9)); + return (VEC_PUSH_STR(&d->vec, "operator^")); case SIMPLE_HASH('a', 'a') : d->p += 2; if (*d->p == 'd') { ++d->p; - return (vector_str_push(&d->vec, "operator&=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator&=")); } else - return (vector_str_push(&d->vec, "operator&&", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator&&")); case SIMPLE_HASH('o', 'o') : d->p += 2; - return (vector_str_push(&d->vec, "operator||", 10)); + return (VEC_PUSH_STR(&d->vec, "operator||")); case SIMPLE_HASH('n', 't') : d->p += 2; - return (vector_str_push(&d->vec, "operator!", 9)); + return (VEC_PUSH_STR(&d->vec, "operator!")); case SIMPLE_HASH('c', 'o') : d->p += 2; - return (vector_str_push(&d->vec, "operator~", 9)); + return (VEC_PUSH_STR(&d->vec, "operator~")); case SIMPLE_HASH('p', 'p') : d->p += 2; - return (vector_str_push(&d->vec, "operator++", 10)); + return (VEC_PUSH_STR(&d->vec, "operator++")); case SIMPLE_HASH('m', 'm') : d->p += 2; - return (vector_str_push(&d->vec, "operator--", 10)); + return (VEC_PUSH_STR(&d->vec, "operator--")); case SIMPLE_HASH('a', 's') : d->p += 2; - return (vector_str_push(&d->vec, "operator=", 9)); + return (VEC_PUSH_STR(&d->vec, "operator=")); case SIMPLE_HASH('r', 'f') : d->p += 2; - return (vector_str_push(&d->vec, "operator->", 10)); + return (VEC_PUSH_STR(&d->vec, "operator->")); case SIMPLE_HASH('a', 'p') : /* apl */ if (*(d->p + 2) != 'l') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator+=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator+=")); case SIMPLE_HASH('a', 'm') : d->p += 2; if (*d->p == 'i') { ++d->p; - return (vector_str_push(&d->vec, "operator-=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator-=")); } else if (*d->p == 'u') { ++d->p; - return (vector_str_push(&d->vec, "operator*=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator*=")); } else if (*d->p == 'd') { ++d->p; - return (vector_str_push(&d->vec, "operator%=", - 10)); + return (VEC_PUSH_STR(&d->vec, "operator%=")); } return (false); case SIMPLE_HASH('a', 'l') : /* als */ if (*(d->p + 2) != 's') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator<<=", 11)); + return (VEC_PUSH_STR(&d->vec, "operator<<=")); case SIMPLE_HASH('a', 'r') : /* ars */ if (*(d->p + 2) != 's') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator>>=", 11)); + return (VEC_PUSH_STR(&d->vec, "operator>>=")); case SIMPLE_HASH('a', 'o') : /* aor */ if (*(d->p + 2) != 'r') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator|=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator|=")); case SIMPLE_HASH('a', 'e') : /* aer */ if (*(d->p + 2) != 'r') return (false); d->p += 3; - return (vector_str_push(&d->vec, "operator^=", 10)); + return (VEC_PUSH_STR(&d->vec, "operator^=")); case SIMPLE_HASH('c', 'm') : d->p += 2; - return (vector_str_push(&d->vec, "operator,", 9)); + return (VEC_PUSH_STR(&d->vec, "operator,")); case SIMPLE_HASH('r', 'm') : d->p += 2; - return (vector_str_push(&d->vec, "operator->*", 11)); + return (VEC_PUSH_STR(&d->vec, "operator->*")); case SIMPLE_HASH('c', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "()", 2)); + return (VEC_PUSH_STR(&d->vec, "()")); case SIMPLE_HASH('v', 'c') : d->p += 2; - return (vector_str_push(&d->vec, "[]", 2)); + return (VEC_PUSH_STR(&d->vec, "[]")); case SIMPLE_HASH('n', 'w') : d->p += 2; - return (vector_str_push(&d->vec, "operator new()", 14)); + return (VEC_PUSH_STR(&d->vec, "operator new()")); case SIMPLE_HASH('d', 'l') : d->p += 2; - return (vector_str_push(&d->vec, "operator delete()", - 17)); + return (VEC_PUSH_STR(&d->vec, "operator delete()")); case SIMPLE_HASH('o', 'p') : /* __op__ */ d->p += 2; d->type = ENCODE_OP_USER; return (read_op_user(d)); case SIMPLE_HASH('t', 'f') : d->p += 2; d->type = ENCODE_OP_TF; if (read_type(d) == false) return (false); - return (vector_str_push(&d->vec, " type_info function", 19)); + return (VEC_PUSH_STR(&d->vec, " type_info function")); case SIMPLE_HASH('t', 'i') : d->p += 2; d->type = ENCODE_OP_TI; if (read_type(d) == false) return (false); - return (vector_str_push(&d->vec, " type_info node", 15)); + return (VEC_PUSH_STR(&d->vec, " type_info node")); default : return (false); }; } static bool read_op_user(struct demangle_data *d) { struct demangle_data from, to; size_t from_len, to_len; bool rtn; char *from_str, *to_str; if (d == NULL) return (false); if (init_demangle_data(&from) == false) return (false); rtn = false; from_str = NULL; to_str = NULL; if (init_demangle_data(&to) == false) goto clean; to.p = d->p; if (*to.p == 'Q') { ++to.p; if (read_qual_name(&to) == false) goto clean; /* pop last '::' */ if (vector_str_pop(&to.vec) == false) goto clean; } else { if (read_class(&to) == false) goto clean; /* skip '__' */ to.p += 2; } if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL) goto clean; from.p = to.p; if (*from.p == 'Q') { ++from.p; if (read_qual_name(&from) == false) goto clean; /* pop last '::' */ if (vector_str_pop(&from.vec) == false) goto clean; } else if (read_class(&from) == false) goto clean; if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL) goto clean; if (vector_str_push(&d->vec, from_str, from_len) == false) goto clean; - if (vector_str_push(&d->vec, "::operator ", 11) == false) + if (VEC_PUSH_STR(&d->vec, "::operator ") == false) goto clean; if (vector_str_push(&d->vec, to_str, to_len) == false) goto clean; - rtn = vector_str_push(&d->vec, "()", 2); + rtn = VEC_PUSH_STR(&d->vec, "()"); clean: free(to_str); free(from_str); dest_demangle_data(&to); dest_demangle_data(&from); return (rtn); } /* single digit + class names */ static bool read_qual_name(struct demangle_data *d) { int i; char num; if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); num = *d->p - 48; assert(num > 0); ++d->p; for (i = 0; i < num ; ++i) { if (read_class(d) == false) return (false); - if (vector_str_push(&d->vec, "::", 2) == false) + if (VEC_PUSH_STR(&d->vec, "::") == false) return (false); } if (*d->p != '\0') d->p = d->p + 2; return (true); } /* Return -1 at fail, 0 at success, and 1 at end */ static int read_subst(struct demangle_data *d) { size_t idx; char *str; if (d == NULL) return (-1); idx = strtol(d->p + 1, &str, 10); if (idx == 0 && (errno == EINVAL || errno == ERANGE)) return (-1); assert(idx > 0); assert(str != NULL); d->p = str; - if (vector_str_push(&d->vec, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) return (-1); - if (vector_str_push(&d->arg, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) return (-1); if (*d->p == '\0') return (1); return (0); } static int read_subst_iter(struct demangle_data *d) { int i; size_t idx; char repeat; char *str; if (d == NULL) return (-1); ++d->p; assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); repeat = *d->p - 48; assert(repeat > 1); ++d->p; idx = strtol(d->p, &str, 10); if (idx == 0 && (errno == EINVAL || errno == ERANGE)) return (-1); assert(idx > 0); assert(str != NULL); d->p = str; for (i = 0; i < repeat ; ++i) { - if (vector_str_push(&d->vec, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) return (-1); - if (vector_str_push(&d->arg, d->arg.container[idx - 1], - strlen(d->arg.container[idx - 1])) == false) + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) return (-1); if (i != repeat - 1 && - vector_str_push(&d->vec, ", ", 2) == false) + VEC_PUSH_STR(&d->vec, ", ") == false) return (-1); } if (*d->p == '\0') return (1); return (0); } static bool read_type(struct demangle_data *d) { if (d == NULL) return (false); assert(d->p != NULL && "d->p (org str) is NULL"); while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' || *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' || *d->p == 'M') { switch (*d->p) { case 'U' : ++d->p; - if (vector_str_push(&d->vec, "unsigned ", 9) == false) + if (VEC_PUSH_STR(&d->vec, "unsigned ") == false) return (false); break; case 'C' : ++d->p; if (*d->p == 'P') d->cnst = true; else { - if (vector_str_push(&d->vec, "const ", 6) == + if (VEC_PUSH_STR(&d->vec, "const ") == false) return (false); } break; case 'V' : ++d->p; - if (vector_str_push(&d->vec, "volatile ", 9) == false) + if (VEC_PUSH_STR(&d->vec, "volatile ") == false) return (false); break; case 'S' : ++d->p; - if (vector_str_push(&d->vec, "signed ", 7) == false) + if (VEC_PUSH_STR(&d->vec, "signed ") == false) return (false); break; case 'P' : ++d->p; if (*d->p == 'F') return (read_func_ptr(d)); else d->ptr = true; break; case 'R' : ++d->p; d->ref = true; break; case 'F' : break; case 'A' : ++d->p; if (read_array(d) == false) return (false); break; case 'M' : ++d->p; if (read_memptr(d) == false) return (false); break; default : break; } } if (ELFTC_ISDIGIT(*d->p)) return (read_class(d)); switch (*d->p) { case 'Q' : ++d->p; return (read_qual_name(d)); case 'v' : ++d->p; - return (vector_str_push(&d->vec, "void", 4)); + return (VEC_PUSH_STR(&d->vec, "void")); case 'b': ++d->p; - return(vector_str_push(&d->vec, "bool", 4)); + return(VEC_PUSH_STR(&d->vec, "bool")); case 'c' : ++d->p; - return (vector_str_push(&d->vec, "char", 4)); + return (VEC_PUSH_STR(&d->vec, "char")); case 's' : ++d->p; - return (vector_str_push(&d->vec, "short", 5)); + return (VEC_PUSH_STR(&d->vec, "short")); case 'i' : ++d->p; - return (vector_str_push(&d->vec, "int", 3)); + return (VEC_PUSH_STR(&d->vec, "int")); case 'l' : ++d->p; - return (vector_str_push(&d->vec, "long", 4)); + return (VEC_PUSH_STR(&d->vec, "long")); case 'f' : ++d->p; - return (vector_str_push(&d->vec, "float", 5)); + return (VEC_PUSH_STR(&d->vec, "float")); case 'd': ++d->p; - return (vector_str_push(&d->vec, "double", 6)); + return (VEC_PUSH_STR(&d->vec, "double")); case 'r': ++d->p; - return (vector_str_push(&d->vec, "long double", 11)); + return (VEC_PUSH_STR(&d->vec, "long double")); case 'e': ++d->p; - return (vector_str_push(&d->vec, "...", 3)); + return (VEC_PUSH_STR(&d->vec, "...")); case 'w': ++d->p; - return (vector_str_push(&d->vec, "wchar_t", 7)); + return (VEC_PUSH_STR(&d->vec, "wchar_t")); case 'x': ++d->p; - return (vector_str_push(&d->vec, "long long", 9)); + return (VEC_PUSH_STR(&d->vec, "long long")); default: return (false); }; /* NOTREACHED */ return (false); } Index: vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu3.c =================================================================== --- vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu3.c (revision 317072) +++ vendor/elftoolchain/dist/libelftc/libelftc_dem_gnu3.c (revision 317073) @@ -1,3618 +1,3608 @@ /*- * 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 3480 2016-07-24 23:38:41Z emaste $"); +ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3512 2016-12-29 07:04:19Z kaiwang27 $"); /** * @file cpp_demangle.c * @brief Decode IA-64 C++ ABI style implementation. * * IA-64 standard ABI(Itanium C++ ABI) references. * * http://www.codesourcery.com/cxx-abi/abi.html#mangling \n * http://www.codesourcery.com/cxx-abi/abi-mangling.html */ enum type_qualifier { TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT, TYPE_CST, TYPE_VEC }; 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 */ int push_head; }; #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) +#define DEM_PUSH_STR(d,s) cpp_demangle_push_str((d), (s), strlen((s))) +#define VEC_PUSH_STR(d,s) vector_str_push((d), (s), strlen((s))) 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_flat(struct cpp_demangle_data *, char **); 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_name_flat(struct cpp_demangle_data *, char**); 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_number_as_string(struct cpp_demangle_data *, char **); 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_type_flat(struct cpp_demangle_data *, char **); 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); /** * @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); 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)) + if (ddata.paren && !VEC_PUSH_STR(&ddata.output, ")")) goto clean; - if (ddata.mem_vat && !vector_str_push(&ddata.output, " volatile", 9)) + if (ddata.mem_vat && !VEC_PUSH_STR(&ddata.output, " volatile")) goto clean; - if (ddata.mem_cst && !vector_str_push(&ddata.output, " const", 6)) + if (ddata.mem_cst && !VEC_PUSH_STR(&ddata.output, " const")) goto clean; - if (ddata.mem_rst && !vector_str_push(&ddata.output, " restrict", 9)) + if (ddata.mem_rst && !VEC_PUSH_STR(&ddata.output, " restrict")) 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; d->push_head = 0; 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; if ((f = decoder(fp, ddata->cur - fp)) == NULL) return (0); rtn = 0; if ((len = strlen(f)) > 0) rtn = cpp_demangle_push_str(ddata, f, len); free(f); ++ddata->cur; 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 (ddata->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))) + if (!VEC_PUSH_STR(&subst_v, 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)) + if (!DEM_PUSH_STR(ddata, "*")) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, "*", 1)) + if (!VEC_PUSH_STR(&subst_v, "*")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_REF: - if (!cpp_demangle_push_str(ddata, "&", 1)) + if (!DEM_PUSH_STR(ddata, "&")) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, "&", 1)) + if (!VEC_PUSH_STR(&subst_v, "&")) 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)) + if (!DEM_PUSH_STR(ddata, " complex")) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, " complex", 8)) + if (!VEC_PUSH_STR(&subst_v, " complex")) 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)) + if (!DEM_PUSH_STR(ddata, " imaginary")) 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 (v->ext_name.size == 0 || 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(e_len + 2)) == NULL) goto clean; snprintf(buf, e_len + 2, " %s", v->ext_name.container[e_idx]); - if (!cpp_demangle_push_str(ddata, buf, e_len + 1)) { + if (!DEM_PUSH_STR(ddata, buf)) { free(buf); goto clean; } if (type_str != NULL) { - if (!vector_str_push(&subst_v, buf, - e_len + 1)) { + if (!VEC_PUSH_STR(&subst_v, buf)) { 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)) + if (!DEM_PUSH_STR(ddata, " restrict")) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, " restrict", 9)) + if (!VEC_PUSH_STR(&subst_v, " restrict")) 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)) + if (!DEM_PUSH_STR(ddata, " volatile")) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, " volatile", 9)) + if (!VEC_PUSH_STR(&subst_v, " volatile")) 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)) + if (!DEM_PUSH_STR(ddata, " const")) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, " const", 6)) + if (!VEC_PUSH_STR(&subst_v, " const")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_VEC: if (v->ext_name.size == 0 || 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(e_len + 12)) == NULL) goto clean; snprintf(buf, e_len + 12, " __vector(%s)", v->ext_name.container[e_idx]); - if (!cpp_demangle_push_str(ddata, buf, e_len + 11)) { + if (!DEM_PUSH_STR(ddata, buf)) { free(buf); goto clean; } if (type_str != NULL) { - if (!vector_str_push(&subst_v, buf, - e_len + 11)) { + if (!VEC_PUSH_STR(&subst_v, buf)) { free(buf); goto clean; } if (!cpp_demangle_push_subst_v(ddata, &subst_v)) { free(buf); goto clean; } } free(buf); ++e_idx; 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)) + if (!DEM_PUSH_STR(ddata, "[]")) 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)) + if (!DEM_PUSH_STR(ddata, "[")) return (0); if (!cpp_demangle_push_str(ddata, num, num_len)) return (0); - if (!cpp_demangle_push_str(ddata, "]", 1)) + if (!DEM_PUSH_STR(ddata, "]")) 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)) { + if (!DEM_PUSH_STR(ddata, "[")) { free(exp); return (0); } if (!cpp_demangle_push_str(ddata, exp, exp_len)) { free(exp); return (0); } - if (!cpp_demangle_push_str(ddata, "]", 1)) { + if (!DEM_PUSH_STR(ddata, "]")) { 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': if (*(ddata->cur + 2) != 'E') return (0); switch (*(++ddata->cur)) { case '0': ddata->cur += 2; - return (cpp_demangle_push_str(ddata, "false", 5)); + return (DEM_PUSH_STR(ddata, "false")); case '1': ddata->cur += 2; - return (cpp_demangle_push_str(ddata, "true", 4)); + return (DEM_PUSH_STR(ddata, "true")); 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)) + if (!DEM_PUSH_STR(ddata, "-")) 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 - 1)); 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_flat(struct cpp_demangle_data *ddata, char **str) { struct vector_str *output; size_t i, p_idx, idx, exp_len; char *exp; output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; if (!cpp_demangle_read_expression(ddata)) return (0); if ((exp = vector_str_substr(output, p_idx, output->size - 1, &exp_len)) == NULL) return (0); idx = output->size; for (i = p_idx; i < idx; ++i) { if (!vector_str_pop(output)) { free(exp); return (0); } } *str = exp; return (1); } 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)) + if (!DEM_PUSH_STR(ddata, "(")) 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)) + if (!DEM_PUSH_STR(ddata, "::*")) 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)) + if (!DEM_PUSH_STR(ddata, ")(")) 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)) + if (!DEM_PUSH_STR(ddata, ")")) 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) { char *name, *type, *num_str; long offset; int rtn; if (ddata == NULL || *ddata->cur == '\0') return (0); /* special name */ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { case SIMPLE_HASH('G', 'A'): - if (!cpp_demangle_push_str(ddata, "hidden alias for ", 17)) + if (!DEM_PUSH_STR(ddata, "hidden alias for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_encoding(ddata)); case SIMPLE_HASH('G', 'R'): - if (!cpp_demangle_push_str(ddata, "reference temporary #", 21)) + if (!DEM_PUSH_STR(ddata, "reference temporary #")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); if (!cpp_demangle_read_name_flat(ddata, &name)) return (0); rtn = 0; if (!cpp_demangle_read_number_as_string(ddata, &num_str)) goto clean1; - if (!cpp_demangle_push_str(ddata, num_str, strlen(num_str))) + if (!DEM_PUSH_STR(ddata, num_str)) goto clean2; - if (!cpp_demangle_push_str(ddata, " for ", 5)) + if (!DEM_PUSH_STR(ddata, " for ")) goto clean2; - if (!cpp_demangle_push_str(ddata, name, strlen(name))) + if (!DEM_PUSH_STR(ddata, name)) goto clean2; rtn = 1; clean2: free(num_str); clean1: free(name); return (rtn); case SIMPLE_HASH('G', 'T'): ddata->cur += 2; if (*ddata->cur == '\0') return (0); switch (*ddata->cur) { case 'n': - if (!cpp_demangle_push_str(ddata, - "non-transaction clone for ", 26)) + if (!DEM_PUSH_STR(ddata, "non-transaction clone for ")) return (0); break; case 't': default: - if (!cpp_demangle_push_str(ddata, - "transaction clone for ", 22)) + if (!DEM_PUSH_STR(ddata, "transaction clone for ")) return (0); break; } ++ddata->cur; return (cpp_demangle_read_encoding(ddata)); case SIMPLE_HASH('G', 'V'): /* sentry object for 1 time init */ - if (!cpp_demangle_push_str(ddata, "guard variable for ", 20)) + if (!DEM_PUSH_STR(ddata, "guard variable for ")) 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)) + if (!DEM_PUSH_STR(ddata, + "virtual function covariant override ")) 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', 'C'): /* construction vtable */ - if (!cpp_demangle_push_str(ddata, "construction vtable for ", - 24)) + if (!DEM_PUSH_STR(ddata, "construction vtable for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); if (!cpp_demangle_read_type_flat(ddata, &type)) return (0); rtn = 0; if (!cpp_demangle_read_number(ddata, &offset)) goto clean3; if (*ddata->cur++ != '_') goto clean3; if (!cpp_demangle_read_type(ddata, 0)) goto clean3; - if (!cpp_demangle_push_str(ddata, "-in-", 4)) + if (!DEM_PUSH_STR(ddata, "-in-")) goto clean3; - if (!cpp_demangle_push_str(ddata, type, strlen(type))) + if (!DEM_PUSH_STR(ddata, type)) goto clean3; rtn = 1; clean3: free(type); return (rtn); case SIMPLE_HASH('T', 'D'): /* typeinfo common proxy */ break; case SIMPLE_HASH('T', 'F'): /* typeinfo fn */ - if (!cpp_demangle_push_str(ddata, "typeinfo fn for ", 16)) + if (!DEM_PUSH_STR(ddata, "typeinfo fn for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'h'): /* virtual function non-virtual override thunk */ - if (!cpp_demangle_push_str(ddata, - "virtual function non-virtual override ", 38)) + if (!DEM_PUSH_STR(ddata, + "virtual function non-virtual override ")) 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', 'H'): /* TLS init function */ - if (!cpp_demangle_push_str(ddata, "TLS init function for ", - 22)) + if (!DEM_PUSH_STR(ddata, "TLS init function for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); break; case SIMPLE_HASH('T', 'I'): /* typeinfo structure */ - if (!cpp_demangle_push_str(ddata, "typeinfo for ", 13)) + if (!DEM_PUSH_STR(ddata, "typeinfo for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'J'): /* java class */ - if (!cpp_demangle_push_str(ddata, "java Class for ", 15)) + if (!DEM_PUSH_STR(ddata, "java Class for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'S'): /* RTTI name (NTBS) */ - if (!cpp_demangle_push_str(ddata, "typeinfo name for ", 18)) + if (!DEM_PUSH_STR(ddata, "typeinfo name for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'T'): /* VTT table */ - if (!cpp_demangle_push_str(ddata, "VTT for ", 8)) + if (!DEM_PUSH_STR(ddata, "VTT for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'v'): /* virtual function virtual override thunk */ - if (!cpp_demangle_push_str(ddata, - "virtual function virtual override ", 34)) + if (!DEM_PUSH_STR(ddata, + "virtual function virtual override ")) 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)) + if (!DEM_PUSH_STR(ddata, "vtable for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'W'): /* TLS wrapper function */ - if (!cpp_demangle_push_str(ddata, "TLS wrapper function for ", - 25)) + if (!DEM_PUSH_STR(ddata, "TLS wrapper function for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); break; } 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)) + if (!DEM_PUSH_STR(ddata, ")")) return (0); ddata->paren = false; } if (*ddata->cur == 's') ++ddata->cur; else { - if (!cpp_demangle_push_str(ddata, "::", 2)) + if (!DEM_PUSH_STR(ddata, "::")) 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 = ddata->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_name_flat(struct cpp_demangle_data *ddata, char **str) { struct vector_str *output; size_t i, p_idx, idx, name_len; char *name; output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; if (!cpp_demangle_read_name(ddata)) return (0); if ((name = vector_str_substr(output, p_idx, output->size - 1, &name_len)) == NULL) return (0); idx = output->size; for (i = p_idx; i < idx; ++i) { if (!vector_str_pop(output)) { free(name); return (0); } } *str = name; return (1); } 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 = ddata->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)) + if (!DEM_PUSH_STR(ddata, "::")) goto clean; - if (!vector_str_push(&v, "::", 2)) + if (!VEC_PUSH_STR(&v, "::")) 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_number_as_string(struct cpp_demangle_data *ddata, char **str) { long n; if (!cpp_demangle_read_number(ddata, &n)) { *str = NULL; return (0); } if (asprintf(str, "%ld", n) < 0) { *str = NULL; return (0); } 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)) + if (!DEM_PUSH_STR(ddata, "offset : ")) 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)) + if (negative && !DEM_PUSH_STR(ddata, "-")) return (0); assert(start != NULL); if (!cpp_demangle_push_str(ddata, start, ddata->cur - start)) return (0); - if (!cpp_demangle_push_str(ddata, " ", 1)) + if (!DEM_PUSH_STR(ddata, " ")) 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)) + if (!DEM_PUSH_STR(ddata, " ")) goto clean3; if (!cpp_demangle_push_str(ddata, class_type, class_type_len)) goto clean3; - if (!cpp_demangle_push_str(ddata, "::*", 3)) + if (!DEM_PUSH_STR(ddata, "::*")) 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; int err; if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 || len <= 0) return (0); if (len == 12 && (memcmp("_GLOBAL__N_1", ddata->cur, 12) == 0)) - err = cpp_demangle_push_str(ddata, "(anonymous namespace)", 21); + err = DEM_PUSH_STR(ddata, "(anonymous namespace)"); else err = cpp_demangle_push_str(ddata, ddata->cur, len); if (err == 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) + if (!DEM_PUSH_STR(ddata, "std::allocator")) 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)) + if (!DEM_PUSH_STR(ddata, "std::basic_string")) 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::basic_iostream", 19)) + if (!DEM_PUSH_STR(ddata, "std::basic_iostream")) return (0); ddata->last_sname = "basic_iostream"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::basic_iostream", 19)); return (1); case SIMPLE_HASH('S', 'i'): /* std::basic_istream > */ - if (!cpp_demangle_push_str(ddata, "std::basic_istream", 18)) + if (!DEM_PUSH_STR(ddata, "std::basic_istream")) return (0); ddata->last_sname = "basic_istream"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::basic_istream", 18)); return (1); case SIMPLE_HASH('S', 'o'): /* std::basic_ostream > */ - if (!cpp_demangle_push_str(ddata, "std::basic_ostream", 18)) + if (!DEM_PUSH_STR(ddata, "std::basic_ostream")) return (0); ddata->last_sname = "basic_ostream"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::basic_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)) + if (!DEM_PUSH_STR(ddata, "std::string")) 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)) + if (!DEM_PUSH_STR(ddata, "std::")) goto clean; - if (!vector_str_push(&v, "std::", 5)) + if (!VEC_PUSH_STR(&v, "std::")) goto clean; ddata->cur += 2; output = ddata->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 = ddata->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)) + if (!DEM_PUSH_STR(ddata, "<")) return (0); limit = 0; v = ddata->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)) + if (!DEM_PUSH_STR(ddata, " >")) return (0); - } else if (!cpp_demangle_push_str(ddata, ">", 1)) + } else if (!DEM_PUSH_STR(ddata, ">")) return (0); break; } else if (*ddata->cur != 'I' && - !cpp_demangle_push_str(ddata, ", ", 2)) + !DEM_PUSH_STR(ddata, ", ")) 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, *exp_str, *num_str; if (ddata == NULL) return (0); output = &ddata->output; if (!strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) { ddata->push_head++; output = &ddata->output_tmp; } else if (delimit == 1) { if (ddata->paren == false) { - if (!cpp_demangle_push_str(ddata, "(", 1)) + if (!DEM_PUSH_STR(ddata, "(")) 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)) + !DEM_PUSH_STR(ddata, ", ")) 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 = exp_str = num_str = NULL; again: /* builtin type */ switch (*ddata->cur) { case 'a': /* signed char */ - if (!cpp_demangle_push_str(ddata, "signed char", 11)) + if (!DEM_PUSH_STR(ddata, "signed char")) 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)) + if (!DEM_PUSH_STR(ddata, "bool")) 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)) + if (!DEM_PUSH_STR(ddata, "char")) goto clean; ++ddata->cur; goto rtn; case 'd': /* double */ - if (!cpp_demangle_push_str(ddata, "double", 6)) + if (!DEM_PUSH_STR(ddata, "double")) goto clean; ++ddata->cur; goto rtn; case 'D': ++ddata->cur; switch (*ddata->cur) { case 'd': /* IEEE 754r decimal floating point (64 bits) */ - if (!cpp_demangle_push_str(ddata, "decimal64", 9)) + if (!DEM_PUSH_STR(ddata, "decimal64")) goto clean; ++ddata->cur; break; case 'e': /* IEEE 754r decimal floating point (128 bits) */ - if (!cpp_demangle_push_str(ddata, "decimal128", 10)) + if (!DEM_PUSH_STR(ddata, "decimal128")) goto clean; ++ddata->cur; break; case 'f': /* IEEE 754r decimal floating point (32 bits) */ - if (!cpp_demangle_push_str(ddata, "decimal32", 9)) + if (!DEM_PUSH_STR(ddata, "decimal32")) goto clean; ++ddata->cur; break; case 'h': /* IEEE 754r half-precision floating point (16 bits) */ - if (!cpp_demangle_push_str(ddata, "half", 4)) + if (!DEM_PUSH_STR(ddata, "half")) goto clean; ++ddata->cur; break; case 'i': /* char32_t */ - if (!cpp_demangle_push_str(ddata, "char32_t", 8)) + if (!DEM_PUSH_STR(ddata, "char32_t")) goto clean; ++ddata->cur; break; case 'n': /* std::nullptr_t (i.e., decltype(nullptr)) */ - if (!cpp_demangle_push_str(ddata, "decltype(nullptr)", - 17)) + if (!DEM_PUSH_STR(ddata, "decltype(nullptr)")) goto clean; ++ddata->cur; break; case 's': /* char16_t */ - if (!cpp_demangle_push_str(ddata, "char16_t", 8)) + if (!DEM_PUSH_STR(ddata, "char16_t")) goto clean; ++ddata->cur; break; case 'v': /* gcc vector_size extension. */ ++ddata->cur; if (*ddata->cur == '_') { ++ddata->cur; if (!cpp_demangle_read_expression_flat(ddata, &exp_str)) goto clean; - if (!vector_str_push(&v.ext_name, exp_str, - strlen(exp_str))) + if (!VEC_PUSH_STR(&v.ext_name, exp_str)) goto clean; } else { if (!cpp_demangle_read_number_as_string(ddata, &num_str)) goto clean; - if (!vector_str_push(&v.ext_name, num_str, - strlen(num_str))) + if (!VEC_PUSH_STR(&v.ext_name, num_str)) goto clean; } if (*ddata->cur != '_') goto clean; ++ddata->cur; if (!vector_type_qualifier_push(&v, TYPE_VEC)) goto clean; goto again; default: goto clean; } goto rtn; case 'e': /* long double */ - if (!cpp_demangle_push_str(ddata, "long double", 11)) + if (!DEM_PUSH_STR(ddata, "long double")) goto clean; ++ddata->cur; goto rtn; case 'f': /* float */ - if (!cpp_demangle_push_str(ddata, "float", 5)) + if (!DEM_PUSH_STR(ddata, "float")) 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)) + if (!DEM_PUSH_STR(ddata, "__float128")) 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)) + if (!DEM_PUSH_STR(ddata, "unsigned char")) goto clean; ++ddata->cur; goto rtn; case 'i': /* int */ - if (!cpp_demangle_push_str(ddata, "int", 3)) + if (!DEM_PUSH_STR(ddata, "int")) goto clean; ++ddata->cur; goto rtn; case 'j': /* unsigned int */ - if (!cpp_demangle_push_str(ddata, "unsigned int", 12)) + if (!DEM_PUSH_STR(ddata, "unsigned int")) 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)) + if (!DEM_PUSH_STR(ddata, "long")) goto clean; ++ddata->cur; goto rtn; case 'm': /* unsigned long */ - if (!cpp_demangle_push_str(ddata, "unsigned long", 13)) + if (!DEM_PUSH_STR(ddata, "unsigned long")) 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)) + if (!DEM_PUSH_STR(ddata, "__int128")) goto clean; ++ddata->cur; goto rtn; case 'o': /* unsigned __int128 */ - if (!cpp_demangle_push_str(ddata, "unsigned __int128", 17)) + if (!DEM_PUSH_STR(ddata, "unsigned __int128")) 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)) + if (!DEM_PUSH_STR(ddata, "short")) 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)) + if (!DEM_PUSH_STR(ddata, "unsigned short")) 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; if (!vector_type_qualifier_push(&v, TYPE_EXT)) goto clean; goto again; case 'v': /* void */ - if (!cpp_demangle_push_str(ddata, "void", 4)) + if (!DEM_PUSH_STR(ddata, "void")) 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", 7)) + if (!DEM_PUSH_STR(ddata, "wchar_t")) goto clean; ++ddata->cur; goto rtn; case 'x': /* long long */ - if (!cpp_demangle_push_str(ddata, "long long", 9)) + if (!DEM_PUSH_STR(ddata, "long long")) goto clean; ++ddata->cur; goto rtn; case 'y': /* unsigned long long */ - if (!cpp_demangle_push_str(ddata, "unsigned long long", 18)) + if (!DEM_PUSH_STR(ddata, "unsigned long long")) goto clean; ++ddata->cur; goto rtn; case 'z': /* ellipsis */ - if (!cpp_demangle_push_str(ddata, "ellipsis", 8)) + if (!DEM_PUSH_STR(ddata, "...")) 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); free(exp_str); free(num_str); vector_type_qualifier_dest(&v); if (ddata->push_head > 0) { if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata) == 0) return (0); if (--ddata->push_head > 0) return (1); - if (!vector_str_push(&ddata->output_tmp, " ", 1)) + if (!VEC_PUSH_STR(&ddata->output_tmp, " ")) 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)) + if (!DEM_PUSH_STR(ddata, "(")) return (0); ddata->paren = true; ddata->pfirst = true; } return (1); clean: free(type_str); free(exp_str); free(num_str); vector_type_qualifier_dest(&v); return (0); } static int cpp_demangle_read_type_flat(struct cpp_demangle_data *ddata, char **str) { struct vector_str *output; size_t i, p_idx, idx, type_len; char *type; output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; if (!cpp_demangle_read_type(ddata, 0)) return (0); if ((type = vector_str_substr(output, p_idx, output->size - 1, &type_len)) == NULL) return (0); idx = output->size; for (i = p_idx; i < idx; ++i) { if (!vector_str_pop(output)) { free(type); return (0); } } *str = type; return (1); } /* * 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)) + if (!DEM_PUSH_STR(ddata, "operator&&")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'd'): /* operator & (unary) */ - if (!cpp_demangle_push_str(ddata, "operator&", 9)) + if (!DEM_PUSH_STR(ddata, "operator&")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'n'): /* operator & */ - if (!cpp_demangle_push_str(ddata, "operator&", 9)) + if (!DEM_PUSH_STR(ddata, "operator&")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'N'): /* operator &= */ - if (!cpp_demangle_push_str(ddata, "operator&=", 10)) + if (!DEM_PUSH_STR(ddata, "operator&=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'S'): /* operator = */ - if (!cpp_demangle_push_str(ddata, "operator=", 9)) + if (!DEM_PUSH_STR(ddata, "operator=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'l'): /* operator () */ - if (!cpp_demangle_push_str(ddata, "operator()", 10)) + if (!DEM_PUSH_STR(ddata, "operator()")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'm'): /* operator , */ - if (!cpp_demangle_push_str(ddata, "operator,", 9)) + if (!DEM_PUSH_STR(ddata, "operator,")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'o'): /* operator ~ */ - if (!cpp_demangle_push_str(ddata, "operator~", 9)) + if (!DEM_PUSH_STR(ddata, "operator~")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'v'): /* operator (cast) */ - if (!cpp_demangle_push_str(ddata, "operator(cast)", 14)) + if (!DEM_PUSH_STR(ddata, "operator(cast)")) 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)) + if (!DEM_PUSH_STR(ddata, "operator delete []")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'e'): /* operator * (unary) */ - if (!cpp_demangle_push_str(ddata, "operator*", 9)) + if (!DEM_PUSH_STR(ddata, "operator*")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'l'): /* operator delete */ - if (!cpp_demangle_push_str(ddata, "operator delete", 15)) + if (!DEM_PUSH_STR(ddata, "operator delete")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'v'): /* operator / */ - if (!cpp_demangle_push_str(ddata, "operator/", 9)) + if (!DEM_PUSH_STR(ddata, "operator/")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'V'): /* operator /= */ - if (!cpp_demangle_push_str(ddata, "operator/=", 10)) + if (!DEM_PUSH_STR(ddata, "operator/=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'o'): /* operator ^ */ - if (!cpp_demangle_push_str(ddata, "operator^", 9)) + if (!DEM_PUSH_STR(ddata, "operator^")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'O'): /* operator ^= */ - if (!cpp_demangle_push_str(ddata, "operator^=", 10)) + if (!DEM_PUSH_STR(ddata, "operator^=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'q'): /* operator == */ - if (!cpp_demangle_push_str(ddata, "operator==", 10)) + if (!DEM_PUSH_STR(ddata, "operator==")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('g', 'e'): /* operator >= */ - if (!cpp_demangle_push_str(ddata, "operator>=", 10)) + if (!DEM_PUSH_STR(ddata, "operator>=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('g', 't'): /* operator > */ - if (!cpp_demangle_push_str(ddata, "operator>", 9)) + if (!DEM_PUSH_STR(ddata, "operator>")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('i', 'x'): /* operator [] */ - if (!cpp_demangle_push_str(ddata, "operator[]", 10)) + if (!DEM_PUSH_STR(ddata, "operator[]")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 'e'): /* operator <= */ - if (!cpp_demangle_push_str(ddata, "operator<=", 10)) + if (!DEM_PUSH_STR(ddata, "operator<=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 's'): /* operator << */ - if (!cpp_demangle_push_str(ddata, "operator<<", 10)) + if (!DEM_PUSH_STR(ddata, "operator<<")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 'S'): /* operator <<= */ - if (!cpp_demangle_push_str(ddata, "operator<<=", 11)) + if (!DEM_PUSH_STR(ddata, "operator<<=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 't'): /* operator < */ - if (!cpp_demangle_push_str(ddata, "operator<", 9)) + if (!DEM_PUSH_STR(ddata, "operator<")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'i'): /* operator - */ - if (!cpp_demangle_push_str(ddata, "operator-", 9)) + if (!DEM_PUSH_STR(ddata, "operator-")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'I'): /* operator -= */ - if (!cpp_demangle_push_str(ddata, "operator-=", 10)) + if (!DEM_PUSH_STR(ddata, "operator-=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'l'): /* operator * */ - if (!cpp_demangle_push_str(ddata, "operator*", 9)) + if (!DEM_PUSH_STR(ddata, "operator*")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'L'): /* operator *= */ - if (!cpp_demangle_push_str(ddata, "operator*=", 10)) + if (!DEM_PUSH_STR(ddata, "operator*=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'm'): /* operator -- */ - if (!cpp_demangle_push_str(ddata, "operator--", 10)) + if (!DEM_PUSH_STR(ddata, "operator--")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'a'): /* operator new[] */ - if (!cpp_demangle_push_str(ddata, "operator new []", 15)) + if (!DEM_PUSH_STR(ddata, "operator new []")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'e'): /* operator != */ - if (!cpp_demangle_push_str(ddata, "operator!=", 10)) + if (!DEM_PUSH_STR(ddata, "operator!=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'g'): /* operator - (unary) */ - if (!cpp_demangle_push_str(ddata, "operator-", 9)) + if (!DEM_PUSH_STR(ddata, "operator-")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 't'): /* operator ! */ - if (!cpp_demangle_push_str(ddata, "operator!", 9)) + if (!DEM_PUSH_STR(ddata, "operator!")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'w'): /* operator new */ - if (!cpp_demangle_push_str(ddata, "operator new", 12)) + if (!DEM_PUSH_STR(ddata, "operator new")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'o'): /* operator || */ - if (!cpp_demangle_push_str(ddata, "operator||", 10)) + if (!DEM_PUSH_STR(ddata, "operator||")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'r'): /* operator | */ - if (!cpp_demangle_push_str(ddata, "operator|", 9)) + if (!DEM_PUSH_STR(ddata, "operator|")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'R'): /* operator |= */ - if (!cpp_demangle_push_str(ddata, "operator|=", 10)) + if (!DEM_PUSH_STR(ddata, "operator|=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'l'): /* operator + */ - if (!cpp_demangle_push_str(ddata, "operator+", 9)) + if (!DEM_PUSH_STR(ddata, "operator+")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'L'): /* operator += */ - if (!cpp_demangle_push_str(ddata, "operator+=", 10)) + if (!DEM_PUSH_STR(ddata, "operator+=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'm'): /* operator ->* */ - if (!cpp_demangle_push_str(ddata, "operator->*", 11)) + if (!DEM_PUSH_STR(ddata, "operator->*")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'p'): /* operator ++ */ - if (!cpp_demangle_push_str(ddata, "operator++", 10)) + if (!DEM_PUSH_STR(ddata, "operator++")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 's'): /* operator + (unary) */ - if (!cpp_demangle_push_str(ddata, "operator+", 9)) + if (!DEM_PUSH_STR(ddata, "operator+")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 't'): /* operator -> */ - if (!cpp_demangle_push_str(ddata, "operator->", 10)) + if (!DEM_PUSH_STR(ddata, "operator->")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('q', 'u'): /* operator ? */ - if (!cpp_demangle_push_str(ddata, "operator?", 9)) + if (!DEM_PUSH_STR(ddata, "operator?")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'm'): /* operator % */ - if (!cpp_demangle_push_str(ddata, "operator%", 9)) + if (!DEM_PUSH_STR(ddata, "operator%")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'M'): /* operator %= */ - if (!cpp_demangle_push_str(ddata, "operator%=", 10)) + if (!DEM_PUSH_STR(ddata, "operator%=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 's'): /* operator >> */ - if (!cpp_demangle_push_str(ddata, "operator>>", 10)) + if (!DEM_PUSH_STR(ddata, "operator>>")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'S'): /* operator >>= */ - if (!cpp_demangle_push_str(ddata, "operator>>=", 11)) + if (!DEM_PUSH_STR(ddata, "operator>>=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'z'): /* operator sizeof */ - if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16)) + if (!DEM_PUSH_STR(ddata, "operator sizeof ")) 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)) + if (!DEM_PUSH_STR(ddata, "scope resolution operator ")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('s', 'v'): /* operator sizeof */ - if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16)) + if (!DEM_PUSH_STR(ddata, "operator sizeof ")) 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)) + if (!DEM_PUSH_STR(ddata, "vendor extened operator ")) 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)) + if (!DEM_PUSH_STR(ddata, "::")) 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)) + if (!DEM_PUSH_STR(ddata, "::~")) 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)) + if (!DEM_PUSH_STR(ddata, "offset : ")) return (0); if (!cpp_demangle_read_offset_number(ddata)) return (0); - if (!cpp_demangle_push_str(ddata, "virtual offset : ", 17)) + if (!DEM_PUSH_STR(ddata, "virtual offset : ")) 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.c =================================================================== --- vendor/elftoolchain/dist/nm/nm.c (revision 317072) +++ vendor/elftoolchain/dist/nm/nm.c (revision 317073) @@ -1,2120 +1,2120 @@ /*- * Copyright (c) 2007 Hyogeol Lee * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: nm.c 3472 2016-05-17 20:11:16Z emaste $"); +ELFTC_VCSID("$Id: nm.c 3504 2016-12-17 15:33:16Z kaiwang27 $"); /* symbol information list */ STAILQ_HEAD(sym_head, sym_entry); struct sym_entry { char *name; GElf_Sym *sym; STAILQ_ENTRY(sym_entry) sym_entries; }; typedef int (*fn_sort)(const void *, const void *); typedef void (*fn_elem_print)(char, const char *, const GElf_Sym *, const char *); typedef void (*fn_sym_print)(const GElf_Sym *); typedef int (*fn_filter)(char, const GElf_Sym *, const char *); /* output filter list */ static SLIST_HEAD(filter_head, filter_entry) nm_out_filter = SLIST_HEAD_INITIALIZER(nm_out_filter); struct filter_entry { fn_filter fn; SLIST_ENTRY(filter_entry) filter_entries; }; struct sym_print_data { struct sym_head *headp; size_t sh_num, list_num; const char *t_table, **s_table, *filename, *objname; }; struct nm_prog_info { const char *name; const char *def_filename; }; /* List for line number information. */ struct line_info_entry { uint64_t addr; /* address */ uint64_t line; /* line number */ char *file; /* file name with path */ SLIST_ENTRY(line_info_entry) entries; }; SLIST_HEAD(line_info_head, line_info_entry); /* List for function line number information. */ struct func_info_entry { char *name; /* function name */ char *file; /* file name with path */ uint64_t lowpc; /* low address */ uint64_t highpc; /* high address */ uint64_t line; /* line number */ SLIST_ENTRY(func_info_entry) entries; }; SLIST_HEAD(func_info_head, func_info_entry); /* List for variable line number information. */ struct var_info_entry { char *name; /* variable name */ char *file; /* file name with path */ uint64_t addr; /* address */ uint64_t line; /* line number */ SLIST_ENTRY(var_info_entry) entries; }; SLIST_HEAD(var_info_head, var_info_entry); /* output numric type */ enum radix { RADIX_OCT, RADIX_HEX, RADIX_DEC }; /* output symbol type, PRINT_SYM_DYN for dynamic symbol only */ enum print_symbol { PRINT_SYM_SYM, PRINT_SYM_DYN }; /* output name type */ enum print_name { PRINT_NAME_NONE, PRINT_NAME_FULL, PRINT_NAME_MULTI }; struct nm_prog_options { enum print_symbol print_symbol; enum print_name print_name; enum radix t; int demangle_type; bool print_debug; bool print_armap; int print_size; bool debug_line; int def_only; bool undef_only; int sort_size; bool sort_reverse; int no_demangle; /* * function pointer to sort symbol list. * possible function - cmp_name, cmp_none, cmp_size, cmp_value */ fn_sort sort_fn; /* * function pointer to print symbol elem. * possible function - sym_elem_print_all * sym_elem_print_all_portable * sym_elem_print_all_sysv */ fn_elem_print elem_print_fn; fn_sym_print value_print_fn; fn_sym_print size_print_fn; }; #define CHECK_SYM_PRINT_DATA(p) (p->headp == NULL || p->sh_num == 0 || \ p->t_table == NULL || p->s_table == NULL || p->filename == NULL) #define IS_SYM_TYPE(t) ((t) == '?' || isalpha((t)) != 0) #define IS_UNDEF_SYM_TYPE(t) ((t) == 'U' || (t) == 'v' || (t) == 'w') #define UNUSED(p) ((void)p) static int cmp_name(const void *, const void *); static int cmp_none(const void *, const void *); static int cmp_size(const void *, const void *); static int cmp_value(const void *, const void *); static void filter_dest(void); static int filter_insert(fn_filter); static void get_opt(int, char **); static int get_sym(Elf *, struct sym_head *, int, size_t, size_t, const char *, const char **, int); static const char * get_sym_name(Elf *, const GElf_Sym *, size_t, const char **, int); static char get_sym_type(const GElf_Sym *, const char *); static void global_dest(void); static void global_init(void); static bool is_sec_data(GElf_Shdr *); static bool is_sec_debug(const char *); static bool is_sec_nobits(GElf_Shdr *); static bool is_sec_readonly(GElf_Shdr *); static bool is_sec_text(GElf_Shdr *); static void print_ar_index(int, Elf *); static void print_header(const char *, const char *); static void print_version(void); static int read_elf(Elf *, const char *, Elf_Kind); static int read_object(const char *); static int read_files(int, char **); static void set_opt_value_print_fn(enum radix); static int sym_elem_def(char, const GElf_Sym *, const char *); static int sym_elem_global(char, const GElf_Sym *, const char *); static int sym_elem_global_static(char, const GElf_Sym *, const char *); static int sym_elem_nondebug(char, const GElf_Sym *, const char *); static int sym_elem_nonzero_size(char, const GElf_Sym *, const char *); static void sym_elem_print_all(char, const char *, const GElf_Sym *, const char *); static void sym_elem_print_all_portable(char, const char *, const GElf_Sym *, const char *); static void sym_elem_print_all_sysv(char, const char *, const GElf_Sym *, const char *); static int sym_elem_undef(char, const GElf_Sym *, const char *); static void sym_list_dest(struct sym_head *); static int sym_list_insert(struct sym_head *, const char *, const GElf_Sym *); static void sym_list_print(struct sym_print_data *, struct func_info_head *, struct var_info_head *, struct line_info_head *); static void sym_list_print_each(struct sym_entry *, struct sym_print_data *, struct func_info_head *, struct var_info_head *, struct line_info_head *); static struct sym_entry *sym_list_sort(struct sym_print_data *); static void sym_size_oct_print(const GElf_Sym *); static void sym_size_hex_print(const GElf_Sym *); static void sym_size_dec_print(const GElf_Sym *); static void sym_value_oct_print(const GElf_Sym *); static void sym_value_hex_print(const GElf_Sym *); static void sym_value_dec_print(const GElf_Sym *); static void usage(int); static struct nm_prog_info nm_info; static struct nm_prog_options nm_opts; static int nm_elfclass; /* * Point to current sym_print_data to use portable qsort function. * (e.g. There is no qsort_r function in NetBSD.) * * Using in sym_list_sort. */ static struct sym_print_data *nm_print_data; static const struct option nm_longopts[] = { { "debug-syms", no_argument, NULL, 'a' }, { "defined-only", no_argument, &nm_opts.def_only, 1}, { "demangle", optional_argument, NULL, 'C' }, { "dynamic", no_argument, NULL, 'D' }, { "extern-only", no_argument, NULL, 'g' }, { "format", required_argument, NULL, 'F' }, { "help", no_argument, NULL, 'h' }, { "line-numbers", no_argument, NULL, 'l' }, { "no-demangle", no_argument, &nm_opts.no_demangle, 1}, { "no-sort", no_argument, NULL, 'p' }, { "numeric-sort", no_argument, NULL, 'v' }, { "print-armap", no_argument, NULL, 's' }, { "print-file-name", no_argument, NULL, 'A' }, { "print-size", no_argument, NULL, 'S' }, { "radix", required_argument, NULL, 't' }, { "reverse-sort", no_argument, NULL, 'r' }, { "size-sort", no_argument, &nm_opts.sort_size, 1}, { "undefined-only", no_argument, NULL, 'u' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; #if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS) static __inline uint32_t be32dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); } static __inline uint32_t le32dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); } static __inline uint64_t be64dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); } static __inline uint64_t le64dec(const void *pp) { unsigned char const *p = (unsigned char const *)pp; return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); } #endif static int cmp_name(const void *l, const void *r) { assert(l != NULL); assert(r != NULL); assert(((const struct sym_entry *)l)->name != NULL); assert(((const struct sym_entry *)r)->name != NULL); return (strcmp(((const struct sym_entry *)l)->name, ((const struct sym_entry *)r)->name)); } static int cmp_none(const void *l, const void *r) { UNUSED(l); UNUSED(r); return (0); } /* Size comparison. If l and r have same size, compare their name. */ static int cmp_size(const void *lp, const void *rp) { const struct sym_entry *l, *r; l = lp; r = rp; assert(l != NULL); assert(l->name != NULL); assert(l->sym != NULL); assert(r != NULL); assert(r->name != NULL); assert(r->sym != NULL); if (l->sym->st_size == r->sym->st_size) return (strcmp(l->name, r->name)); return (l->sym->st_size - r->sym->st_size); } /* Value comparison. Undefined symbols come first. */ static int cmp_value(const void *lp, const void *rp) { const struct sym_entry *l, *r; const char *ttable; int l_is_undef, r_is_undef; l = lp; r = rp; assert(nm_print_data != NULL); ttable = nm_print_data->t_table; assert(l != NULL); assert(l->name != NULL); assert(l->sym != NULL); assert(r != NULL); assert(r->name != NULL); assert(r->sym != NULL); assert(ttable != NULL); l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0; r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0; assert(l_is_undef + r_is_undef >= 0); assert(l_is_undef + r_is_undef <= 2); switch (l_is_undef + r_is_undef) { case 0: /* Both defined */ if (l->sym->st_value == r->sym->st_value) return (strcmp(l->name, r->name)); return (l->sym->st_value > r->sym->st_value ? 1 : -1); case 1: /* One undefined */ return (l_is_undef == 0 ? 1 : -1); case 2: /* Both undefined */ return (strcmp(l->name, r->name)); } /* NOTREACHED */ return (l->sym->st_value - r->sym->st_value); } static void filter_dest(void) { struct filter_entry *e; while (!SLIST_EMPTY(&nm_out_filter)) { e = SLIST_FIRST(&nm_out_filter); SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries); free(e); } } static int filter_insert(fn_filter filter_fn) { struct filter_entry *e; assert(filter_fn != NULL); if ((e = malloc(sizeof(struct filter_entry))) == NULL) { warn("malloc"); return (0); } e->fn = filter_fn; SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries); return (1); } static int parse_demangle_option(const char *opt) { if (opt == NULL) return (ELFTC_DEM_UNKNOWN); else if (!strncasecmp(opt, "gnu-v2", 6)) return (ELFTC_DEM_GNU2); else if (!strncasecmp(opt, "gnu-v3", 6)) return (ELFTC_DEM_GNU3); else if (!strncasecmp(opt, "arm", 3)) return (ELFTC_DEM_ARM); else errx(EXIT_FAILURE, "unknown demangling style '%s'", opt); /* NOTREACHED */ return (0); } static void get_opt(int argc, char **argv) { int ch; bool is_posix, oflag; if (argc <= 0 || argv == NULL) return; oflag = is_posix = false; nm_opts.t = RADIX_HEX; while ((ch = getopt_long(argc, argv, "ABCDF:PSVaefghlnoprst:uvx", nm_longopts, NULL)) != -1) { switch (ch) { case 'A': nm_opts.print_name = PRINT_NAME_FULL; break; case 'B': nm_opts.elem_print_fn = &sym_elem_print_all; break; case 'C': nm_opts.demangle_type = parse_demangle_option(optarg); break; case 'D': nm_opts.print_symbol = PRINT_SYM_DYN; break; case 'F': /* sysv, bsd, posix */ switch (optarg[0]) { case 'B': case 'b': nm_opts.elem_print_fn = &sym_elem_print_all; break; case 'P': case 'p': is_posix = true; nm_opts.elem_print_fn = &sym_elem_print_all_portable; break; case 'S': case 's': nm_opts.elem_print_fn = &sym_elem_print_all_sysv; break; default: warnx("%s: Invalid format", optarg); usage(1); } break; case 'P': is_posix = true; nm_opts.elem_print_fn = &sym_elem_print_all_portable; break; case 'S': nm_opts.print_size = 1; break; case 'V': print_version(); /* NOTREACHED */ case 'a': nm_opts.print_debug = true; break; case 'e': filter_insert(sym_elem_global_static); break; case 'f': break; case 'g': filter_insert(sym_elem_global); break; case 'h': usage(0); break; case 'l': nm_opts.debug_line = true; break; case 'n': case 'v': nm_opts.sort_fn = &cmp_value; break; case 'o': oflag = true; break; case 'p': nm_opts.sort_fn = &cmp_none; break; case 'r': nm_opts.sort_reverse = true; break; case 's': nm_opts.print_armap = true; break; case 't': /* t require always argument to getopt_long */ switch (optarg[0]) { case 'd': nm_opts.t = RADIX_DEC; break; case 'o': nm_opts.t = RADIX_OCT; break; case 'x': nm_opts.t = RADIX_HEX; break; default: warnx("%s: Invalid radix", optarg); usage(1); } break; case 'u': filter_insert(sym_elem_undef); nm_opts.undef_only = true; break; /* case 'v': see case 'n' above. */ case 'x': nm_opts.t = RADIX_HEX; break; case 0: if (nm_opts.sort_size != 0) { nm_opts.sort_fn = &cmp_size; filter_insert(sym_elem_def); filter_insert(sym_elem_nonzero_size); } if (nm_opts.def_only != 0) filter_insert(sym_elem_def); if (nm_opts.no_demangle != 0) nm_opts.demangle_type = -1; break; default : usage(1); } } /* * In POSIX mode, the '-o' option controls the output radix. * In non-POSIX mode, the option is a synonym for the '-A' and * '--print-file-name' options. */ if (oflag) { if (is_posix) nm_opts.t = RADIX_OCT; else nm_opts.print_name = PRINT_NAME_FULL; } assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null"); assert(nm_opts.elem_print_fn != NULL && "nm_opts.elem_print_fn is null"); assert(nm_opts.value_print_fn != NULL && "nm_opts.value_print_fn is null"); set_opt_value_print_fn(nm_opts.t); if (nm_opts.undef_only == true) { if (nm_opts.sort_fn == &cmp_size) errx(EXIT_FAILURE, "--size-sort with -u is meaningless"); if (nm_opts.def_only != 0) errx(EXIT_FAILURE, "-u with --defined-only is meaningless"); } if (nm_opts.print_debug == false) filter_insert(sym_elem_nondebug); if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none) nm_opts.sort_reverse = false; } /* * Get symbol information from elf. */ static int get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx, size_t strndx, const char *type_table, const char **sec_table, int sec_table_size) { Elf_Scn *scn; Elf_Data *data; GElf_Shdr shdr; GElf_Sym sym; struct filter_entry *fep; size_t ndx; int rtn; const char *sym_name; char type; bool filter; int i, j; assert(elf != NULL); assert(headp != NULL); rtn = 0; for (i = 1; i < shnum; i++) { if ((scn = elf_getscn(elf, i)) == NULL) { warnx("elf_getscn failed: %s", elf_errmsg(-1)); continue; } if (gelf_getshdr(scn, &shdr) != &shdr) { warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); continue; } if (shdr.sh_type == SHT_SYMTAB) { if (nm_opts.print_symbol != PRINT_SYM_SYM) continue; } else if (shdr.sh_type == SHT_DYNSYM) { if (nm_opts.print_symbol != PRINT_SYM_DYN) continue; } else continue; ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx; data = NULL; while ((data = elf_getdata(scn, data)) != NULL) { j = 1; while (gelf_getsym(data, j++, &sym) != NULL) { sym_name = get_sym_name(elf, &sym, ndx, sec_table, sec_table_size); filter = false; type = get_sym_type(&sym, type_table); SLIST_FOREACH(fep, &nm_out_filter, filter_entries) { if (!fep->fn(type, &sym, sym_name)) { filter = true; break; } } if (filter == false) { if (sym_list_insert(headp, sym_name, &sym) == 0) return (0); rtn++; } } } } return (rtn); } static const char * get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table, int sec_table_size) { const char *sym_name; sym_name = NULL; /* Show section name as symbol name for STT_SECTION symbols. */ if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) { if (sec_table != NULL && sym->st_shndx < sec_table_size) sym_name = sec_table[sym->st_shndx]; } else sym_name = elf_strptr(elf, ndx, sym->st_name); if (sym_name == NULL) sym_name = "(null)"; return (sym_name); } static char get_sym_type(const GElf_Sym *sym, const char *type_table) { bool is_local; if (sym == NULL || type_table == NULL) return ('?'); is_local = sym->st_info >> 4 == STB_LOCAL; if (sym->st_shndx == SHN_ABS) /* absolute */ return (is_local ? 'a' : 'A'); if (sym->st_shndx == SHN_COMMON) /* common */ return ('C'); if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */ if ((sym->st_info & 0xf) == STT_OBJECT) return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V'); return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W'); } if (sym->st_shndx == SHN_UNDEF) /* undefined */ return ('U'); return (is_local == true && type_table[sym->st_shndx] != 'N' ? tolower((unsigned char) type_table[sym->st_shndx]) : type_table[sym->st_shndx]); } static void global_dest(void) { filter_dest(); } static void global_init(void) { if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "elf_version error"); nm_info.name = ELFTC_GETPROGNAME(); nm_info.def_filename = "a.out"; nm_opts.print_symbol = PRINT_SYM_SYM; nm_opts.print_name = PRINT_NAME_NONE; nm_opts.demangle_type = -1; nm_opts.print_debug = false; nm_opts.print_armap = false; nm_opts.print_size = 0; nm_opts.debug_line = false; nm_opts.def_only = 0; nm_opts.undef_only = false; nm_opts.sort_size = 0; nm_opts.sort_reverse = false; nm_opts.no_demangle = 0; nm_opts.sort_fn = &cmp_name; nm_opts.elem_print_fn = &sym_elem_print_all; nm_opts.value_print_fn = &sym_value_dec_print; nm_opts.size_print_fn = &sym_size_dec_print; SLIST_INIT(&nm_out_filter); } static bool is_sec_data(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS); } static bool is_sec_debug(const char *shname) { const char *dbg_sec[] = { ".debug", ".gnu.linkonce.wi.", ".line", ".rel.debug", ".rela.debug", ".stab", NULL }; const char **p; if (shname == NULL) return (false); for (p = dbg_sec; *p; p++) { if (!strncmp(shname, *p, strlen(*p))) return (true); } return (false); } static bool is_sec_nobits(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return (s->sh_type == SHT_NOBITS); } static bool is_sec_readonly(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return ((s->sh_flags & SHF_WRITE) == 0); } static bool is_sec_text(GElf_Shdr *s) { assert(s != NULL && "shdr is NULL"); return ((s->sh_flags & SHF_EXECINSTR) != 0); } static void print_ar_index(int fd, Elf *arf) { Elf *elf; Elf_Arhdr *arhdr; Elf_Arsym *arsym; Elf_Cmd cmd; off_t start; size_t arsym_size; if (arf == NULL) return; if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL) return; printf("\nArchive index:\n"); start = arsym->as_off; cmd = ELF_C_READ; while (arsym_size > 1) { if (elf_rand(arf, arsym->as_off) == arsym->as_off && (elf = elf_begin(fd, cmd, arf)) != NULL) { if ((arhdr = elf_getarhdr(elf)) != NULL) printf("%s in %s\n", arsym->as_name, arhdr->ar_name != NULL ? arhdr->ar_name : arhdr->ar_rawname); elf_end(elf); } ++arsym; --arsym_size; } elf_rand(arf, start); } #define DEMANGLED_BUFFER_SIZE (8 * 1024) #define PRINT_DEMANGLED_NAME(FORMAT, NAME) do { \ char _demangled[DEMANGLED_BUFFER_SIZE]; \ if (nm_opts.demangle_type < 0 || \ elftc_demangle((NAME), _demangled, sizeof(_demangled), \ nm_opts.demangle_type) < 0) \ printf((FORMAT), (NAME)); \ else \ printf((FORMAT), _demangled); \ } while (0) static void print_header(const char *file, const char *obj) { if (file == NULL) return; if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) { printf("\n\n%s from %s", nm_opts.undef_only == false ? "Symbols" : "Undefined symbols", file); if (obj != NULL) printf("[%s]", obj); printf(":\n\n"); printf("\ Name Value Class Type Size Line Section\n\n"); } else { /* archive file without -A option and POSIX */ if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) { if (nm_opts.elem_print_fn == sym_elem_print_all_portable) printf("%s[%s]:\n", file, obj); else if (nm_opts.elem_print_fn == sym_elem_print_all) printf("\n%s:\n", obj); /* multiple files(not archive) without -A option */ } else if (nm_opts.print_name == PRINT_NAME_MULTI) { if (nm_opts.elem_print_fn == sym_elem_print_all) printf("\n"); printf("%s:\n", file); } } } static void print_version(void) { (void) printf("%s (%s)\n", nm_info.name, elftc_version()); exit(0); } static uint64_t get_block_value(Dwarf_Debug dbg, Dwarf_Block *block) { Elf *elf; GElf_Ehdr eh; Dwarf_Error de; if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) { warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de)); return (0); } if (gelf_getehdr(elf, &eh) != &eh) { warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); return (0); } if (block->bl_len == 5) { if (eh.e_ident[EI_DATA] == ELFDATA2LSB) return (le32dec((uint8_t *) block->bl_data + 1)); else return (be32dec((uint8_t *) block->bl_data + 1)); } else if (block->bl_len == 9) { if (eh.e_ident[EI_DATA] == ELFDATA2LSB) return (le64dec((uint8_t *) block->bl_data + 1)); else return (be64dec((uint8_t *) block->bl_data + 1)); } return (0); } static char * find_object_name(Dwarf_Debug dbg, Dwarf_Die die) { Dwarf_Die ret_die; Dwarf_Attribute at; Dwarf_Off off; Dwarf_Error de; const char *str; char *name; if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == DW_DLV_OK) { if ((name = strdup(str)) == NULL) { warn("strdup"); return (NULL); } return (name); } if (dwarf_attr(die, DW_AT_specification, &at, &de) != DW_DLV_OK) return (NULL); if (dwarf_global_formref(at, &off, &de) != DW_DLV_OK) return (NULL); if (dwarf_offdie(dbg, off, &ret_die, &de) != DW_DLV_OK) return (NULL); return (find_object_name(dbg, ret_die)); } static void search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info, struct var_info_head *var_info, Dwarf_Die die, char **src_files, Dwarf_Signed filecount) { Dwarf_Attribute at; Dwarf_Unsigned udata; Dwarf_Half tag; Dwarf_Block *block; Dwarf_Bool flag; Dwarf_Die ret_die; Dwarf_Error de; struct func_info_entry *func; struct var_info_entry *var; int ret; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); goto cont_search; } /* We're interested in DIEs which define functions or variables. */ if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point && tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable) goto cont_search; if (tag == DW_TAG_variable) { /* Ignore "artificial" variable. */ if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) == DW_DLV_OK && flag) goto cont_search; /* Ignore pure declaration. */ if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) == DW_DLV_OK && flag) goto cont_search; /* Ignore stack varaibles. */ if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) != DW_DLV_OK || !flag) goto cont_search; if ((var = calloc(1, sizeof(*var))) == NULL) { warn("calloc failed"); goto cont_search; } if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, &de) == DW_DLV_OK && udata > 0 && (Dwarf_Signed) (udata - 1) < filecount) { var->file = strdup(src_files[udata - 1]); if (var->file == NULL) { warn("strdup"); free(var); goto cont_search; } } if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == DW_DLV_OK) var->line = udata; var->name = find_object_name(dbg, die); if (var->name == NULL) { if (var->file) free(var->file); free(var); goto cont_search; } if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK && dwarf_formblock(at, &block, &de) == DW_DLV_OK) { /* * Since we ignored stack variables, the rest are the * external varaibles which should always use DW_OP_addr * operator for DW_AT_location value. */ if (*((uint8_t *)block->bl_data) == DW_OP_addr) var->addr = get_block_value(dbg, block); } SLIST_INSERT_HEAD(var_info, var, entries); } else { if ((func = calloc(1, sizeof(*func))) == NULL) { warn("calloc failed"); goto cont_search; } /* * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line * attributes for inlined functions as well. */ if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, &de) == DW_DLV_OK && udata > 0 && (Dwarf_Signed) (udata - 1) < filecount) { func->file = strdup(src_files[udata - 1]); if (func->file == NULL) { warn("strdup"); free(func); goto cont_search; } } if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == DW_DLV_OK) func->line = udata; func->name = find_object_name(dbg, die); if (func->name == NULL) { if (func->file) free(func->file); free(func); goto cont_search; } if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) == DW_DLV_OK) func->lowpc = udata; if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) == DW_DLV_OK) func->highpc = udata; SLIST_INSERT_HEAD(func_info, func, entries); } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_line_attr(dbg, func_info, var_info, ret_die, src_files, filecount); /* Search sibling. */ ret = dwarf_siblingof(dbg, die, &ret_die, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_line_attr(dbg, func_info, var_info, ret_die, src_files, filecount); dwarf_dealloc(dbg, die, DW_DLA_DIE); } /* * Read elf file and collect symbol information, sort them, print. * Return 1 at failed, 0 at success. */ static int read_elf(Elf *elf, const char *filename, Elf_Kind kind) { Dwarf_Debug dbg; Dwarf_Die die; Dwarf_Error de; Dwarf_Half tag; Elf_Arhdr *arhdr; Elf_Scn *scn; GElf_Shdr shdr; GElf_Half i; Dwarf_Line *lbuf; Dwarf_Unsigned lineno; Dwarf_Signed lcount, filecount; Dwarf_Addr lineaddr; struct sym_print_data p_data; struct sym_head list_head; struct line_info_head *line_info; struct func_info_head *func_info; struct var_info_head *var_info; struct line_info_entry *lie; struct func_info_entry *func; struct var_info_entry *var; const char *shname, *objname; char *type_table, **sec_table, *sfile, **src_files; size_t shstrndx, shnum, dynndx, strndx; int ret, rtn, e_err; #define OBJNAME (objname == NULL ? filename : objname) assert(filename != NULL && "filename is null"); STAILQ_INIT(&list_head); type_table = NULL; sec_table = NULL; line_info = NULL; func_info = NULL; var_info = NULL; objname = NULL; dynndx = SHN_UNDEF; strndx = SHN_UNDEF; rtn = 0; nm_elfclass = gelf_getclass(elf); if (kind == ELF_K_AR) { if ((arhdr = elf_getarhdr(elf)) == NULL) goto next_cmd; objname = arhdr->ar_name != NULL ? arhdr->ar_name : arhdr->ar_rawname; } if (!elf_getshnum(elf, &shnum)) { if ((e_err = elf_errno()) != 0) - warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); + warnx("%s: %s", OBJNAME, "File format not recognized"); else warnx("%s: cannot get section number", OBJNAME); rtn = 1; goto next_cmd; } if (shnum == 0) { warnx("%s: has no section", OBJNAME); rtn = 1; goto next_cmd; } if (!elf_getshstrndx(elf, &shstrndx)) { warnx("%s: cannot get str index", OBJNAME); rtn = 1; goto next_cmd; } /* type_table for type determine */ if ((type_table = malloc(sizeof(char) * shnum)) == NULL) { warn("%s: malloc", OBJNAME); rtn = 1; goto next_cmd; } /* sec_table for section name to display in sysv format */ if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) { warn("%s: calloc", OBJNAME); rtn = 1; goto next_cmd; } type_table[0] = 'U'; if ((sec_table[0] = strdup("*UND*")) == NULL) { warn("strdup"); goto next_cmd; } for (i = 1; i < shnum; ++i) { type_table[i] = 'U'; if ((scn = elf_getscn(elf, i)) == NULL) { if ((e_err = elf_errno()) != 0) warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); else warnx("%s: cannot get section", OBJNAME); rtn = 1; goto next_cmd; } if (gelf_getshdr(scn, &shdr) == NULL) goto next_cmd; /* * Cannot test by type and attribute for dynstr, strtab */ shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name); if (shname != NULL) { if ((sec_table[i] = strdup(shname)) == NULL) { warn("strdup"); goto next_cmd; } if (!strncmp(shname, ".dynstr", 7)) { dynndx = elf_ndxscn(scn); if (dynndx == SHN_UNDEF) { warnx("%s: elf_ndxscn failed: %s", OBJNAME, elf_errmsg(-1)); goto next_cmd; } } if (!strncmp(shname, ".strtab", 7)) { strndx = elf_ndxscn(scn); if (strndx == SHN_UNDEF) { warnx("%s: elf_ndxscn failed: %s", OBJNAME, elf_errmsg(-1)); goto next_cmd; } } } else { sec_table[i] = strdup("*UND*"); if (sec_table[i] == NULL) { warn("strdup"); goto next_cmd; } } if (is_sec_text(&shdr)) type_table[i] = 'T'; else if (is_sec_data(&shdr)) { if (is_sec_readonly(&shdr)) type_table[i] = 'R'; else type_table[i] = 'D'; } else if (is_sec_nobits(&shdr)) type_table[i] = 'B'; else if (is_sec_debug(shname)) type_table[i] = 'N'; else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr)) type_table[i] = 'n'; } print_header(filename, objname); if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) || (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) { warnx("%s: no symbols", OBJNAME); /* This is not an error case */ goto next_cmd; } STAILQ_INIT(&list_head); if (!nm_opts.debug_line) goto process_sym; /* * Collect dwarf line number information. */ if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) != DW_DLV_OK) { warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de)); goto process_sym; } line_info = malloc(sizeof(struct line_info_head)); func_info = malloc(sizeof(struct func_info_head)); var_info = malloc(sizeof(struct var_info_head)); if (line_info == NULL || func_info == NULL || var_info == NULL) { warn("malloc"); (void) dwarf_finish(dbg, &de); goto process_sym; } SLIST_INIT(line_info); SLIST_INIT(func_info); SLIST_INIT(var_info); while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { die = NULL; while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) { if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); continue; } /* XXX: What about DW_TAG_partial_unit? */ if (tag == DW_TAG_compile_unit) break; } if (die == NULL) { warnx("could not find DW_TAG_compile_unit die"); continue; } /* Retrieve source file list. */ ret = dwarf_srcfiles(die, &src_files, &filecount, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_srclines: %s", dwarf_errmsg(de)); if (ret != DW_DLV_OK) continue; /* * Retrieve line number information from .debug_line section. */ ret = dwarf_srclines(die, &lbuf, &lcount, &de); if (ret == DW_DLV_ERROR) warnx("dwarf_srclines: %s", dwarf_errmsg(de)); if (ret != DW_DLV_OK) goto line_attr; for (i = 0; (Dwarf_Signed) i < lcount; i++) { if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); continue; } if (dwarf_lineno(lbuf[i], &lineno, &de)) { warnx("dwarf_lineno: %s", dwarf_errmsg(de)); continue; } if (dwarf_linesrc(lbuf[i], &sfile, &de)) { warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); continue; } if ((lie = malloc(sizeof(*lie))) == NULL) { warn("malloc"); continue; } lie->addr = lineaddr; lie->line = lineno; lie->file = strdup(sfile); if (lie->file == NULL) { warn("strdup"); free(lie); continue; } SLIST_INSERT_HEAD(line_info, lie, entries); } line_attr: /* Retrieve line number information from DIEs. */ search_line_attr(dbg, func_info, var_info, die, src_files, filecount); } (void) dwarf_finish(dbg, &de); process_sym: p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx, type_table, (void *) sec_table, shnum); if (p_data.list_num == 0) goto next_cmd; p_data.headp = &list_head; p_data.sh_num = shnum; p_data.t_table = type_table; p_data.s_table = (void *) sec_table; p_data.filename = filename; p_data.objname = objname; sym_list_print(&p_data, func_info, var_info, line_info); next_cmd: if (nm_opts.debug_line) { if (func_info != NULL) { while (!SLIST_EMPTY(func_info)) { func = SLIST_FIRST(func_info); SLIST_REMOVE_HEAD(func_info, entries); free(func->file); free(func->name); free(func); } free(func_info); func_info = NULL; } if (var_info != NULL) { while (!SLIST_EMPTY(var_info)) { var = SLIST_FIRST(var_info); SLIST_REMOVE_HEAD(var_info, entries); free(var->file); free(var->name); free(var); } free(var_info); var_info = NULL; } if (line_info != NULL) { while (!SLIST_EMPTY(line_info)) { lie = SLIST_FIRST(line_info); SLIST_REMOVE_HEAD(line_info, entries); free(lie->file); free(lie); } free(line_info); line_info = NULL; } } if (sec_table != NULL) for (i = 0; i < shnum; ++i) free(sec_table[i]); free(sec_table); free(type_table); sym_list_dest(&list_head); return (rtn); #undef OBJNAME } static int read_object(const char *filename) { Elf *elf, *arf; Elf_Cmd elf_cmd; Elf_Kind kind; int fd, rtn, e_err; assert(filename != NULL && "filename is null"); if ((fd = open(filename, O_RDONLY)) == -1) { warn("'%s'", filename); return (1); } elf_cmd = ELF_C_READ; if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) { if ((e_err = elf_errno()) != 0) warnx("elf_begin error: %s", elf_errmsg(e_err)); else warnx("elf_begin error"); close(fd); return (1); } assert(arf != NULL && "arf is null."); rtn = 0; if ((kind = elf_kind(arf)) == ELF_K_NONE) { warnx("%s: File format not recognized", filename); elf_end(arf); close(fd); return (1); } if (kind == ELF_K_AR) { if (nm_opts.print_name == PRINT_NAME_MULTI && nm_opts.elem_print_fn == sym_elem_print_all) printf("\n%s:\n", filename); if (nm_opts.print_armap == true) print_ar_index(fd, arf); } while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) { rtn |= read_elf(elf, filename, kind); /* * If file is not archive, elf_next return ELF_C_NULL and * stop the loop. */ elf_cmd = elf_next(elf); elf_end(elf); } elf_end(arf); close(fd); return (rtn); } static int read_files(int argc, char **argv) { int rtn = 0; if (argc < 0 || argv == NULL) return (1); if (argc == 0) rtn |= read_object(nm_info.def_filename); else { if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1) nm_opts.print_name = PRINT_NAME_MULTI; while (argc > 0) { rtn |= read_object(*argv); --argc; ++argv; } } return (rtn); } static void print_lineno(struct sym_entry *ep, struct func_info_head *func_info, struct var_info_head *var_info, struct line_info_head *line_info) { struct func_info_entry *func; struct var_info_entry *var; struct line_info_entry *lie; /* For function symbol, search the function line information list. */ if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) { SLIST_FOREACH(func, func_info, entries) { if (func->name != NULL && !strcmp(ep->name, func->name) && ep->sym->st_value >= func->lowpc && ep->sym->st_value < func->highpc) { printf("\t%s:%" PRIu64, func->file, func->line); return; } } } /* For variable symbol, search the variable line information list. */ if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) { SLIST_FOREACH(var, var_info, entries) { if (!strcmp(ep->name, var->name) && ep->sym->st_value == var->addr) { printf("\t%s:%" PRIu64, var->file, var->line); return; } } } /* Otherwise search line number information the .debug_line section. */ if (line_info != NULL) { SLIST_FOREACH(lie, line_info, entries) { if (ep->sym->st_value == lie->addr) { printf("\t%s:%" PRIu64, lie->file, lie->line); return; } } } } static void set_opt_value_print_fn(enum radix t) { switch (t) { case RADIX_OCT: nm_opts.value_print_fn = &sym_value_oct_print; nm_opts.size_print_fn = &sym_size_oct_print; break; case RADIX_DEC: nm_opts.value_print_fn = &sym_value_dec_print; nm_opts.size_print_fn = &sym_size_dec_print; break; case RADIX_HEX: default : nm_opts.value_print_fn = &sym_value_hex_print; nm_opts.size_print_fn = &sym_size_hex_print; } assert(nm_opts.value_print_fn != NULL && "nm_opts.value_print_fn is null"); } static void sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym, const char *name) { if (sec == NULL || sym == NULL || name == NULL || nm_opts.value_print_fn == NULL) return; if (IS_UNDEF_SYM_TYPE(type)) { if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32) printf("%-8s", ""); else printf("%-16s", ""); } else { switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) + nm_opts.print_size) { case 3: if (sym->st_size != 0) { nm_opts.value_print_fn(sym); printf(" "); nm_opts.size_print_fn(sym); } break; case 2: if (sym->st_size != 0) nm_opts.size_print_fn(sym); break; case 1: nm_opts.value_print_fn(sym); if (sym->st_size != 0) { printf(" "); nm_opts.size_print_fn(sym); } break; case 0: default: nm_opts.value_print_fn(sym); } } printf(" %c ", type); PRINT_DEMANGLED_NAME("%s", name); } static void sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym, const char *name) { if (sec == NULL || sym == NULL || name == NULL || nm_opts.value_print_fn == NULL) return; PRINT_DEMANGLED_NAME("%s", name); printf(" %c ", type); if (!IS_UNDEF_SYM_TYPE(type)) { nm_opts.value_print_fn(sym); printf(" "); if (sym->st_size != 0) nm_opts.size_print_fn(sym); } else printf(" "); } static void sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym, const char *name) { if (sec == NULL || sym == NULL || name == NULL || nm_opts.value_print_fn == NULL) return; PRINT_DEMANGLED_NAME("%-20s|", name); if (IS_UNDEF_SYM_TYPE(type)) printf(" "); else nm_opts.value_print_fn(sym); printf("| %c |", type); switch (sym->st_info & 0xf) { case STT_OBJECT: printf("%18s|", "OBJECT"); break; case STT_FUNC: printf("%18s|", "FUNC"); break; case STT_SECTION: printf("%18s|", "SECTION"); break; case STT_FILE: printf("%18s|", "FILE"); break; case STT_LOPROC: printf("%18s|", "LOPROC"); break; case STT_HIPROC: printf("%18s|", "HIPROC"); break; case STT_NOTYPE: default: printf("%18s|", "NOTYPE"); } if (sym->st_size != 0) nm_opts.size_print_fn(sym); else printf(" "); printf("| |%s", sec); } static int sym_elem_def(char type, const GElf_Sym *sym, const char *name) { assert(IS_SYM_TYPE((unsigned char) type)); UNUSED(sym); UNUSED(name); return (!IS_UNDEF_SYM_TYPE((unsigned char) type)); } static int sym_elem_global(char type, const GElf_Sym *sym, const char *name) { assert(IS_SYM_TYPE((unsigned char) type)); UNUSED(sym); UNUSED(name); /* weak symbols resemble global. */ return (isupper((unsigned char) type) || type == 'w'); } static int sym_elem_global_static(char type, const GElf_Sym *sym, const char *name) { unsigned char info; assert(sym != NULL); UNUSED(type); UNUSED(name); info = sym->st_info >> 4; return (info == STB_LOCAL || info == STB_GLOBAL || info == STB_WEAK); } static int sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name) { assert(sym != NULL); UNUSED(type); UNUSED(name); if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE) return (0); if (sym->st_name == 0) return (0); return (1); } static int sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name) { assert(sym != NULL); UNUSED(type); UNUSED(name); return (sym->st_size > 0); } static int sym_elem_undef(char type, const GElf_Sym *sym, const char *name) { assert(IS_SYM_TYPE((unsigned char) type)); UNUSED(sym); UNUSED(name); return (IS_UNDEF_SYM_TYPE((unsigned char) type)); } static void sym_list_dest(struct sym_head *headp) { struct sym_entry *ep, *ep_n; if (headp == NULL) return; ep = STAILQ_FIRST(headp); while (ep != NULL) { ep_n = STAILQ_NEXT(ep, sym_entries); free(ep->sym); free(ep->name); free(ep); ep = ep_n; } } static int sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym) { struct sym_entry *e; if (headp == NULL || name == NULL || sym == NULL) return (0); if ((e = malloc(sizeof(struct sym_entry))) == NULL) { warn("malloc"); return (0); } if ((e->name = strdup(name)) == NULL) { warn("strdup"); free(e); return (0); } if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) { warn("malloc"); free(e->name); free(e); return (0); } memcpy(e->sym, sym, sizeof(GElf_Sym)); /* Display size instead of value for common symbol. */ if (sym->st_shndx == SHN_COMMON) e->sym->st_value = sym->st_size; STAILQ_INSERT_TAIL(headp, e, sym_entries); return (1); } /* If file has not .debug_info, line_info will be NULL */ static void sym_list_print(struct sym_print_data *p, struct func_info_head *func_info, struct var_info_head *var_info, struct line_info_head *line_info) { struct sym_entry *e_v; size_t si; int i; if (p == NULL || CHECK_SYM_PRINT_DATA(p)) return; if ((e_v = sym_list_sort(p)) == NULL) return; if (nm_opts.sort_reverse == false) for (si = 0; si != p->list_num; ++si) sym_list_print_each(&e_v[si], p, func_info, var_info, line_info); else for (i = p->list_num - 1; i != -1; --i) sym_list_print_each(&e_v[i], p, func_info, var_info, line_info); free(e_v); } /* If file has not .debug_info, line_info will be NULL */ static void sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p, struct func_info_head *func_info, struct var_info_head *var_info, struct line_info_head *line_info) { const char *sec; char type; if (ep == NULL || CHECK_SYM_PRINT_DATA(p)) return; assert(ep->name != NULL); assert(ep->sym != NULL); type = get_sym_type(ep->sym, p->t_table); if (nm_opts.print_name == PRINT_NAME_FULL) { printf("%s", p->filename); if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) { if (p->objname != NULL) printf("[%s]", p->objname); printf(": "); } else { if (p->objname != NULL) printf(":%s", p->objname); printf(":"); } } switch (ep->sym->st_shndx) { case SHN_LOPROC: /* LOPROC or LORESERVE */ sec = "*LOPROC*"; break; case SHN_HIPROC: sec = "*HIPROC*"; break; case SHN_LOOS: sec = "*LOOS*"; break; case SHN_HIOS: sec = "*HIOS*"; break; case SHN_ABS: sec = "*ABS*"; break; case SHN_COMMON: sec = "*COM*"; break; case SHN_HIRESERVE: /* HIRESERVE or XINDEX */ sec = "*HIRESERVE*"; break; default: if (ep->sym->st_shndx > p->sh_num) return; sec = p->s_table[ep->sym->st_shndx]; break; } nm_opts.elem_print_fn(type, sec, ep->sym, ep->name); if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type)) print_lineno(ep, func_info, var_info, line_info); printf("\n"); } static struct sym_entry * sym_list_sort(struct sym_print_data *p) { struct sym_entry *ep, *e_v; int idx; if (p == NULL || CHECK_SYM_PRINT_DATA(p)) return (NULL); if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) { warn("malloc"); return (NULL); } idx = 0; STAILQ_FOREACH(ep, p->headp, sym_entries) { if (ep->name != NULL && ep->sym != NULL) { e_v[idx].name = ep->name; e_v[idx].sym = ep->sym; ++idx; } } assert((size_t)idx == p->list_num); if (nm_opts.sort_fn != &cmp_none) { nm_print_data = p; assert(nm_print_data != NULL); qsort(e_v, p->list_num, sizeof(struct sym_entry), nm_opts.sort_fn); } return (e_v); } static void sym_size_oct_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRIo64, sym->st_size); } static void sym_size_hex_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); if (nm_elfclass == ELFCLASS32) printf("%08" PRIx64, sym->st_size); else printf("%016" PRIx64, sym->st_size); } static void sym_size_dec_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRId64, sym->st_size); } static void sym_value_oct_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRIo64, sym->st_value); } static void sym_value_hex_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); if (nm_elfclass == ELFCLASS32) printf("%08" PRIx64, sym->st_value); else printf("%016" PRIx64, sym->st_value); } static void sym_value_dec_print(const GElf_Sym *sym) { assert(sym != NULL && "sym is null"); printf("%016" PRId64, sym->st_value); } static void usage(int exitcode) { printf("Usage: %s [options] file ...\ \n Display symbolic information in file.\n\ \n Options: \ \n -A, --print-file-name Write the full pathname or library name of an\ \n object on each line.\ \n -a, --debug-syms Display all symbols include debugger-only\ \n symbols.", nm_info.name); printf("\ \n -B Equivalent to specifying \"--format=bsd\".\ \n -C, --demangle[=style] Decode low-level symbol names.\ \n --no-demangle Do not demangle low-level symbol names.\ \n -D, --dynamic Display only dynamic symbols.\ \n -e Display only global and static symbols."); printf("\ \n -f Produce full output (default).\ \n --format=format Display output in specific format. Allowed\ \n formats are: \"bsd\", \"posix\" and \"sysv\".\ \n -g, --extern-only Display only global symbol information.\ \n -h, --help Show this help message.\ \n -l, --line-numbers Display filename and linenumber using\ \n debugging information.\ \n -n, --numeric-sort Sort symbols numerically by value."); printf("\ \n -o Write numeric values in octal. Equivalent to\ \n specifying \"-t o\".\ \n -p, --no-sort Do not sort symbols.\ \n -P Write information in a portable output format.\ \n Equivalent to specifying \"--format=posix\".\ \n -r, --reverse-sort Reverse the order of the sort.\ \n -S, --print-size Print symbol sizes instead values.\ \n -s, --print-armap Include an index of archive members.\ \n --size-sort Sort symbols by size."); printf("\ \n -t, --radix=format Write each numeric value in the specified\ \n format:\ \n d In decimal,\ \n o In octal,\ \n x In hexadecimal."); printf("\ \n -u, --undefined-only Display only undefined symbols.\ \n --defined-only Display only defined symbols.\ \n -V, --version Show the version identifier for %s.\ \n -v Sort output by value.\ \n -x Write numeric values in hexadecimal.\ \n Equivalent to specifying \"-t x\".", nm_info.name); printf("\n\ \n The default options are: output in bsd format, use a hexadecimal radix,\ \n sort by symbol name, do not demangle names.\n"); exit(exitcode); } /* * Display symbolic information in file. * Return 0 at success, >0 at failed. */ int main(int argc, char **argv) { int rtn; global_init(); get_opt(argc, argv); rtn = read_files(argc - optind, argv + optind); global_dest(); exit(rtn); } Index: vendor/elftoolchain/dist/readelf/readelf.c =================================================================== --- vendor/elftoolchain/dist/readelf/readelf.c (revision 317072) +++ vendor/elftoolchain/dist/readelf/readelf.c (revision 317073) @@ -1,7278 +1,7299 @@ /*- * Copyright (c) 2009-2015 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 #include "_elftc.h" -ELFTC_VCSID("$Id: readelf.c 3484 2016-08-03 13:36:49Z emaste $"); +ELFTC_VCSID("$Id: readelf.c 3519 2017-04-09 23:15:58Z kaiwang27 $"); /* * readelf(1) options. */ #define RE_AA 0x00000001 #define RE_C 0x00000002 #define RE_DD 0x00000004 #define RE_D 0x00000008 #define RE_G 0x00000010 #define RE_H 0x00000020 #define RE_II 0x00000040 #define RE_I 0x00000080 #define RE_L 0x00000100 #define RE_NN 0x00000200 #define RE_N 0x00000400 #define RE_P 0x00000800 #define RE_R 0x00001000 #define RE_SS 0x00002000 #define RE_S 0x00004000 #define RE_T 0x00008000 #define RE_U 0x00010000 #define RE_VV 0x00020000 #define RE_WW 0x00040000 #define RE_W 0x00080000 #define RE_X 0x00100000 /* * dwarf dump options. */ #define DW_A 0x00000001 #define DW_FF 0x00000002 #define DW_F 0x00000004 #define DW_I 0x00000008 #define DW_LL 0x00000010 #define DW_L 0x00000020 #define DW_M 0x00000040 #define DW_O 0x00000080 #define DW_P 0x00000100 #define DW_RR 0x00000200 #define DW_R 0x00000400 #define DW_S 0x00000800 #define DW_DEFAULT_OPTIONS (DW_A | DW_F | DW_I | DW_L | DW_O | DW_P | \ DW_R | DW_RR | DW_S) /* * readelf(1) run control flags. */ #define DISPLAY_FILENAME 0x0001 /* * Internal data structure for sections. */ struct section { const char *name; /* section name */ Elf_Scn *scn; /* section scn */ uint64_t off; /* section offset */ uint64_t sz; /* section size */ uint64_t entsize; /* section entsize */ uint64_t align; /* section alignment */ uint64_t type; /* section type */ uint64_t flags; /* section flags */ uint64_t addr; /* section virtual addr */ uint32_t link; /* section link ndx */ uint32_t info; /* section info ndx */ }; struct dumpop { union { size_t si; /* section index */ const char *sn; /* section name */ } u; enum { DUMP_BY_INDEX = 0, DUMP_BY_NAME } type; /* dump type */ #define HEX_DUMP 0x0001 #define STR_DUMP 0x0002 int op; /* dump operation */ STAILQ_ENTRY(dumpop) dumpop_list; }; struct symver { const char *name; int type; }; /* * Structure encapsulates the global data for readelf(1). */ struct readelf { const char *filename; /* current processing file. */ int options; /* command line options. */ int flags; /* run control flags. */ int dop; /* dwarf dump options. */ Elf *elf; /* underlying ELF descriptor. */ Elf *ar; /* archive ELF descriptor. */ Dwarf_Debug dbg; /* DWARF handle. */ Dwarf_Half cu_psize; /* DWARF CU pointer size. */ Dwarf_Half cu_osize; /* DWARF CU offset size. */ Dwarf_Half cu_ver; /* DWARF CU version. */ GElf_Ehdr ehdr; /* ELF header. */ int ec; /* ELF class. */ size_t shnum; /* #sections. */ struct section *vd_s; /* Verdef section. */ struct section *vn_s; /* Verneed section. */ struct section *vs_s; /* Versym section. */ uint16_t *vs; /* Versym array. */ int vs_sz; /* Versym array size. */ struct symver *ver; /* Version array. */ int ver_sz; /* Size of version array. */ struct section *sl; /* list of sections. */ STAILQ_HEAD(, dumpop) v_dumpop; /* list of dump ops. */ uint64_t (*dw_read)(Elf_Data *, uint64_t *, int); uint64_t (*dw_decode)(uint8_t **, int); }; enum options { OPTION_DEBUG_DUMP }; static struct option longopts[] = { {"all", no_argument, NULL, 'a'}, {"arch-specific", no_argument, NULL, 'A'}, {"archive-index", no_argument, NULL, 'c'}, {"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP}, {"dynamic", no_argument, NULL, 'd'}, {"file-header", no_argument, NULL, 'h'}, {"full-section-name", no_argument, NULL, 'N'}, {"headers", no_argument, NULL, 'e'}, {"help", no_argument, 0, 'H'}, {"hex-dump", required_argument, NULL, 'x'}, {"histogram", no_argument, NULL, 'I'}, {"notes", no_argument, NULL, 'n'}, {"program-headers", no_argument, NULL, 'l'}, {"relocs", no_argument, NULL, 'r'}, {"sections", no_argument, NULL, 'S'}, {"section-headers", no_argument, NULL, 'S'}, {"section-groups", no_argument, NULL, 'g'}, {"section-details", no_argument, NULL, 't'}, {"segments", no_argument, NULL, 'l'}, {"string-dump", required_argument, NULL, 'p'}, {"symbols", no_argument, NULL, 's'}, {"syms", no_argument, NULL, 's'}, {"unwind", no_argument, NULL, 'u'}, {"use-dynamic", no_argument, NULL, 'D'}, {"version-info", no_argument, 0, 'V'}, {"version", no_argument, 0, 'v'}, {"wide", no_argument, 0, 'W'}, {NULL, 0, NULL, 0} }; struct eflags_desc { uint64_t flag; const char *desc; }; struct mips_option { uint64_t flag; const char *desc; }; static void add_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t); static const char *aeabi_adv_simd_arch(uint64_t simd); static const char *aeabi_align_needed(uint64_t an); static const char *aeabi_align_preserved(uint64_t ap); static const char *aeabi_arm_isa(uint64_t ai); static const char *aeabi_cpu_arch(uint64_t arch); static const char *aeabi_cpu_arch_profile(uint64_t pf); static const char *aeabi_div(uint64_t du); static const char *aeabi_enum_size(uint64_t es); static const char *aeabi_fp_16bit_format(uint64_t fp16); static const char *aeabi_fp_arch(uint64_t fp); static const char *aeabi_fp_denormal(uint64_t fd); static const char *aeabi_fp_exceptions(uint64_t fe); static const char *aeabi_fp_hpext(uint64_t fh); static const char *aeabi_fp_number_model(uint64_t fn); static const char *aeabi_fp_optm_goal(uint64_t fog); static const char *aeabi_fp_rounding(uint64_t fr); static const char *aeabi_hardfp(uint64_t hfp); static const char *aeabi_mpext(uint64_t mp); static const char *aeabi_optm_goal(uint64_t og); static const char *aeabi_pcs_config(uint64_t pcs); static const char *aeabi_pcs_got(uint64_t got); static const char *aeabi_pcs_r9(uint64_t r9); static const char *aeabi_pcs_ro(uint64_t ro); static const char *aeabi_pcs_rw(uint64_t rw); static const char *aeabi_pcs_wchar_t(uint64_t wt); static const char *aeabi_t2ee(uint64_t t2ee); static const char *aeabi_thumb_isa(uint64_t ti); static const char *aeabi_fp_user_exceptions(uint64_t fu); static const char *aeabi_unaligned_access(uint64_t ua); static const char *aeabi_vfp_args(uint64_t va); static const char *aeabi_virtual(uint64_t vt); static const char *aeabi_wmmx_arch(uint64_t wmmx); static const char *aeabi_wmmx_args(uint64_t wa); static const char *elf_class(unsigned int class); static const char *elf_endian(unsigned int endian); static const char *elf_machine(unsigned int mach); static const char *elf_osabi(unsigned int abi); static const char *elf_type(unsigned int type); static const char *elf_ver(unsigned int ver); static const char *dt_type(unsigned int mach, unsigned int dtype); static void dump_ar(struct readelf *re, int); static void dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe); static void dump_attributes(struct readelf *re); static uint8_t *dump_compatibility_tag(uint8_t *p, uint8_t *pe); 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_section_groups(struct readelf *re); 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, uint8_t *pe); 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 int get_ent_count(struct section *s, int *ent_count); 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 *note_type_xen(unsigned int nt); static const char *option_kind(uint8_t kind); static const char *phdr_type(unsigned int mach, unsigned int ptype); static const char *ppc_abi_fp(uint64_t fp); static const char *ppc_abi_vector(uint64_t vec); static void readelf_usage(int status); 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 mach, unsigned int os, 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, uint8_t *dpe); static uint64_t _decode_uleb128(uint8_t **dp, uint8_t *dpe); 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_NONE: return "NONE"; case ELFOSABI_HPUX: return "HPUX"; 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_CLOUDABI: return "CloudABI"; case ELFOSABI_ARM_AEABI: return "ARM EABI"; 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_IAMCU: return "Intel MCU"; 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"; case EM_RISCV: return "RISC-V"; 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 mach, unsigned int ptype) { static char s_ptype[32]; if (ptype >= PT_LOPROC && ptype <= PT_HIPROC) { switch (mach) { case EM_ARM: switch (ptype) { case PT_ARM_ARCHEXT: return "ARM_ARCHEXT"; case PT_ARM_EXIDX: return "ARM_EXIDX"; } break; } snprintf(s_ptype, sizeof(s_ptype), "LOPROC+%#x", ptype - PT_LOPROC); return (s_ptype); } 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"; + case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE"; + case PT_OPENBSD_WXNEEDED: return "OPENBSD_WXNEEDED"; + case PT_OPENBSD_BOOTDATA: return "OPENBSD_BOOTDATA"; default: 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_ARM: switch (stype) { case SHT_ARM_EXIDX: return "ARM_EXIDX"; case SHT_ARM_PREEMPTMAP: return "ARM_PREEMPTMAP"; case SHT_ARM_ATTRIBUTES: return "ARM_ATTRIBUTES"; case SHT_ARM_DEBUGOVERLAY: return "ARM_DEBUGOVERLAY"; case SHT_ARM_OVERLAYSECTION: return "ARM_OVERLAYSECTION"; } break; case EM_X86_64: switch (stype) { case SHT_X86_64_UNWIND: return "X86_64_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"; + case SHT_MIPS_ABIFLAGS: return "MIPS_ABIFLAGS"; 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_SUNW_ASLR: return "SUNW_ASLR"; 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_TLSDESC_PLT: return "DT_TLSDESC_PLT"; case DT_TLSDESC_GOT: return "DT_TLSDESC_GOT"; 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"; case STB_GNU_UNIQUE: return "UNIQUE"; 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 mach, unsigned int os, 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) { if ((os == ELFOSABI_GNU || os == ELFOSABI_FREEBSD) && stype == STT_GNU_IFUNC) return "IFUNC"; snprintf(s_stype, sizeof(s_stype), "OS+%#x", stype - STT_LOOS); } else if (stype >= STT_LOPROC && stype <= STT_HIPROC) { if (mach == EM_SPARCV9 && stype == STT_SPARC_REGISTER) return "REGISTER"; 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}, {"COMPRESSED", 'C', SHF_COMPRESSED}, {NULL, 0, 0} }; 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); else if (strcmp(name, "Xen") == 0 && et != ET_CORE) return note_type_xen(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 const char * note_type_xen(unsigned int nt) { switch (nt) { case 0: return "XEN_ELFNOTE_INFO"; case 1: return "XEN_ELFNOTE_ENTRY"; case 2: return "XEN_ELFNOTE_HYPERCALL_PAGE"; case 3: return "XEN_ELFNOTE_VIRT_BASE"; case 4: return "XEN_ELFNOTE_PADDR_OFFSET"; case 5: return "XEN_ELFNOTE_XEN_VERSION"; case 6: return "XEN_ELFNOTE_GUEST_OS"; case 7: return "XEN_ELFNOTE_GUEST_VERSION"; case 8: return "XEN_ELFNOTE_LOADER"; case 9: return "XEN_ELFNOTE_PAE_MODE"; case 10: return "XEN_ELFNOTE_FEATURES"; case 11: return "XEN_ELFNOTE_BSD_SYMTAB"; case 12: return "XEN_ELFNOTE_HV_START_LOW"; case 13: return "XEN_ELFNOTE_L1_MFN_VALID"; case 14: return "XEN_ELFNOTE_SUSPEND_CANCEL"; case 15: return "XEN_ELFNOTE_INIT_P2M"; case 16: return "XEN_ELFNOTE_MOD_START_PFN"; case 17: return "XEN_ELFNOTE_SUPPORTED_FEATURES"; default: return (note_type_unknown(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: case EM_IAMCU: 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; + size_t phnum, 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); + printf("%-37s%u", " Number of program headers:", re->ehdr.e_phnum); + if (re->ehdr.e_phnum == PN_XNUM) { + /* Extended program header numbering is in use. */ + if (elf_getphnum(re->elf, &phnum)) + printf(" (%zu)", phnum); + } + putchar('\n'); /* 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; int i, j; #define PH_HDR "Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz", \ "MemSiz", "Flg", "Align" #define PH_CT phdr_type(re->ehdr.e_machine, 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, &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].addr >= phdr.p_vaddr && re->sl[j].addr + re->sl[j].sz <= phdr.p_vaddr + 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 } /* * Return number of entries in the given section. We'd prefer ent_count be a * size_t *, but libelf APIs already use int for section indices. */ static int get_ent_count(struct section *s, int *ent_count) { if (s->entsize == 0) { warnx("section %s has entry size 0", s->name); return (0); } else if (s->sz / s->entsize > INT_MAX) { warnx("section %s has invalid section count", s->name); return (0); } *ent_count = (int)(s->sz / s->entsize); return (1); } 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; if (!get_ent_count(s, &jmax)) continue; 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; uint32_t type; uint8_t type2, type3; if (s->link >= re->shnum) return; #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, \ elftc_reloc_type_str(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, \ elftc_reloc_type_str(re->ehdr.e_machine, type), \ (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); } assert(d->d_size == s->sz); if (!get_ent_count(s, &len)) return; for (i = 0; i < len; i++) { if (gelf_getrel(d, i, &r) != &r) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info)); symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info)); if (re->ec == ELFCLASS32) { r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info), ELF64_R_TYPE(r.r_info)); printf("%8.8jx %8.8jx %-19.19s %8.8jx %s\n", REL_CT32); } else { type = ELF64_R_TYPE(r.r_info); if (re->ehdr.e_machine == EM_MIPS) { type2 = (type >> 8) & 0xFF; type3 = (type >> 16) & 0xFF; type = type & 0xFF; } 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); if (re->ehdr.e_machine == EM_MIPS) { if (re->options & RE_WW) { printf("%32s: %s\n", "Type2", elftc_reloc_type_str(EM_MIPS, type2)); printf("%32s: %s\n", "Type3", elftc_reloc_type_str(EM_MIPS, type3)); } else { printf("%24s: %s\n", "Type2", elftc_reloc_type_str(EM_MIPS, type2)); printf("%24s: %s\n", "Type3", elftc_reloc_type_str(EM_MIPS, type3)); } } } } #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; uint32_t type; uint8_t type2, type3; if (s->link >= re->shnum) return; #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, \ elftc_reloc_type_str(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, \ elftc_reloc_type_str(re->ehdr.e_machine, type), \ (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); } assert(d->d_size == s->sz); if (!get_ent_count(s, &len)) return; for (i = 0; i < len; i++) { if (gelf_getrela(d, i, &r) != &r) { warnx("gelf_getrel failed: %s", elf_errmsg(-1)); continue; } symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info)); symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info)); if (re->ec == ELFCLASS32) { r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info), ELF64_R_TYPE(r.r_info)); printf("%8.8jx %8.8jx %-19.19s %8.8jx %s", RELA_CT32); printf(" + %x\n", (uint32_t) r.r_addend); } else { type = ELF64_R_TYPE(r.r_info); if (re->ehdr.e_machine == EM_MIPS) { type2 = (type >> 8) & 0xFF; type3 = (type >> 16) & 0xFF; type = type & 0xFF; } 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); if (re->ehdr.e_machine == EM_MIPS) { if (re->options & RE_WW) { printf("%32s: %s\n", "Type2", elftc_reloc_type_str(EM_MIPS, type2)); printf("%32s: %s\n", "Type3", elftc_reloc_type_str(EM_MIPS, type3)); } else { printf("%24s: %s\n", "Type2", elftc_reloc_type_str(EM_MIPS, type2)); printf("%24s: %s\n", "Type3", elftc_reloc_type_str(EM_MIPS, type3)); } } } } #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; uint32_t stab; int elferr, j, len; uint16_t vs; s = &re->sl[i]; if (s->link >= re->shnum) return; 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; if (!get_ent_count(s, &len)) return; printf("Symbol table (%s)", s->name); printf(" contains %d entries:\n", len); printf("%7s%9s%14s%5s%8s%6s%9s%5s\n", "Num:", "Value", "Size", "Type", "Bind", "Vis", "Ndx", "Name"); for (j = 0; j < len; 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", (uintmax_t) sym.st_size); printf(" %-7s", st_type(re->ehdr.e_machine, re->ehdr.e_ident[EI_OSABI], 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) { vs = re->vs[j] & VERSYM_VERSION; if (vs >= re->ver_sz || re->ver[vs].name == NULL) { warnx("invalid versym version index %u", vs); break; } if (re->vs[j] & VERSYM_HIDDEN || re->ver[vs].type == 0) printf("@%s (%d)", re->ver[vs].name, vs); else printf("@@%s (%d)", re->ver[vs].name, vs); } 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, len; /* * 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; if (!get_ent_count(s, &len)) return; for (i = 0; i < len; 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; if (s->link >= re->shnum) return; ds = &re->sl[s->link]; if (!get_ent_count(ds, &dynsymcount)) return; if (symndx >= (uint32_t)dynsymcount) { warnx("Malformed .gnu.hash section (symndx out of range)"); return; } 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 filesize, 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, &filesize)) == 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) { if (phdr.p_offset >= filesize || phdr.p_filesz > filesize - phdr.p_offset) { warnx("invalid PHDR offset"); continue; } 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 (s->link >= re->shnum) 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 (s->link >= re->shnum) 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; uint16_t vs; 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); } vs = re->vs[i] & VERSYM_VERSION; if (vs >= re->ver_sz || re->ver[vs].name == NULL) { warnx("invalid versym version index %u", re->vs[i]); break; } if (re->vs[i] & VERSYM_HIDDEN) printf(" %3xh %-12s ", vs, re->ver[re->vs[i] & VERSYM_VERSION].name); else printf(" %3x %-12s ", vs, 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, len; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type != SHT_GNU_LIBLIST) continue; if (s->link >= re->shnum) 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; if (!get_ent_count(s, &len)) continue; printf("\nLibrary list section '%s' ", s->name); printf("contains %d entries:\n", len); 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 void dump_section_groups(struct readelf *re) { struct section *s; const char *symname; Elf_Data *d; uint32_t *w; int i, j, elferr; size_t n; for (i = 0; (size_t) i < re->shnum; i++) { s = &re->sl[i]; if (s->type != SHT_GROUP) continue; if (s->link >= re->shnum) 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; w = d->d_buf; /* We only support COMDAT section. */ if ((*w++ & GRP_COMDAT) == 0) return; if (s->entsize == 0) s->entsize = 4; symname = get_symbol_name(re, s->link, s->info); n = s->sz / s->entsize; if (n-- < 1) return; printf("\nCOMDAT group section [%5d] `%s' [%s] contains %ju" " sections:\n", i, s->name, symname, (uintmax_t)n); printf(" %-10.10s %s\n", "[Index]", "Name"); for (j = 0; (size_t) j < n; j++, w++) { if (*w >= re->shnum) { warnx("invalid section index: %u", *w); continue; } printf(" [%5u] %s\n", *w, re->sl[*w].name); } } } static uint8_t * dump_unknown_tag(uint64_t tag, uint8_t *p, uint8_t *pe) { 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, pe); printf("%ju\n", (uintmax_t) val); } return (p); } static uint8_t * dump_compatibility_tag(uint8_t *p, uint8_t *pe) { uint64_t val; val = _decode_uleb128(&p, pe); printf("flag = %ju, vendor = %s\n", (uintmax_t) 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, pe); 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, pe); 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, pe); 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, pe); break; case 64: /* Tag_nodefaults */ /* ignored, written as 0. */ (void) _decode_uleb128(&p, pe); printf("True\n"); break; case 65: /* Tag_also_compatible_with */ val = _decode_uleb128(&p, pe); /* Must be Tag_CPU_arch */ if (val != 6) { printf("unknown\n"); break; } val = _decode_uleb128(&p, pe); 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, pe); switch (tag) { case Tag_GNU_MIPS_ABI_FP: val = _decode_uleb128(&p, pe); printf(" Tag_GNU_MIPS_ABI_FP: %s\n", mips_abi_fp(val)); break; case 32: /* Tag_compatibility */ p = dump_compatibility_tag(p, pe); break; default: p = dump_unknown_tag(tag, p, pe); 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, pe); switch (tag) { case Tag_GNU_Power_ABI_FP: val = _decode_uleb128(&p, pe); printf(" Tag_GNU_Power_ABI_FP: %s\n", ppc_abi_fp(val)); break; case Tag_GNU_Power_ABI_Vector: val = _decode_uleb128(&p, pe); printf(" Tag_GNU_Power_ABI_Vector: %s\n", ppc_abi_vector(val)); break; case 32: /* Tag_compatibility */ p = dump_compatibility_tag(p, pe); break; default: p = dump_unknown_tag(tag, p, pe); break; } } } static void dump_attributes(struct readelf *re) { struct section *s; Elf_Data *d; uint8_t *p, *pe, *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; pe = p + d->d_size; 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"); return; } seclen = re->dw_decode(&p, 4); if (seclen > len) { warnx("invalid attribute section length"); return; } len -= seclen; nlen = strlen((char *) p) + 1; if (nlen + 4 > seclen) { warnx("invalid attribute section name"); return; } 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"); return; } seclen -= sublen; printf("%s", top_tag(tag)); if (tag == 2 || tag == 3) { putchar(':'); for (;;) { val = _decode_uleb128(&p, pe); 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; + int i; - 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. + * Dump .reginfo if present (although it will be ignored by an OS if a + * .MIPS.options section is present, according to SGI mips64 spec). */ - 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); - } + 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, len; (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; if (!get_ent_count(s, &len)) return; printf("\nSection '%s' contains %d entries:\n", s->name, len); 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); 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; } } 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; pe = (uint8_t *) d->d_buf + endoff; 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, pe); mtime = _decode_uleb128(&p, pe); fsize = _decode_uleb128(&p, pe); 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++; printf("\n"); printf(" Line Number Statements:\n"); RESET_REGISTERS; while (p < pe) { if (*p == 0) { /* * Extended Opcodes. */ p++; opsize = _decode_uleb128(&p, pe); 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, pe); mtime = _decode_uleb128(&p, pe); fsize = _decode_uleb128(&p, pe); 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, pe) * 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, pe); 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, pe); printf(" Set File to %ju\n", (uintmax_t) file); break; case DW_LNS_set_column: column = _decode_uleb128(&p, pe); 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, pe); printf(" Set isa to %ju\n", (uintmax_t) 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", (uintmax_t) (ranges[j].dwr_addr1 + base0), (uintmax_t) (ranges[j].dwr_addr2 + base0)); else printf("%016jx %016jx\n", (uintmax_t) (ranges[j].dwr_addr1 + base0), (uintmax_t) (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; + int i, j, ret, has_content; - 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, &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"); - + has_content = 0; TAILQ_FOREACH(la, &lalist, la_next) { - if (dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de) != + if ((ret = dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de)) != DW_DLV_OK) { - warnx("dwarf_loclist_n failed: %s", dwarf_errmsg(de)); + if (ret != DW_DLV_NO_ENTRY) + warnx("dwarf_loclist_n failed: %s", + dwarf_errmsg(de)); continue; } + if (!has_content) { + has_content = 1; + printf("\nContents of section .debug_loc:\n"); + printf(" Offset Begin End Expression\n"); + } 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 ", (uintmax_t) 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); } + + if (!has_content) + printf("\nSection '.debug_loc' has no debugging data.\n"); } /* * 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) { if (sym.st_shndx < re->shnum && re->sl[sym.st_shndx].name != NULL) return (re->sl[sym.st_shndx].name); return (""); } if (s->link >= re->shnum || (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 && (d = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } (void) elf_errno(); 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 && (d = elf_rawdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); continue; } (void) elf_errno(); 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"; + name = ""; } if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) { - if ((elferr = elf_errno()) != 0) + if ((elferr = elf_errno()) != 0) { warnx("elf_ndxscn failed: %s", elf_errmsg(elferr)); - continue; + continue; + } } if (ndx >= re->shnum) { warnx("section index of '%s' out of range", name); continue; } if (sh.sh_link >= re->shnum) warnx("section link %llu of '%s' out of range", (unsigned long long)sh.sh_link, name); 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_G) dump_section_groups(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; + struct loc_at *la, *_la; Dwarf_Error de; + int error; 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); + + TAILQ_FOREACH_SAFE(la, &lalist, la_next, _la) { + TAILQ_REMOVE(&lalist, la, la_next); + free(la); + } 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; /* FALLTHROUGH */ case 4: ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24; /* FALLTHROUGH */ case 2: ret |= ((uint64_t) src[1]) << 8; /* FALLTHROUGH */ 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; /* FALLTHROUGH */ case 4: ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24; /* FALLTHROUGH */ case 2: ret |= ((uint64_t) src[1]) << 8; /* FALLTHROUGH */ 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, uint8_t *dpe) { int64_t ret = 0; uint8_t b = 0; int shift = 0; uint8_t *src = *dp; do { if (src >= dpe) break; 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, uint8_t *dpe) { uint64_t ret = 0; uint8_t b; int shift = 0; uint8_t *src = *dp; do { if (src >= dpe) break; 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 Print the contents of the section groups.\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\ -w[afilmoprsFLR] | --debug-dump={abbrev,aranges,decodedline,frames,\n\ frames-interp,info,loc,macro,pubnames,\n\ ranges,Ranges,rawline,str}\n\ Display DWARF information.\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(int status) { fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(status); } 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(EXIT_SUCCESS); break; case 'A': re->options |= RE_AA; break; case 'a': re->options |= RE_AA | RE_D | RE_G | 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(EXIT_SUCCESS); 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(EXIT_FAILURE); 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++) { re->filename = argv[i]; dump_object(re); } exit(EXIT_SUCCESS); } Index: vendor/elftoolchain/dist/strings/strings.c =================================================================== --- vendor/elftoolchain/dist/strings/strings.c (revision 317072) +++ vendor/elftoolchain/dist/strings/strings.c (revision 317073) @@ -1,457 +1,452 @@ /*- * Copyright (c) 2007 S.Sam Arun Raj * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" -ELFTC_VCSID("$Id: strings.c 3446 2016-05-03 01:31:17Z emaste $"); +ELFTC_VCSID("$Id: strings.c 3498 2016-10-26 19:25:13Z emaste $"); -enum return_code { - RETURN_OK, - RETURN_NOINPUT, - RETURN_SOFTWARE -}; - enum radix_style { RADIX_DECIMAL, RADIX_HEX, RADIX_OCTAL }; enum encoding_style { ENCODING_7BIT, ENCODING_8BIT, ENCODING_16BIT_BIG, ENCODING_16BIT_LITTLE, ENCODING_32BIT_BIG, ENCODING_32BIT_LITTLE }; #define PRINTABLE(c) \ ((c) >= 0 && (c) <= 255 && \ ((c) == '\t' || isprint((c)) || \ (encoding == ENCODING_8BIT && (c) > 127))) static int encoding_size, entire_file, show_filename, show_loc; static enum encoding_style encoding; static enum radix_style radix; static intmax_t min_len; static struct option strings_longopts[] = { { "all", no_argument, NULL, 'a'}, { "bytes", required_argument, NULL, 'n'}, { "encoding", required_argument, NULL, 'e'}, { "help", no_argument, NULL, 'h'}, { "print-file-name", no_argument, NULL, 'f'}, { "radix", required_argument, NULL, 't'}, { "version", no_argument, NULL, 'v'}, { NULL, 0, NULL, 0 } }; long getcharacter(void); int handle_file(const char *); int handle_elf(const char *, int); int handle_binary(const char *, int); int find_strings(const char *, off_t, off_t); void show_version(void); void usage(void); /* * strings(1) extracts text(contiguous printable characters) * from elf and binary files. */ int main(int argc, char **argv) { int ch, rc; - rc = RETURN_OK; + rc = 0; min_len = 0; encoding_size = 1; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "ELF library initialization failed: %s", elf_errmsg(-1)); while ((ch = getopt_long(argc, argv, "1234567890ae:fhn:ot:Vv", strings_longopts, NULL)) != -1) switch((char)ch) { case 'a': entire_file = 1; break; case 'e': if (*optarg == 's') { encoding = ENCODING_7BIT; } else if (*optarg == 'S') { encoding = ENCODING_8BIT; } else if (*optarg == 'b') { encoding = ENCODING_16BIT_BIG; encoding_size = 2; } else if (*optarg == 'B') { encoding = ENCODING_32BIT_BIG; encoding_size = 4; } else if (*optarg == 'l') { encoding = ENCODING_16BIT_LITTLE; encoding_size = 2; } else if (*optarg == 'L') { encoding = ENCODING_32BIT_LITTLE; encoding_size = 4; } else usage(); /* NOTREACHED */ break; case 'f': show_filename = 1; break; case 'n': min_len = strtoimax(optarg, (char**)NULL, 10); if (min_len <= 0) errx(EX_USAGE, "option -n should specify a " "positive decimal integer."); break; case 'o': show_loc = 1; radix = RADIX_OCTAL; break; case 't': show_loc = 1; if (*optarg == 'd') radix = RADIX_DECIMAL; else if (*optarg == 'o') radix = RADIX_OCTAL; else if (*optarg == 'x') radix = RADIX_HEX; else usage(); /* NOTREACHED */ break; case 'v': case 'V': show_version(); /* NOTREACHED */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': min_len *= 10; min_len += ch - '0'; break; case 'h': case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if (!min_len) min_len = 4; if (!*argv) rc = handle_file("{standard input}"); else while (*argv) { - rc = handle_file(*argv); + if (handle_file(*argv) != 0) + rc = 1; argv++; } return (rc); } int handle_file(const char *name) { int fd, rt; if (name == NULL) - return (RETURN_NOINPUT); + return (1); if (strcmp("{standard input}", name) != 0) { if (freopen(name, "rb", stdin) == NULL) { warnx("'%s': %s", name, strerror(errno)); - return (RETURN_NOINPUT); + return (1); } } else { return (find_strings(name, (off_t)0, (off_t)0)); } fd = fileno(stdin); if (fd < 0) - return (RETURN_NOINPUT); + return (1); rt = handle_elf(name, fd); return (rt); } /* * Files not understood by handle_elf, will be passed off here and will * treated as a binary file. This would include text file, core dumps ... */ int handle_binary(const char *name, int fd) { struct stat buf; memset(&buf, 0, sizeof(struct stat)); (void) lseek(fd, (off_t)0, SEEK_SET); if (!fstat(fd, &buf)) return (find_strings(name, (off_t)0, buf.st_size)); - return (RETURN_SOFTWARE); + return (1); } /* * Will analyse a file to see if it ELF, other files including ar(1), * core dumps are passed off and treated as flat binary files. Unlike * GNU size in FreeBSD this routine will not treat ELF object from * different archs as flat binary files(has to overridden using -a). */ int handle_elf(const char *name, int fd) { GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf *elf; Elf_Scn *scn; int rc; - rc = RETURN_OK; + rc = 0; /* If entire file is chosen, treat it as a binary file */ if (entire_file) return (handle_binary(name, fd)); (void) lseek(fd, (off_t)0, SEEK_SET); elf = elf_begin(fd, ELF_C_READ, NULL); if (elf_kind(elf) != ELF_K_ELF) { (void) elf_end(elf); return (handle_binary(name, fd)); } if (gelf_getehdr(elf, &elfhdr) == NULL) { (void) elf_end(elf); warnx("%s: ELF file could not be processed", name); - return (RETURN_SOFTWARE); + return (1); } if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { (void) elf_end(elf); return (handle_binary(name, fd)); } else { scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) == NULL) continue; if (shdr.sh_type != SHT_NOBITS && (shdr.sh_flags & SHF_ALLOC) != 0) { rc = find_strings(name, shdr.sh_offset, shdr.sh_size); } } } (void) elf_end(elf); return (rc); } /* * Retrieves a character from input stream based on the encoding * type requested. */ long getcharacter(void) { long rt; int i; char buf[4], c; rt = EOF; for(i = 0; i < encoding_size; i++) { c = getc(stdin); if (feof(stdin)) return (EOF); buf[i] = c; } switch(encoding) { case ENCODING_7BIT: case ENCODING_8BIT: rt = buf[0]; break; case ENCODING_16BIT_BIG: rt = (buf[0] << 8) | buf[1]; break; case ENCODING_16BIT_LITTLE: rt = buf[0] | (buf[1] << 8); break; case ENCODING_32BIT_BIG: rt = ((long) buf[0] << 24) | ((long) buf[1] << 16) | ((long) buf[2] << 8) | buf[3]; break; case ENCODING_32BIT_LITTLE: rt = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) | ((long) buf[3] << 24); break; } return (rt); } /* * Input stream stdin is read until the end of file is reached or until * the section size is reached in case of ELF files. Contiguous * characters of >= min_size(default 4) will be displayed. */ int find_strings(const char *name, off_t offset, off_t size) { off_t cur_off, start_off; char *obuf; long c; int i; if ((obuf = (char*)calloc(1, min_len + 1)) == NULL) { (void) fprintf(stderr, "Unable to allocate memory: %s\n", strerror(errno)); - return (RETURN_SOFTWARE); + return (1); } (void) fseeko(stdin, offset, SEEK_SET); cur_off = offset; start_off = 0; while(1) { if ((offset + size) && (cur_off >= offset + size)) break; start_off = cur_off; memset(obuf, 0, min_len+1); for(i = 0; i < min_len; i++) { c = getcharacter(); if (c == EOF && feof(stdin)) goto _exit1; if (PRINTABLE(c)) { obuf[i] = c; obuf[i+1] = 0; cur_off += encoding_size; } else { if (encoding == ENCODING_8BIT && (uint8_t)c > 127) { obuf[i] = c; obuf[i+1] = 0; cur_off += encoding_size; continue; } cur_off += encoding_size; break; } } if (i >= min_len && ((cur_off <= offset + size) || !(offset + size))) { if (show_filename) printf ("%s: ", name); if (show_loc) { switch(radix) { case RADIX_DECIMAL: (void) printf("%7ju ", (uintmax_t)start_off); break; case RADIX_HEX: (void) printf("%7jx ", (uintmax_t)start_off); break; case RADIX_OCTAL: (void) printf("%7jo ", (uintmax_t)start_off); break; } } printf("%s", obuf); while(1) { if ((offset + size) && (cur_off >= offset + size)) break; c = getcharacter(); cur_off += encoding_size; if (encoding == ENCODING_8BIT && (uint8_t)c > 127) { putchar(c); continue; } if (!PRINTABLE(c) || c == EOF) break; putchar(c); } putchar('\n'); } } _exit1: free(obuf); - return (RETURN_OK); + return (0); } #define USAGE_MESSAGE "\ Usage: %s [options] [file...]\n\ Print contiguous sequences of printable characters.\n\n\ Options:\n\ -a | --all Scan the entire file for strings.\n\ -e ENC | --encoding=ENC Select the character encoding to use.\n\ -f | --print-file-name Print the file name before each string.\n\ -h | --help Print a help message and exit.\n\ -n N | --bytes=N | -N Print sequences with 'N' or more characters.\n\ -o Print offsets in octal.\n\ -t R | --radix=R Print offsets using the radix named by 'R'.\n\ -v | --version Print a version identifier and exit.\n" void usage(void) { (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } void show_version(void) { (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } Index: vendor/elftoolchain/dist/test/ar/plugin/os.FreeBSD.mk =================================================================== --- vendor/elftoolchain/dist/test/ar/plugin/os.FreeBSD.mk (nonexistent) +++ vendor/elftoolchain/dist/test/ar/plugin/os.FreeBSD.mk (revision 317073) @@ -0,0 +1,2 @@ +DPADD+= ${LIBBZ2} +LDADD+= -lbz2 Property changes on: vendor/elftoolchain/dist/test/ar/plugin/os.FreeBSD.mk ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/elftoolchain/dist/test/cxxfilt/tet_scen =================================================================== --- vendor/elftoolchain/dist/test/cxxfilt/tet_scen (revision 317072) +++ vendor/elftoolchain/dist/test/cxxfilt/tet_scen (revision 317073) @@ -1,11 +1,17 @@ # $Id$ all "Starting Test Suite" ^misc + ^regression "Complete Test Suite" misc - "Starting noarg Test" + "Starting misc Test" /ts/misc/tc - "Complete noarg Test" + "Complete misc Test" + +regression + "Starting regression Test" + /ts/regression/tc + "Complete regression Test" Index: vendor/elftoolchain/dist/test/cxxfilt/ts/Makefile =================================================================== --- vendor/elftoolchain/dist/test/cxxfilt/ts/Makefile (revision 317072) +++ vendor/elftoolchain/dist/test/cxxfilt/ts/Makefile (revision 317073) @@ -1,7 +1,8 @@ # $Id$ TOP= ../../.. SUBDIR+= misc +SUBDIR+= regression -.include "${TOP}/mk/elftoolchain.subdir.mk" \ No newline at end of file +.include "${TOP}/mk/elftoolchain.subdir.mk" Index: vendor/elftoolchain/dist/test/cxxfilt/ts/regression/Makefile =================================================================== --- vendor/elftoolchain/dist/test/cxxfilt/ts/regression/Makefile (nonexistent) +++ vendor/elftoolchain/dist/test/cxxfilt/ts/regression/Makefile (revision 317073) @@ -0,0 +1,5 @@ +# $Id$ + +TOP= ../../../.. + +.include "../common/ts.mk" Property changes on: vendor/elftoolchain/dist/test/cxxfilt/ts/regression/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/elftoolchain/dist/test/cxxfilt/ts/regression/tclist =================================================================== --- vendor/elftoolchain/dist/test/cxxfilt/ts/regression/tclist (nonexistent) +++ vendor/elftoolchain/dist/test/cxxfilt/ts/regression/tclist (revision 317073) @@ -0,0 +1,34 @@ +# ticket 481, TLS wrappers +"_ZTWL20PrettyStackTraceHead", "TLS wrapper function for PrettyStackTraceHead" + +# ticket 488, trailing E +"_ZN1fILi4EEE", "f<4>" + +# ticket 489, handle Dv (__vector) +"_Z22__gen_ocl_write_imagef11ocl_image2dDv2_iDv4_f", "__gen_ocl_write_imagef(ocl_image2d, int __vector(2), float __vector(4))" +"_Z23__gen_ocl_write_imageui16ocl_image2darrayDv3_iDv4_j", "__gen_ocl_write_imageui(ocl_image2darray, int __vector(3), unsigned int __vector(4))" +"_Z1fDv2_i", "f(int __vector(2))" + +# ticket 491, omit "void" +"_Z1fv", "f()" +"_Z1fPv", "f(void*)" +"_Z1fiv", "f(int, void)" +"_Z1fvi", "f(void, int)" + +# ticket 508, demangler failure +"_ZN8TaskPool11AddTaskImplEONSt3__18functionIFvvEEE", "TaskPool::AddTaskImpl(std::__1::function&&)" + +# ticket 530, assertion failure +"_ZNSp16invalidOargumentC1ERKSs", "invalidOargument::invalidOargument(std::basic_string, std::allocator > const&)" + +# ticket 531, assertion failure +"____new_strtold_internal", "____new_strtold_internal" + +# ticket 537, demangler fails on a symbol from GNU gold +"_ZN4gold15relocate_relocsILi64ELb1ENS_22Default_classify_relocILi4ELi64ELb1EEEEEvPKNS_13Relocate_infoIXT_EXT0_EEEPKhmPNS_14Output_sectionEN6elfcpp9Elf_typesIXT_EE7Elf_OffEPhNSD_8Elf_AddrEmSF_m", "void gold::relocate_relocs<64, true, gold::Default_classify_reloc<4, 64, true> >(gold::Relocate_info<64, true> const*, unsigned char const*, unsigned long, gold::Output_section*, elfcpp::Elf_types<64>::Elf_Off, unsigned char*, elfcpp::Elf_types<64>::Elf_Addr, unsigned long, unsigned char*, unsigned long)" + +# ticket 538, demangler uses incorrect back-ref +"_ZN1f1gEP1hNS0_1iE", "f::g(h*, h::i)" + +# ticket 539, demangler does not demangle lambdas +"_ZZN9libunwind17LocalAddressSpace18findUnwindSectionsEjRNS_18UnwindInfoSectionsEENUlP12dl_phdr_infojPvE_8__invokeES4_jS5_", "libunwind::LocalAddressSpace::findUnwindSections(unsigned int, libunwind::UnwindInfoSections&)::{lambda(dl_phdr_info*, unsigned int, void*)#1}::__invoke(dl_phdr_info*, unsigned int, void*)"