Index: stable/12/contrib/elftoolchain/elfcopy/sections.c =================================================================== --- stable/12/contrib/elftoolchain/elfcopy/sections.c (revision 367461) +++ stable/12/contrib/elftoolchain/elfcopy/sections.c (revision 367462) @@ -1,1708 +1,1753 @@ /*- * Copyright (c) 2007-2011,2014 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "elfcopy.h" ELFTC_VCSID("$Id: sections.c 3758 2019-06-28 01:16:50Z emaste $"); static void add_gnu_debuglink(struct elfcopy *ecp); static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); static void check_section_rename(struct elfcopy *ecp, struct section *s); static void filter_reloc(struct elfcopy *ecp, struct section *s); static int get_section_flags(struct elfcopy *ecp, const char *name); static void insert_sections(struct elfcopy *ecp); static int is_append_section(struct elfcopy *ecp, const char *name); static int is_compress_section(struct elfcopy *ecp, const char *name); static int is_debug_section(const char *name); static int is_dwo_section(const char *name); static int is_modify_section(struct elfcopy *ecp, const char *name); static int is_print_section(struct elfcopy *ecp, const char *name); static void modify_section(struct elfcopy *ecp, struct section *s); static void pad_section(struct elfcopy *ecp, struct section *s); static void print_data(const char *d, size_t sz); static void print_section(struct section *s); static void *read_section(struct section *s, size_t *size); static void set_shstrtab(struct elfcopy *ecp); static void update_reloc(struct elfcopy *ecp, struct section *s); static void update_section_group(struct elfcopy *ecp, struct section *s); int is_remove_section(struct elfcopy *ecp, const char *name) { /* Always keep section name table */ if (strcmp(name, ".shstrtab") == 0) return 0; if (strcmp(name, ".symtab") == 0 || strcmp(name, ".strtab") == 0) { if (ecp->strip == STRIP_ALL && lookup_symop_list( ecp, NULL, SYMOP_KEEP) == NULL) return (1); else return (0); } if (ecp->strip == STRIP_DWO && is_dwo_section(name)) return (1); if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name)) return (1); if (is_debug_section(name)) { if (ecp->strip == STRIP_ALL || ecp->strip == STRIP_DEBUG || ecp->strip == STRIP_UNNEEDED || (ecp->flags & DISCARD_LOCAL)) return (1); if (ecp->strip == STRIP_NONDEBUG) return (0); } if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove) return (1); if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy)) return (1); } return (0); } /* * Relocation section needs to be removed if the section it applies to * will be removed. */ int is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info) { const char *name; GElf_Shdr ish; Elf_Scn *is; size_t indx; int elferr; if (elf_getshstrndx(ecp->ein, &indx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", elf_errmsg(-1)); is = elf_getscn(ecp->ein, sh_info); if (is != NULL) { if (gelf_getshdr(is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (is_remove_section(ecp, name)) return (1); else return (0); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); /* Remove reloc section if we can't find the target section. */ return (1); } static int is_append_section(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->append != 0 && sac->string != NULL) return (1); return (0); } static int is_compress_section(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->compress != 0) return (1); return (0); } static void check_section_rename(struct elfcopy *ecp, struct section *s) { struct sec_action *sac; char *prefix; size_t namelen; if (s->pseudo) return; sac = lookup_sec_act(ecp, s->name, 0); if (sac != NULL && sac->rename) s->name = sac->newname; if (!strcmp(s->name, ".symtab") || !strcmp(s->name, ".strtab") || !strcmp(s->name, ".shstrtab")) return; prefix = NULL; if (s->loadable && ecp->prefix_alloc != NULL) prefix = ecp->prefix_alloc; else if (ecp->prefix_sec != NULL) prefix = ecp->prefix_sec; if (prefix != NULL) { namelen = strlen(s->name) + strlen(prefix) + 1; if ((s->newname = malloc(namelen)) == NULL) err(EXIT_FAILURE, "malloc failed"); snprintf(s->newname, namelen, "%s%s", prefix, s->name); s->name = s->newname; } } static int get_section_flags(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->flags) return sac->flags; return (0); } /* * Determine whether the section are debugging section. * According to libbfd, debugging sections are recognized * only by name. */ static int is_debug_section(const char *name) { const char *dbg_sec[] = { ".apple_", ".debug", ".gnu.linkonce.wi.", ".line", ".stab", NULL }; const char **p; for(p = dbg_sec; *p; p++) { if (strncmp(name, *p, strlen(*p)) == 0) return (1); } return (0); } static int is_dwo_section(const char *name) { size_t len; if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0) return (1); return (0); } static int is_print_section(struct elfcopy *ecp, const char *name) { struct sec_action *sac; sac = lookup_sec_act(ecp, name, 0); if (sac != NULL && sac->print != 0) return (1); return (0); } static int is_modify_section(struct elfcopy *ecp, const char *name) { if (is_append_section(ecp, name) || is_compress_section(ecp, name)) return (1); return (0); } struct sec_action* lookup_sec_act(struct elfcopy *ecp, const char *name, int add) { struct sec_action *sac; if (name == NULL) return NULL; STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { if (strcmp(name, sac->name) == 0) return sac; } if (add == 0) return NULL; if ((sac = malloc(sizeof(*sac))) == NULL) errx(EXIT_FAILURE, "not enough memory"); memset(sac, 0, sizeof(*sac)); sac->name = name; STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list); return (sac); } void free_sec_act(struct elfcopy *ecp) { struct sec_action *sac, *sac_temp; STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) { STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list); free(sac); } } void insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail) { struct section *s; if (tail || TAILQ_EMPTY(&ecp->v_sec) || TAILQ_LAST(&ecp->v_sec, sectionlist)->off <= sec->off) { TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list); } else { TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (sec->off < s->off) { TAILQ_INSERT_BEFORE(s, sec, sec_list); break; } } } if (sec->pseudo == 0) ecp->nos++; } /* * First step of section creation: create scn and internal section * structure, discard sections to be removed. */ void create_scn(struct elfcopy *ecp) { struct section *s; const char *name; Elf_Scn *is; GElf_Shdr ish; size_t indx; uint64_t oldndx, newndx; int elferr, sec_flags, reorder; bool sections_added; /* * Insert a pseudo section that contains the ELF header * and program header. Used as reference for section offset * or load address adjustment. */ if ((s = calloc(1, sizeof(*s))) == NULL) err(EXIT_FAILURE, "calloc failed"); s->off = 0; s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) + gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT); s->align = 1; s->pseudo = 1; s->loadable = add_to_inseg_list(ecp, s); insert_to_sec_list(ecp, s, 0); /* Create internal .shstrtab section. */ init_shstrtab(ecp); if (elf_getshstrndx(ecp->ein, &indx) == 0) errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", elf_errmsg(-1)); sections_added = false; reorder = 0; is = NULL; while ((is = elf_nextscn(ecp->ein, is)) != NULL) { if (gelf_getshdr(is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); /* Skip sections to be removed. */ if (is_remove_section(ecp, name)) continue; /* * Relocation section need to be remove if the section * it applies will be removed. */ if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) if (ish.sh_info != 0 && is_remove_reloc_sec(ecp, ish.sh_info)) continue; /* * Section groups should be removed if symbol table will * be removed. (section group's signature stored in symbol * table) */ if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL) continue; /* Get section flags set by user. */ sec_flags = get_section_flags(ecp, name); /* Create internal section object. */ if (strcmp(name, ".shstrtab") != 0) { if ((s = calloc(1, sizeof(*s))) == NULL) err(EXIT_FAILURE, "calloc failed"); s->name = name; s->is = is; s->off = ish.sh_offset; s->sz = ish.sh_size; s->align = ish.sh_addralign; s->type = ish.sh_type; s->flags = ish.sh_flags; s->vma = ish.sh_addr; /* * Search program headers to determine whether section * is loadable, but if user explicitly set section flags * while neither "load" nor "alloc" is set, we make the * section unloadable. * * Sections in relocatable object is loadable if * section flag SHF_ALLOC is set. */ if (sec_flags && (sec_flags & (SF_LOAD | SF_ALLOC)) == 0) s->loadable = 0; else { s->loadable = add_to_inseg_list(ecp, s); if ((ecp->flags & RELOCATABLE) && (ish.sh_flags & SHF_ALLOC)) s->loadable = 1; } } else { /* Assuming .shstrtab is "unloadable". */ s = ecp->shstrtab; s->off = ish.sh_offset; } oldndx = newndx = SHN_UNDEF; if (strcmp(name, ".symtab") != 0 && strcmp(name, ".strtab") != 0) { /* Add new sections before .shstrtab if we have one. */ if (!strcmp(name, ".shstrtab")) { /* * Add sections specified by --add-section and * gnu debuglink. we want these sections have * smaller index than .shstrtab section. */ sections_added = true; if (ecp->debuglink != NULL) add_gnu_debuglink(ecp); if (ecp->flags & SEC_ADD) insert_sections(ecp); } if ((s->os = elf_newscn(ecp->eout)) == NULL) errx(EXIT_FAILURE, "elf_newscn failed: %s", elf_errmsg(-1)); if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF) errx(EXIT_FAILURE, "elf_ndxscn failed: %s", elf_errmsg(-1)); } if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF) errx(EXIT_FAILURE, "elf_ndxscn failed: %s", elf_errmsg(-1)); if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF) ecp->secndx[oldndx] = newndx; /* * If strip action is STRIP_NONDEBUG(only keep debug), * change sections type of loadable sections and section * groups to SHT_NOBITS, and the content of those sections * will be discarded. However, SHT_NOTE sections should * be kept. */ if (ecp->strip == STRIP_NONDEBUG) { if (((ish.sh_flags & SHF_ALLOC) || (ish.sh_flags & SHF_GROUP)) && ish.sh_type != SHT_NOTE) s->type = SHT_NOBITS; } check_section_rename(ecp, s); /* create section header based on input object. */ if (strcmp(name, ".symtab") != 0 && strcmp(name, ".strtab") != 0 && strcmp(name, ".shstrtab") != 0) { copy_shdr(ecp, s, NULL, 0, sec_flags); /* * elfcopy puts .symtab, .strtab and .shstrtab * sections in the end of the output object. * If the input objects have more sections * after any of these 3 sections, the section * table will be reordered. section symbols * should be regenerated for relocations. */ if (reorder) ecp->flags &= ~SYMTAB_INTACT; } else reorder = 1; if (strcmp(name, ".symtab") == 0) { ecp->flags |= SYMTAB_EXIST; ecp->symtab = s; } if (strcmp(name, ".strtab") == 0) ecp->strtab = s; insert_to_sec_list(ecp, s, 0); } if (!sections_added) { if (ecp->debuglink != NULL) add_gnu_debuglink(ecp); if (ecp->flags & SEC_ADD) insert_sections(ecp); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); } struct section * insert_shtab(struct elfcopy *ecp, int tail) { struct section *s, *shtab; GElf_Ehdr ieh; int nsecs; /* * Treat section header table as a "pseudo" section, insert it * into section list, so later it will get sorted and resynced * just as normal sections. */ if ((shtab = calloc(1, sizeof(*shtab))) == NULL) errx(EXIT_FAILURE, "calloc failed"); if (!tail) { /* * "shoff" of input object is used as a hint for section * resync later. */ if (gelf_getehdr(ecp->ein, &ieh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); shtab->off = ieh.e_shoff; } else shtab->off = 0; /* Calculate number of sections in the output object. */ nsecs = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (!s->pseudo) nsecs++; } /* Remember there is always a null section, so we +1 here. */ shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT); if (shtab->sz == 0) errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8); shtab->loadable = 0; shtab->pseudo = 1; insert_to_sec_list(ecp, shtab, tail); return (shtab); } void copy_content(struct elfcopy *ecp) { struct section *s; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { /* Skip pseudo section. */ if (s->pseudo) continue; /* Skip special sections. */ if (strcmp(s->name, ".symtab") == 0 || strcmp(s->name, ".strtab") == 0 || strcmp(s->name, ".shstrtab") == 0) continue; /* * If strip action is STRIP_ALL, relocation info need * to be stripped. Skip filtering otherwisw. */ if (ecp->strip == STRIP_ALL && (s->type == SHT_REL || s->type == SHT_RELA)) filter_reloc(ecp, s); /* * The section indices in the SHT_GROUP section needs * to be updated since we might have stripped some * sections and changed section numbering. */ if (s->type == SHT_GROUP) update_section_group(ecp, s); if (is_modify_section(ecp, s->name)) modify_section(ecp, s); copy_data(s); /* * If symbol table is modified, relocation info might * need update, as symbol index may have changed. */ if ((ecp->flags & SYMTAB_INTACT) == 0 && (ecp->flags & SYMTAB_EXIST) && (s->type == SHT_REL || s->type == SHT_RELA)) update_reloc(ecp, s); if (is_print_section(ecp, s->name)) print_section(s); } } /* * Update section group section. The section indices in the SHT_GROUP * section need update after section numbering changed. */ static void update_section_group(struct elfcopy *ecp, struct section *s) { GElf_Shdr ish; Elf_Data *id; uint32_t *ws, *wd; uint64_t n; size_t ishnum; int i, j; if (!elf_getshnum(ecp->ein, &ishnum)) errx(EXIT_FAILURE, "elf_getshnum failed: %s", elf_errmsg(-1)); if (gelf_getshdr(s->is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); if ((id = elf_getdata(s->is, NULL)) == NULL) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(-1)); if (ish.sh_size == 0) return; if (ish.sh_entsize == 0) ish.sh_entsize = 4; ws = id->d_buf; /* We only support COMDAT section. */ #ifndef GRP_COMDAT #define GRP_COMDAT 0x1 #endif if ((*ws & GRP_COMDAT) == 0) return; if ((s->buf = malloc(ish.sh_size)) == NULL) err(EXIT_FAILURE, "malloc failed"); s->sz = ish.sh_size; wd = s->buf; /* Copy the flag word as-is. */ *wd = *ws; /* Update the section indices. */ n = ish.sh_size / ish.sh_entsize; for(i = 1, j = 1; (uint64_t)i < n; i++) { if (ws[i] != SHN_UNDEF && ws[i] < ishnum && ecp->secndx[ws[i]] != 0) wd[j++] = ecp->secndx[ws[i]]; else s->sz -= 4; } s->nocopy = 1; } /* * Filter relocation entries, only keep those entries whose * symbol is in the keep list. */ static void filter_reloc(struct elfcopy *ecp, struct section *s) { const char *name; GElf_Shdr ish; GElf_Rel rel; GElf_Rela rela; Elf32_Rel *rel32; Elf64_Rel *rel64; Elf32_Rela *rela32; Elf64_Rela *rela64; Elf_Data *id; uint64_t cap, n, nrels, sym; int elferr, i; if (gelf_getshdr(s->is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); /* We don't want to touch relocation info for dynamic symbols. */ if ((ecp->flags & SYMTAB_EXIST) == 0) { /* * No symbol table in output. If sh_link points to a section * that exists in the output object, this relocation section * is for dynamic symbols. Don't touch it. */ if (ish.sh_link != 0 && ecp->secndx[ish.sh_link] != 0) return; } else { /* Symbol table exist, check if index equals. */ if (ish.sh_link != elf_ndxscn(ecp->symtab->is)) return; } #define COPYREL(REL, SZ) do { \ if (nrels == 0) { \ if ((REL##SZ = malloc(cap * \ sizeof(*REL##SZ))) == NULL) \ err(EXIT_FAILURE, "malloc failed"); \ } \ if (nrels >= cap) { \ cap *= 2; \ if ((REL##SZ = realloc(REL##SZ, cap * \ sizeof(*REL##SZ))) == NULL) \ err(EXIT_FAILURE, "realloc failed"); \ } \ REL##SZ[nrels].r_offset = REL.r_offset; \ REL##SZ[nrels].r_info = REL.r_info; \ if (s->type == SHT_RELA) \ rela##SZ[nrels].r_addend = rela.r_addend; \ nrels++; \ } while (0) nrels = 0; cap = 4; /* keep list is usually small. */ rel32 = NULL; rel64 = NULL; rela32 = NULL; rela64 = NULL; if ((id = elf_getdata(s->is, NULL)) == NULL) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(-1)); n = ish.sh_size / ish.sh_entsize; for(i = 0; (uint64_t)i < n; i++) { if (s->type == SHT_REL) { if (gelf_getrel(id, i, &rel) != &rel) errx(EXIT_FAILURE, "gelf_getrel failed: %s", elf_errmsg(-1)); sym = GELF_R_SYM(rel.r_info); } else { if (gelf_getrela(id, i, &rela) != &rela) errx(EXIT_FAILURE, "gelf_getrel failed: %s", elf_errmsg(-1)); sym = GELF_R_SYM(rela.r_info); } /* * If a relocation references a symbol and we are omitting * either that symbol or the entire symbol table we cannot * produce valid output, and so just omit the relocation. * Broken output like this is generally not useful, but some * uses of elfcopy/strip rely on it - for example, GCC's build * process uses it to check for build reproducibility by * stripping objects and comparing them. * * Relocations that do not reference a symbol are retained. */ if (sym != 0) { if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) continue; name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is), sym); if (name == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", elf_errmsg(-1)); if (lookup_symop_list(ecp, name, SYMOP_KEEP) == NULL) continue; } if (ecp->oec == ELFCLASS32) { if (s->type == SHT_REL) COPYREL(rel, 32); else COPYREL(rela, 32); } else { if (s->type == SHT_REL) COPYREL(rel, 64); else COPYREL(rela, 64); } } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); if (ecp->oec == ELFCLASS32) { if (s->type == SHT_REL) s->buf = rel32; else s->buf = rela32; } else { if (s->type == SHT_REL) s->buf = rel64; else s->buf = rela64; } s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL : ELF_T_RELA), nrels, EV_CURRENT); s->nocopy = 1; } static void update_reloc(struct elfcopy *ecp, struct section *s) { GElf_Shdr osh; GElf_Rel rel; GElf_Rela rela; Elf_Data *od; uint64_t n; int i; #define UPDATEREL(REL) do { \ if (gelf_get##REL(od, i, &REL) != &REL) \ errx(EXIT_FAILURE, "gelf_get##REL failed: %s", \ elf_errmsg(-1)); \ REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)], \ GELF_R_TYPE(REL.r_info)); \ if (!gelf_update_##REL(od, i, &REL)) \ errx(EXIT_FAILURE, "gelf_update_##REL failed: %s", \ elf_errmsg(-1)); \ } while(0) if (s->sz == 0) return; if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", elf_errmsg(-1)); /* Only process .symtab reloc info. */ if (osh.sh_link != elf_ndxscn(ecp->symtab->is)) return; if ((od = elf_getdata(s->os, NULL)) == NULL) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(-1)); n = osh.sh_size / osh.sh_entsize; for(i = 0; (uint64_t)i < n; i++) { if (s->type == SHT_REL) UPDATEREL(rel); else UPDATEREL(rela); } } static void pad_section(struct elfcopy *ecp, struct section *s) { GElf_Shdr osh; Elf_Data *od; if (s == NULL || s->pad_sz == 0) return; if ((s->pad = malloc(s->pad_sz)) == NULL) err(EXIT_FAILURE, "malloc failed"); memset(s->pad, ecp->fill, s->pad_sz); /* Create a new Elf_Data to contain the padding bytes. */ if ((od = elf_newdata(s->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); od->d_align = 1; od->d_off = s->sz; od->d_buf = s->pad; od->d_type = ELF_T_BYTE; od->d_size = s->pad_sz; od->d_version = EV_CURRENT; /* Update section header. */ if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); osh.sh_size = s->sz + s->pad_sz; if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "elf_update_shdr failed: %s", elf_errmsg(-1)); } +static int +section_type_alignment(int sht, int class) +{ + switch (sht) + { + case SHT_DYNAMIC: + case SHT_DYNSYM: + case SHT_FINI_ARRAY: + case SHT_GNU_HASH: + case SHT_INIT_ARRAY: + case SHT_PREINIT_ARRAY: + case SHT_REL: + case SHT_RELA: + case SHT_SYMTAB: + return (class == ELFCLASS64 ? 8 : 4); + case SHT_SUNW_move: + return (8); + case SHT_GNU_LIBLIST: + case SHT_GROUP: + case SHT_HASH: + case SHT_NOTE: + case SHT_SUNW_verdef: /* == SHT_GNU_verdef */ + case SHT_SUNW_verneed: /* == SHT_GNU_verneed */ + case SHT_SYMTAB_SHNDX: + return (4); + case SHT_SUNW_syminfo: + case SHT_SUNW_versym: /* == SHT_GNU_versym */ + return (2); + case SHT_NOBITS: + case SHT_PROGBITS: + case SHT_STRTAB: + case SHT_SUNW_dof: + return (1); + } + return (1); +} + void resync_sections(struct elfcopy *ecp) { struct section *s, *ps; GElf_Shdr osh; uint64_t off; int first; + int min_alignment; ps = NULL; first = 1; off = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (first) { off = s->off; first = 0; } /* * Ignore TLS sections with load address 0 and without * content. We don't need to adjust their file offset or * VMA, only the size matters. */ if (s->seg_tls != NULL && s->type == SHT_NOBITS && s->off == 0) continue; /* Align section offset. */ if (s->align == 0) s->align = 1; + min_alignment = section_type_alignment(s->type, ecp->oec); + if (s->align < INT_MAX && (int)s->align < min_alignment) { + warnx("section %s alignment %d increased to %d", + s->name, (int)s->align, min_alignment); + s->align = min_alignment; + } if (off <= s->off) { if (!s->loadable || (ecp->flags & RELOCATABLE)) s->off = roundup(off, s->align); } else { if (s->loadable && (ecp->flags & RELOCATABLE) == 0) warnx("moving loadable section %s, " "is this intentional?", s->name); s->off = roundup(off, s->align); } /* Calculate next section offset. */ off = s->off; if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL)) off += s->sz; if (s->pseudo) { ps = NULL; continue; } /* Count padding bytes added through --pad-to. */ if (s->pad_sz > 0) off += s->pad_sz; /* Update section header accordingly. */ if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); osh.sh_addr = s->vma; + osh.sh_addralign = s->align; osh.sh_offset = s->off; osh.sh_size = s->sz; if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "elf_update_shdr failed: %s", elf_errmsg(-1)); /* Add padding for previous section, if need. */ if (ps != NULL) { if (ps->pad_sz > 0) { /* Apply padding added by --pad-to. */ pad_section(ecp, ps); } else if ((ecp->flags & GAP_FILL) && (ps->off + ps->sz < s->off)) { /* * Fill the gap between sections by padding * the section with lower address. */ ps->pad_sz = s->off - (ps->off + ps->sz); pad_section(ecp, ps); } } ps = s; } /* Pad the last section, if need. */ if (ps != NULL && ps->pad_sz > 0) pad_section(ecp, ps); } static void modify_section(struct elfcopy *ecp, struct section *s) { struct sec_action *sac; size_t srcsz, dstsz, p, len; char *b, *c, *d, *src, *end; int dupe; src = read_section(s, &srcsz); if (src == NULL || srcsz == 0) { /* For empty section, we proceed if we need to append. */ if (!is_append_section(ecp, s->name)) return; } /* Allocate buffer needed for new section data. */ dstsz = srcsz; if (is_append_section(ecp, s->name)) { sac = lookup_sec_act(ecp, s->name, 0); dstsz += strlen(sac->string) + 1; } if ((b = malloc(dstsz)) == NULL) err(EXIT_FAILURE, "malloc failed"); s->buf = b; /* Compress section. */ p = 0; if (is_compress_section(ecp, s->name)) { end = src + srcsz; for(c = src; c < end;) { len = 0; while(c + len < end && c[len] != '\0') len++; if (c + len == end) { /* XXX should we warn here? */ strncpy(&b[p], c, len); p += len; break; } dupe = 0; for (d = b; d < b + p; ) { if (strcmp(d, c) == 0) { dupe = 1; break; } d += strlen(d) + 1; } if (!dupe) { strncpy(&b[p], c, len); b[p + len] = '\0'; p += len + 1; } c += len + 1; } } else { memcpy(b, src, srcsz); p += srcsz; } /* Append section. */ if (is_append_section(ecp, s->name)) { sac = lookup_sec_act(ecp, s->name, 0); len = strlen(sac->string); strncpy(&b[p], sac->string, len); b[p + len] = '\0'; p += len + 1; } s->sz = p; s->nocopy = 1; } static void print_data(const char *d, size_t sz) { const char *c; for (c = d; c < d + sz; c++) { if (*c == '\0') putchar('\n'); else putchar(*c); } } static void print_section(struct section *s) { Elf_Data *id; int elferr; if (s->buf != NULL && s->sz > 0) { print_data(s->buf, s->sz); } else { id = NULL; while ((id = elf_getdata(s->is, id)) != NULL || (id = elf_rawdata(s->is, id)) != NULL) { (void) elf_errno(); print_data(id->d_buf, id->d_size); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); } putchar('\n'); } static void * read_section(struct section *s, size_t *size) { Elf_Data *id; char *b; size_t sz; int elferr; sz = 0; b = NULL; id = NULL; while ((id = elf_getdata(s->is, id)) != NULL || (id = elf_rawdata(s->is, id)) != NULL) { (void) elf_errno(); if (b == NULL) b = malloc(id->d_size); else b = realloc(b, sz + id->d_size); if (b == NULL) err(EXIT_FAILURE, "malloc or realloc failed"); memcpy(&b[sz], id->d_buf, id->d_size); sz += id->d_size; } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", elf_errmsg(elferr)); *size = sz; return (b); } void copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, int sec_flags) { GElf_Shdr ish, osh; if (gelf_getshdr(s->is, &ish) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); if (copy) (void) memcpy(&osh, &ish, sizeof(ish)); else { osh.sh_type = s->type; osh.sh_addr = s->vma; osh.sh_offset = s->off; osh.sh_size = s->sz; osh.sh_link = ish.sh_link; osh.sh_info = ish.sh_info; osh.sh_addralign = s->align; osh.sh_entsize = ish.sh_entsize; if (sec_flags) { osh.sh_flags = 0; if (sec_flags & SF_ALLOC) osh.sh_flags |= SHF_ALLOC; if ((sec_flags & SF_READONLY) == 0) osh.sh_flags |= SHF_WRITE; if (sec_flags & SF_CODE) osh.sh_flags |= SHF_EXECINSTR; if ((sec_flags & SF_CONTENTS) && s->type == SHT_NOBITS && s->sz > 0) { /* * Convert SHT_NOBITS section to section with * (zero'ed) content on file. */ osh.sh_type = s->type = SHT_PROGBITS; if ((s->buf = calloc(1, s->sz)) == NULL) err(EXIT_FAILURE, "malloc failed"); s->nocopy = 1; } } else { osh.sh_flags = ish.sh_flags; /* * Newer binutils as(1) emits the section flag * SHF_INFO_LINK for relocation sections. elfcopy * emits this flag in the output section if it's * missing in the input section, to remain compatible * with binutils. */ if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) osh.sh_flags |= SHF_INFO_LINK; } } if (name == NULL) add_to_shstrtab(ecp, s->name); else add_to_shstrtab(ecp, name); if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "elf_update_shdr failed: %s", elf_errmsg(-1)); } void copy_data(struct section *s) { Elf_Data *id, *od; int elferr; if (s->nocopy && s->buf == NULL) return; if ((id = elf_getdata(s->is, NULL)) == NULL) { (void) elf_errno(); if ((id = elf_rawdata(s->is, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "failed to read section:" " %s", s->name); return; } } if ((od = elf_newdata(s->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); if (s->nocopy) { /* Use s->buf as content if s->nocopy is set. */ od->d_align = id->d_align; od->d_off = 0; od->d_buf = s->buf; od->d_type = id->d_type; od->d_size = s->sz; od->d_version = id->d_version; } else { od->d_align = id->d_align; od->d_off = id->d_off; od->d_buf = id->d_buf; od->d_type = id->d_type; od->d_size = id->d_size; od->d_version = id->d_version; } /* * Alignment Fixup. libelf does not allow the alignment for * Elf_Data descriptor to be set to 0. In this case we workaround * it by setting the alignment to 1. * * According to the ELF ABI, alignment 0 and 1 has the same * meaning: the section has no alignment constraints. */ if (od->d_align == 0) od->d_align = 1; } struct section * create_external_section(struct elfcopy *ecp, const char *name, char *newname, void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype, uint64_t flags, uint64_t align, uint64_t vma, int loadable) { struct section *s; Elf_Scn *os; Elf_Data *od; GElf_Shdr osh; if ((os = elf_newscn(ecp->eout)) == NULL) errx(EXIT_FAILURE, "elf_newscn() failed: %s", elf_errmsg(-1)); if ((s = calloc(1, sizeof(*s))) == NULL) err(EXIT_FAILURE, "calloc failed"); s->name = name; s->newname = newname; /* needs to be free()'ed */ s->off = off; s->sz = size; s->vma = vma; s->align = align; s->loadable = loadable; s->is = NULL; s->os = os; s->type = stype; s->nocopy = 1; insert_to_sec_list(ecp, s, 1); if (gelf_getshdr(os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); osh.sh_flags = flags; osh.sh_type = s->type; osh.sh_addr = s->vma; osh.sh_addralign = s->align; if (!gelf_update_shdr(os, &osh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); add_to_shstrtab(ecp, name); if (buf != NULL && size != 0) { if ((od = elf_newdata(os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); od->d_align = align; od->d_off = 0; od->d_buf = buf; od->d_size = size; od->d_type = dtype; od->d_version = EV_CURRENT; } /* * Clear SYMTAB_INTACT, as we probably need to update/add new * STT_SECTION symbols into the symbol table. */ ecp->flags &= ~SYMTAB_INTACT; return (s); } /* * Insert sections specified by --add-section to the end of section list. */ static void insert_sections(struct elfcopy *ecp) { struct sec_add *sa; struct section *s; size_t off; uint64_t stype; /* Put these sections in the end of current list. */ off = 0; TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->type != SHT_NOBITS && s->type != SHT_NULL) off = s->off + s->sz; else off = s->off; } STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) { /* TODO: Add section header vma/lma, flag changes here */ /* * The default section type for user added section is * SHT_PROGBITS. If the section name match certain patterns, * elfcopy will try to set a more appropriate section type. * However, data type is always set to ELF_T_BYTE and no * translation is performed by libelf. */ stype = SHT_PROGBITS; if (strcmp(sa->name, ".note") == 0 || strncmp(sa->name, ".note.", strlen(".note.")) == 0) stype = SHT_NOTE; (void) create_external_section(ecp, sa->name, NULL, sa->content, sa->size, off, stype, ELF_T_BYTE, 0, 1, 0, 0); } } void add_to_shstrtab(struct elfcopy *ecp, const char *name) { if (elftc_string_table_insert(ecp->shstrtab->strtab, name) == 0) errx(EXIT_FAILURE, "elftc_string_table_insert failed"); } void update_shdr(struct elfcopy *ecp, int update_link) { struct section *s; GElf_Shdr osh; int elferr; /* Finalize the section name string table (.shstrtab). */ set_shstrtab(ecp); TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { if (s->pseudo) continue; if (gelf_getshdr(s->os, &osh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); /* Find section name in string table and set sh_name. */ osh.sh_name = elftc_string_table_lookup(ecp->shstrtab->strtab, s->name); /* * sh_link needs to be updated, since the index of the * linked section might have changed. */ if (update_link && osh.sh_link != 0) osh.sh_link = ecp->secndx[osh.sh_link]; /* * sh_info of relocation section links to the section to which * its relocation info applies. So it may need update as well. */ if ((s->type == SHT_REL || s->type == SHT_RELA) && osh.sh_info != 0) osh.sh_info = ecp->secndx[osh.sh_info]; /* * sh_info of SHT_GROUP section needs to point to the correct * string in the symbol table. */ if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) && (ecp->flags & SYMTAB_INTACT) == 0) osh.sh_info = ecp->symndx[osh.sh_info]; if (!gelf_update_shdr(s->os, &osh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_nextscn failed: %s", elf_errmsg(elferr)); } void init_shstrtab(struct elfcopy *ecp) { Elf_Scn *shstrtab; GElf_Shdr shdr; struct section *s; size_t indx, sizehint; if (elf_getshdrstrndx(ecp->ein, &indx) == 0) { shstrtab = elf_getscn(ecp->ein, indx); if (shstrtab == NULL) errx(EXIT_FAILURE, "elf_getscn failed: %s", elf_errmsg(-1)); if (gelf_getshdr(shstrtab, &shdr) != &shdr) errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); sizehint = shdr.sh_size; } else { /* Clear the error from elf_getshdrstrndx(3). */ (void)elf_errno(); sizehint = 0; } if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL) err(EXIT_FAILURE, "calloc failed"); s = ecp->shstrtab; s->name = ".shstrtab"; s->is = NULL; s->sz = 0; s->align = 1; s->loadable = 0; s->type = SHT_STRTAB; s->vma = 0; s->strtab = elftc_string_table_create(sizehint); add_to_shstrtab(ecp, ""); add_to_shstrtab(ecp, ".symtab"); add_to_shstrtab(ecp, ".strtab"); add_to_shstrtab(ecp, ".shstrtab"); } static void set_shstrtab(struct elfcopy *ecp) { struct section *s; Elf_Data *data; GElf_Shdr sh; const char *image; size_t sz; s = ecp->shstrtab; if (s->os == NULL) { /* Input object does not contain .shstrtab section */ if ((s->os = elf_newscn(ecp->eout)) == NULL) errx(EXIT_FAILURE, "elf_newscn failed: %s", elf_errmsg(-1)); insert_to_sec_list(ecp, s, 1); } if (gelf_getshdr(s->os, &sh) == NULL) errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); sh.sh_addr = 0; sh.sh_addralign = 1; sh.sh_offset = s->off; sh.sh_type = SHT_STRTAB; sh.sh_flags = 0; sh.sh_entsize = 0; sh.sh_info = 0; sh.sh_link = 0; if ((data = elf_newdata(s->os)) == NULL) errx(EXIT_FAILURE, "elf_newdata() failed: %s", elf_errmsg(-1)); /* * If we don't have a symbol table, skip those a few bytes * which are reserved for this in the beginning of shstrtab. */ if (!(ecp->flags & SYMTAB_EXIST)) { elftc_string_table_remove(s->strtab, ".symtab"); elftc_string_table_remove(s->strtab, ".strtab"); } image = elftc_string_table_image(s->strtab, &sz); s->sz = sz; sh.sh_size = sz; if (!gelf_update_shdr(s->os, &sh)) errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", elf_errmsg(-1)); data->d_align = 1; data->d_buf = (void *)(uintptr_t)image; data->d_size = sz; data->d_off = 0; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os))) errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s", elf_errmsg(-1)); } void add_section(struct elfcopy *ecp, const char *arg) { struct sec_add *sa; struct stat sb; const char *s, *fn; FILE *fp; int len; if ((s = strchr(arg, '=')) == NULL) errx(EXIT_FAILURE, "illegal format for --add-section option"); if ((sa = malloc(sizeof(*sa))) == NULL) err(EXIT_FAILURE, "malloc failed"); len = s - arg; if ((sa->name = malloc(len + 1)) == NULL) err(EXIT_FAILURE, "malloc failed"); strncpy(sa->name, arg, len); sa->name[len] = '\0'; fn = s + 1; if (stat(fn, &sb) == -1) err(EXIT_FAILURE, "stat failed"); sa->size = sb.st_size; if (sa->size > 0) { if ((sa->content = malloc(sa->size)) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((fp = fopen(fn, "r")) == NULL) err(EXIT_FAILURE, "can not open %s", fn); if (fread(sa->content, 1, sa->size, fp) == 0 || ferror(fp)) err(EXIT_FAILURE, "fread failed"); fclose(fp); } else sa->content = NULL; STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); ecp->flags |= SEC_ADD; } void free_sec_add(struct elfcopy *ecp) { struct sec_add *sa, *sa_temp; STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) { STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list); free(sa->name); free(sa->content); free(sa); } } static void add_gnu_debuglink(struct elfcopy *ecp) { struct sec_add *sa; struct stat sb; FILE *fp; char *fnbase, *buf; int crc_off; int crc; if (ecp->debuglink == NULL) return; /* Read debug file content. */ if ((sa = malloc(sizeof(*sa))) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((sa->name = strdup(".gnu_debuglink")) == NULL) err(EXIT_FAILURE, "strdup failed"); if (stat(ecp->debuglink, &sb) == -1) err(EXIT_FAILURE, "stat failed"); if (sb.st_size == 0) errx(EXIT_FAILURE, "empty debug link target %s", ecp->debuglink); if ((buf = malloc(sb.st_size)) == NULL) err(EXIT_FAILURE, "malloc failed"); if ((fp = fopen(ecp->debuglink, "r")) == NULL) err(EXIT_FAILURE, "can not open %s", ecp->debuglink); if (fread(buf, 1, sb.st_size, fp) == 0 || ferror(fp)) err(EXIT_FAILURE, "fread failed"); fclose(fp); /* Calculate crc checksum. */ crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF); free(buf); /* Calculate section size and the offset to store crc checksum. */ if ((fnbase = basename(ecp->debuglink)) == NULL) err(EXIT_FAILURE, "basename failed"); crc_off = roundup(strlen(fnbase) + 1, 4); sa->size = crc_off + 4; /* Section content. */ if ((sa->content = calloc(1, sa->size)) == NULL) err(EXIT_FAILURE, "malloc failed"); strncpy(sa->content, fnbase, strlen(fnbase)); if (ecp->oed == ELFDATA2LSB) { sa->content[crc_off] = crc & 0xFF; sa->content[crc_off + 1] = (crc >> 8) & 0xFF; sa->content[crc_off + 2] = (crc >> 16) & 0xFF; sa->content[crc_off + 3] = crc >> 24; } else { sa->content[crc_off] = crc >> 24; sa->content[crc_off + 1] = (crc >> 16) & 0xFF; sa->content[crc_off + 2] = (crc >> 8) & 0xFF; sa->content[crc_off + 3] = crc & 0xFF; } STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); ecp->flags |= SEC_ADD; } static uint32_t crctable[256] = { 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL }; static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc) { uint32_t i; for (i = 0; i < len; i++) { crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8); } return (crc ^ 0xFFFFFFFF); } Index: stable/12/contrib/elftoolchain/libelf/Version.map =================================================================== --- stable/12/contrib/elftoolchain/libelf/Version.map (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/Version.map (revision 367462) @@ -1,96 +1,103 @@ /* $Id: Version.map 2574 2012-09-11 15:11:59Z jkoshy $ */ R1.0 { global: elf32_checksum; elf32_fsize; elf32_getehdr; elf32_getphdr; elf32_getshdr; elf32_newehdr; elf32_newphdr; elf32_xlatetof; elf32_xlatetom; elf64_checksum; elf64_fsize; elf64_getehdr; elf64_getphdr; elf64_getshdr; elf64_newehdr; elf64_newphdr; elf64_xlatetof; elf64_xlatetom; elf_begin; elf_cntl; elf_end; elf_errmsg; elf_errno; elf_fill; elf_flagarhdr; elf_flagdata; elf_flagehdr; elf_flagelf; elf_flagphdr; elf_flagscn; elf_flagshdr; elf_getarhdr; elf_getarsym; elf_getbase; elf_getdata; elf_getident; elf_getphdrnum; elf_getphnum; elf_getscn; elf_getshdrnum; elf_getshdrstrndx; elf_getshnum; elf_getshstrndx; elf_hash; elf_kind; elf_memory; elf_ndxscn; elf_newdata; elf_newscn; elf_next; elf_nextscn; elf_open; elf_openmemory; elf_rand; elf_rawdata; elf_rawfile; elf_setshstrndx; elf_strptr; elf_update; elf_version; gelf_checksum; gelf_fsize; gelf_getcap; gelf_getclass; gelf_getdyn; gelf_getehdr; gelf_getmove; gelf_getphdr; gelf_getrel; gelf_getrela; gelf_getshdr; gelf_getsym; gelf_getsyminfo; gelf_getsymshndx; gelf_newehdr; gelf_newphdr; gelf_update_cap; gelf_update_dyn; gelf_update_ehdr; gelf_update_move; gelf_update_phdr; gelf_update_rel; gelf_update_rela; gelf_update_shdr; gelf_update_sym; gelf_update_syminfo; gelf_update_symshndx; gelf_xlatetof; gelf_xlatetom; +}; + +R1.1 { +global: + elf32_getchdr; + elf64_getchdr; + gelf_getchdr; local: *; -}; +} R1.0; Index: stable/12/contrib/elftoolchain/libelf/_libelf.h =================================================================== --- stable/12/contrib/elftoolchain/libelf/_libelf.h (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/_libelf.h (revision 367462) @@ -1,249 +1,250 @@ /*- * Copyright (c) 2006,2008-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: _libelf.h 3738 2019-05-05 21:49:06Z jkoshy $ */ #ifndef __LIBELF_H_ #define __LIBELF_H_ #include #include #include "_libelf_config.h" #include "_elftc.h" /* * Library-private data structures. */ #define LIBELF_MSG_SIZE 256 struct _libelf_globals { int libelf_arch; unsigned int libelf_byteorder; int libelf_class; int libelf_error; int libelf_fillchar; unsigned int libelf_version; unsigned char libelf_msg[LIBELF_MSG_SIZE]; }; extern struct _libelf_globals _libelf; #define LIBELF_PRIVATE(N) (_libelf.libelf_##N) #define LIBELF_ELF_ERROR_MASK 0xFF #define LIBELF_OS_ERROR_SHIFT 8 #define LIBELF_ERROR(E, O) (((E) & LIBELF_ELF_ERROR_MASK) | \ ((O) << LIBELF_OS_ERROR_SHIFT)) #define LIBELF_SET_ERROR(E, O) do { \ LIBELF_PRIVATE(error) = LIBELF_ERROR(ELF_E_##E, (O)); \ } while (0) #define LIBELF_ADJUST_AR_SIZE(S) (((S) + 1U) & ~1U) /* * Flags for library internal use. These use the upper 16 bits of the * `e_flags' field. */ #define LIBELF_F_API_MASK 0x00FFFFU /* Flags defined by the API. */ #define LIBELF_F_AR_HEADER 0x010000U /* translated header available */ #define LIBELF_F_AR_VARIANT_SVR4 0x020000U /* BSD style ar(1) archive */ #define LIBELF_F_DATA_MALLOCED 0x040000U /* whether data was malloc'ed */ #define LIBELF_F_RAWFILE_MALLOC 0x080000U /* whether e_rawfile was malloc'ed */ #define LIBELF_F_RAWFILE_MMAP 0x100000U /* whether e_rawfile was mmap'ed */ #define LIBELF_F_SHDRS_LOADED 0x200000U /* whether all shdrs were read in */ #define LIBELF_F_SPECIAL_FILE 0x400000U /* non-regular file */ RB_HEAD(scntree, _Elf_Scn); RB_PROTOTYPE(scntree, _Elf_Scn, e_scn, elfscn_cmp); struct _Elf { int e_activations; /* activation count */ unsigned int e_byteorder; /* ELFDATA* */ int e_class; /* ELFCLASS* */ Elf_Cmd e_cmd; /* ELF_C_* used at creation time */ int e_fd; /* associated file descriptor */ unsigned int e_flags; /* ELF_F_* & LIBELF_F_* flags */ Elf_Kind e_kind; /* ELF_K_* */ Elf *e_parent; /* non-NULL for archive members */ unsigned char *e_rawfile; /* uninterpreted bytes */ off_t e_rawsize; /* size of uninterpreted bytes */ unsigned int e_version; /* file version */ /* * Header information for archive members. See the * LIBELF_F_AR_HEADER flag. */ union { Elf_Arhdr *e_arhdr; /* translated header */ unsigned char *e_rawhdr; /* untranslated header */ } e_hdr; union { struct { /* ar(1) archives */ off_t e_next; /* set by elf_rand()/elf_next() */ int e_nchildren; unsigned char *e_rawstrtab; /* file name strings */ size_t e_rawstrtabsz; unsigned char *e_rawsymtab; /* symbol table */ size_t e_rawsymtabsz; Elf_Arsym *e_symtab; size_t e_symtabsz; } e_ar; struct { /* regular ELF files */ union { Elf32_Ehdr *e_ehdr32; Elf64_Ehdr *e_ehdr64; } e_ehdr; union { Elf32_Phdr *e_phdr32; Elf64_Phdr *e_phdr64; } e_phdr; struct scntree e_scn; /* sections */ size_t e_nphdr; /* number of Phdr entries */ size_t e_nscn; /* number of sections */ size_t e_strndx; /* string table section index */ } e_elf; } e_u; }; /* * The internal descriptor wrapping the "Elf_Data" type. */ struct _Libelf_Data { Elf_Data d_data; /* The exported descriptor. */ Elf_Scn *d_scn; /* The containing section */ unsigned int d_flags; STAILQ_ENTRY(_Libelf_Data) d_next; }; struct _Elf_Scn { union { Elf32_Shdr s_shdr32; Elf64_Shdr s_shdr64; } s_shdr; STAILQ_HEAD(, _Libelf_Data) s_data; /* translated data */ STAILQ_HEAD(, _Libelf_Data) s_rawdata; /* raw data */ RB_ENTRY(_Elf_Scn) s_tree; struct _Elf *s_elf; /* parent ELF descriptor */ unsigned int s_flags; /* flags for the section as a whole */ size_t s_ndx; /* index# for this section */ uint64_t s_offset; /* managed by elf_update() */ uint64_t s_rawoff; /* original offset in the file */ uint64_t s_size; /* managed by elf_update() */ }; enum { ELF_TOFILE, ELF_TOMEMORY }; /* * The LIBELF_COPY macros are used to copy fields from a GElf_* * structure to their 32-bit counterparts, while checking for out of * range values. * * - LIBELF_COPY_U32 :: copy an unsigned 32 bit field. * - LIBELF_COPY_S32 :: copy a signed 32 bit field. */ #define LIBELF_COPY_U32(DST, SRC, NAME) do { \ if ((SRC)->NAME > UINT32_MAX) { \ LIBELF_SET_ERROR(RANGE, 0); \ return (0); \ } \ (DST)->NAME = (SRC)->NAME & 0xFFFFFFFFU; \ } while (0) #define LIBELF_COPY_S32(DST, SRC, NAME) do { \ if ((SRC)->NAME > INT32_MAX || \ (SRC)->NAME < INT32_MIN) { \ LIBELF_SET_ERROR(RANGE, 0); \ return (0); \ } \ (DST)->NAME = (int32_t) (SRC)->NAME; \ } while (0) /* * Function Prototypes. */ typedef int _libelf_translator_function(unsigned char *_dst, size_t dsz, unsigned char *_src, size_t _cnt, int _byteswap); #ifdef __cplusplus extern "C" { #endif struct _Libelf_Data *_libelf_allocate_data(Elf_Scn *_s); Elf *_libelf_allocate_elf(void); Elf_Scn *_libelf_allocate_scn(Elf *_e, size_t _ndx); Elf_Arhdr *_libelf_ar_gethdr(Elf *_e); Elf *_libelf_ar_open(Elf *_e, int _reporterror); Elf *_libelf_ar_open_member(int _fd, Elf_Cmd _c, Elf *_ar); Elf_Arsym *_libelf_ar_process_bsd_symtab(Elf *_ar, size_t *_dst); Elf_Arsym *_libelf_ar_process_svr4_symtab(Elf *_ar, size_t *_dst); long _libelf_checksum(Elf *_e, int _elfclass); void *_libelf_ehdr(Elf *_e, int _elfclass, int _allocate); int _libelf_elfmachine(Elf *_e); unsigned int _libelf_falign(Elf_Type _t, int _elfclass); size_t _libelf_fsize(Elf_Type _t, int _elfclass, unsigned int _version, size_t count); _libelf_translator_function *_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass, int _elfmachine); +void *_libelf_getchdr(Elf_Scn *_e, int _elfclass); void *_libelf_getphdr(Elf *_e, int _elfclass); void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass); void _libelf_init_elf(Elf *_e, Elf_Kind _kind); int _libelf_is_mips64el(Elf *e); int _libelf_load_section_headers(Elf *e, void *ehdr); unsigned int _libelf_malign(Elf_Type _t, int _elfclass); Elf *_libelf_memory(unsigned char *_image, size_t _sz, int _reporterror); size_t _libelf_msize(Elf_Type _t, int _elfclass, unsigned int _version); void *_libelf_newphdr(Elf *_e, int _elfclass, size_t _count); Elf *_libelf_open_object(int _fd, Elf_Cmd _c, int _reporterror); Elf64_Xword _libelf_mips64el_r_info_tof(Elf64_Xword r_info); Elf64_Xword _libelf_mips64el_r_info_tom(Elf64_Xword r_info); struct _Libelf_Data *_libelf_release_data(struct _Libelf_Data *_d); void _libelf_release_elf(Elf *_e); Elf_Scn *_libelf_release_scn(Elf_Scn *_s); int _libelf_setphnum(Elf *_e, void *_eh, int _elfclass, size_t _phnum); int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum); int _libelf_setshstrndx(Elf *_e, void *_eh, int _elfclass, size_t _shstrndx); Elf_Data *_libelf_xlate(Elf_Data *_d, const Elf_Data *_s, unsigned int _encoding, int _elfclass, int _elfmachine, int _direction); int _libelf_xlate_shtype(uint32_t _sht); #ifdef __cplusplus } #endif #endif /* __LIBELF_H_ */ Index: stable/12/contrib/elftoolchain/libelf/_libelf_config.h =================================================================== --- stable/12/contrib/elftoolchain/libelf/_libelf_config.h (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/_libelf_config.h (revision 367462) @@ -1,201 +1,205 @@ /*- * Copyright (c) 2008-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: _libelf_config.h 3764 2019-06-28 21:44:46Z emaste $ */ #if defined(__APPLE__) || defined(__DragonFly__) #if defined(__amd64__) #define LIBELF_ARCH EM_X86_64 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS64 #elif defined(__i386__) #define LIBELF_ARCH EM_386 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS32 #endif #endif /* __DragonFly__ */ #ifdef __FreeBSD__ /* * Define LIBELF_{ARCH,BYTEORDER,CLASS} based on the machine architecture. * See also: . */ #if defined(__amd64__) #define LIBELF_ARCH EM_X86_64 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS64 #elif defined(__aarch64__) #define LIBELF_ARCH EM_AARCH64 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS64 #elif defined(__arm__) #define LIBELF_ARCH EM_ARM #if defined(__ARMEB__) /* Big-endian ARM. */ #define LIBELF_BYTEORDER ELFDATA2MSB #else #define LIBELF_BYTEORDER ELFDATA2LSB #endif #define LIBELF_CLASS ELFCLASS32 #elif defined(__i386__) #define LIBELF_ARCH EM_386 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS32 #elif defined(__ia64__) #define LIBELF_ARCH EM_IA_64 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS64 #elif defined(__mips__) #define LIBELF_ARCH EM_MIPS #if defined(__MIPSEB__) #define LIBELF_BYTEORDER ELFDATA2MSB #else #define LIBELF_BYTEORDER ELFDATA2LSB #endif #define LIBELF_CLASS ELFCLASS32 #elif defined(__powerpc64__) #define LIBELF_ARCH EM_PPC64 +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define LIBELF_BYTEORDER ELFDATA2LSB +#else #define LIBELF_BYTEORDER ELFDATA2MSB +#endif #define LIBELF_CLASS ELFCLASS64 #elif defined(__powerpc__) #define LIBELF_ARCH EM_PPC #define LIBELF_BYTEORDER ELFDATA2MSB #define LIBELF_CLASS ELFCLASS32 #elif defined(__riscv) && (__riscv_xlen == 64) #define LIBELF_ARCH EM_RISCV #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS64 #elif defined(__riscv64) #define LIBELF_ARCH EM_RISCV #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS64 #elif defined(__sparc__) #define LIBELF_ARCH EM_SPARCV9 #define LIBELF_BYTEORDER ELFDATA2MSB #define LIBELF_CLASS ELFCLASS64 #else #error Unknown FreeBSD architecture. #endif #endif /* __FreeBSD__ */ /* * Definitions for Minix3. */ #ifdef __minix #define LIBELF_ARCH EM_386 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS32 #endif /* __minix */ #ifdef __NetBSD__ #include #if !defined(ARCH_ELFSIZE) #error ARCH_ELFSIZE is not defined. #endif #if ARCH_ELFSIZE == 32 #define LIBELF_ARCH ELF32_MACHDEP_ID #define LIBELF_BYTEORDER ELF32_MACHDEP_ENDIANNESS #define LIBELF_CLASS ELFCLASS32 #define Elf_Note Elf32_Nhdr #else #define LIBELF_ARCH ELF64_MACHDEP_ID #define LIBELF_BYTEORDER ELF64_MACHDEP_ENDIANNESS #define LIBELF_CLASS ELFCLASS64 #define Elf_Note Elf64_Nhdr #endif #endif /* __NetBSD__ */ #if defined(__OpenBSD__) #include #define LIBELF_ARCH ELF_TARG_MACH #define LIBELF_BYTEORDER ELF_TARG_DATA #define LIBELF_CLASS ELF_TARG_CLASS #endif /* * GNU & Linux compatibility. * * `__linux__' is defined in an environment runs the Linux kernel and glibc. * `__GNU__' is defined in an environment runs a GNU kernel (Hurd) and glibc. * `__GLIBC__' is defined for an environment that runs glibc over a non-GNU * kernel such as GNU/kFreeBSD. */ #if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) #if defined(__linux__) #include "native-elf-format.h" #define LIBELF_CLASS ELFTC_CLASS #define LIBELF_ARCH ELFTC_ARCH #define LIBELF_BYTEORDER ELFTC_BYTEORDER #endif /* defined(__linux__) */ #if LIBELF_CLASS == ELFCLASS32 #define Elf_Note Elf32_Nhdr #elif LIBELF_CLASS == ELFCLASS64 #define Elf_Note Elf64_Nhdr #else #error LIBELF_CLASS needs to be one of ELFCLASS32 or ELFCLASS64 #endif #endif /* defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) */ Index: stable/12/contrib/elftoolchain/libelf/gelf.3 =================================================================== --- stable/12/contrib/elftoolchain/libelf/gelf.3 (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/gelf.3 (revision 367462) @@ -1,203 +1,207 @@ .\" Copyright (c) 2006,2008 Joseph Koshy. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" This software is provided by Joseph Koshy ``as is'' and .\" any express or implied warranties, including, but not limited to, the .\" implied warranties of merchantability and fitness for a particular purpose .\" are disclaimed. in no event shall Joseph Koshy be liable .\" for any direct, indirect, incidental, special, exemplary, or consequential .\" damages (including, but not limited to, procurement of substitute goods .\" or services; loss of use, data, or profits; or business interruption) .\" however caused and on any theory of liability, whether in contract, strict .\" liability, or tort (including negligence or otherwise) arising in any way .\" out of the use of this software, even if advised of the possibility of .\" such damage. .\" .\" $Id: gelf.3 3743 2019-06-12 19:36:30Z jkoshy $ .\" -.Dd June 12, 2019 +.Dd October 23, 2020 .Dt GELF 3 .Os .Sh NAME .Nm gelf .Nd class-independent API for ELF manipulation .Sh LIBRARY .Lb libelf .Sh SYNOPSIS .In gelf.h .Sh DESCRIPTION This manual page describes a class independent API for manipulating ELF objects. This API allows an application to operate on ELF descriptors without needing to the know the ELF class of the descriptor. .Pp The GElf API may be used alongside the ELF API without restriction. .Ss GElf Data Structures The GElf API defines the following class-independent data structures: .Bl -tag -width GElf_Sxword .It Vt GElf_Addr A representation of ELF addresses. +.It Vt GElf_Chdr +A class-independent representation of an ELF Compression Header. .It Vt GElf_Dyn A class-independent representation of ELF .Sy .dynamic section entries. .It Vt GElf_Ehdr A class-independent representation of an ELF Executable Header. .It Vt GElf_Half An unsigned 16 bit quantity. .It Vt GElf_Off A class-independent representation of a ELF offset. .It Vt GElf_Phdr A class-independent representation of an ELF Program Header Table entry. .It Vt GElf_Rel A class-independent representation of an ELF relocation entry. .It Vt GElf_Rela A class-independent representation of an ELF relocation entry with addend. .It Vt GElf_Shdr A class-independent representation of an ELF Section Header Table entry. .It Vt GElf_Sword A signed 32 bit quantity. .It Vt GElf_Sxword A signed 64 bit quantity. .It Vt GElf_Sym A class-independent representation of an ELF symbol table entry. .It Vt GElf_Word An unsigned 32 bit quantity. .It Vt GElf_Xword An unsigned 64 bit quantity. .El .Pp These data structures are sized to be compatible with the corresponding 64 bit ELF structures, and have the same internal structure as their 64 bit class-dependent counterparts. Class-dependent ELF structures are described in .Xr elf 5 . .Ss GElf Programming Model GElf functions always return a .Em copy of the underlying (class-dependent) ELF data structure. The programming model with GElf is as follows: .Bl -enum .It An application will retrieve data from an ELF descriptor using a .Fn gelf_get_* function. This will copy out data into a private .Vt GElf_* data structure. .It The application will work with its private copy of the GElf structure. .It Once done, the application copies the new values back to the underlying ELF data structure using the .Fn gelf_update_* functions. .It The application will then use the .Fn elf_flag* APIs to indicate to the ELF library that an ELF data structure is dirty. .El .Pp When updating an underlying 32 bit ELF data structure, the GElf routines will signal an error if a GElf value is out of range for the underlying ELF data type. .Ss Namespace use The GElf interface uses the following symbols: .Bl -tag -width indent .It GElf_* Class-independent data types. .It gelf_* For functions defined in the API set. .El .Ss GElf Programming APIs This section provides an overview of the GElf programming APIs. Further information is provided in the manual page of each function listed here. .Bl -tag -width indent .It "Allocating ELF Data Structures" .Bl -tag -compact -width indent .It Fn gelf_newehdr Allocate a new ELF Executable Header. .It Fn gelf_newphdr Allocate a new ELF Program Header Table. .El .It "Data Translation" .Bl -tag -compact -width indent .It Fn gelf_xlatetof Translate the native representation of an ELF data structure to its file representation. .It Fn gelf_xlatetom Translate from the file representation of an ELF data structure to a native representation. .El .It "Retrieving ELF Data" .Bl -tag -compact -width indent +.It Fn gelf_getchdr +Retrieve an ELF Compression Header from the underlying ELF descriptor. .It Fn gelf_getdyn Retrieve an ELF .Sy .dynamic table entry. .It Fn gelf_getehdr Retrieve an ELF Executable Header from the underlying ELF descriptor. .It Fn gelf_getphdr Retrieve an ELF Program Header Table entry from the underlying ELF descriptor. .It Fn gelf_getrel Retrieve an ELF relocation entry. .It Fn gelf_getrela Retrieve an ELF relocation entry with addend. .It Fn gelf_getshdr Retrieve an ELF Section Header Table entry from the underlying ELF descriptor. .It Fn gelf_getsym Retrieve an ELF symbol table entry. .El .It Queries .Bl -tag -compact -width indent .It Fn gelf_checksum Retrieves the ELF checksum for an ELF descriptor. .It Fn gelf_fsize Retrieves the size of the file representation of an ELF type. .It Fn gelf_getclass Retrieves the ELF class of an ELF descriptor. .El .It "Updating ELF Data" .Bl -tag -compact -width ".Fn gelf_update_shdr" .It Fn gelf_update_dyn Copy back an ELF .Sy .dynamic Table entry. .It Fn gelf_update_phdr Copy back an ELF Program Header Table entry. .It Fn gelf_update_rel Copy back an ELF relocation entry. .It Fn gelf_update_rela Copy back an ELF relocation with addend entry. .It Fn gelf_update_shdr Copy back an ELF Section Header Table entry. .It Fn gelf_update_sym Copy back an ELF symbol table entry. .El .El .Sh SEE ALSO .Xr elf 3 , .Xr elf 5 .Sh HISTORY The .Nm API first appeared in .At V.4 . This implementation of the API first appeared in .Fx 7.0 . .Sh AUTHORS The GElf API was implemented by .An Joseph Koshy Aq Mt jkoshy@FreeBSD.org . Index: stable/12/contrib/elftoolchain/libelf/gelf.h =================================================================== --- stable/12/contrib/elftoolchain/libelf/gelf.h (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/gelf.h (revision 367462) @@ -1,110 +1,112 @@ /*- * Copyright (c) 2006,2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: gelf.h 3174 2015-03-27 17:13:41Z emaste $ */ #ifndef _GELF_H_ #define _GELF_H_ #include typedef Elf64_Addr GElf_Addr; /* Addresses */ typedef Elf64_Half GElf_Half; /* Half words (16 bit) */ typedef Elf64_Off GElf_Off; /* Offsets */ typedef Elf64_Sword GElf_Sword; /* Signed words (32 bit) */ typedef Elf64_Sxword GElf_Sxword; /* Signed long words (64 bit) */ typedef Elf64_Word GElf_Word; /* Unsigned words (32 bit) */ typedef Elf64_Xword GElf_Xword; /* Unsigned long words (64 bit) */ +typedef Elf64_Chdr GElf_Chdr; /* Compressed section header */ typedef Elf64_Dyn GElf_Dyn; /* ".dynamic" section entries */ typedef Elf64_Ehdr GElf_Ehdr; /* ELF header */ typedef Elf64_Phdr GElf_Phdr; /* Program header */ typedef Elf64_Shdr GElf_Shdr; /* Section header */ typedef Elf64_Sym GElf_Sym; /* Symbol table entries */ typedef Elf64_Rel GElf_Rel; /* Relocation entries */ typedef Elf64_Rela GElf_Rela; /* Relocation entries with addend */ typedef Elf64_Cap GElf_Cap; /* SW/HW capabilities */ typedef Elf64_Move GElf_Move; /* Move entries */ typedef Elf64_Syminfo GElf_Syminfo; /* Symbol information */ #define GELF_M_INFO ELF64_M_INFO #define GELF_M_SIZE ELF64_M_SIZE #define GELF_M_SYM ELF64_M_SYM #define GELF_R_INFO ELF64_R_INFO #define GELF_R_SYM ELF64_R_SYM #define GELF_R_TYPE ELF64_R_TYPE #define GELF_R_TYPE_DATA ELF64_R_TYPE_DATA #define GELF_R_TYPE_ID ELF64_R_TYPE_ID #define GELF_R_TYPE_INFO ELF64_R_TYPE_INFO #define GELF_ST_BIND ELF64_ST_BIND #define GELF_ST_INFO ELF64_ST_INFO #define GELF_ST_TYPE ELF64_ST_TYPE #define GELF_ST_VISIBILITY ELF64_ST_VISIBILITY #ifdef __cplusplus extern "C" { #endif long gelf_checksum(Elf *_elf); size_t gelf_fsize(Elf *_elf, Elf_Type _type, size_t _count, unsigned int _version); +GElf_Chdr *gelf_getchdr(Elf_Scn *_scn, GElf_Chdr *_dst); int gelf_getclass(Elf *_elf); GElf_Dyn *gelf_getdyn(Elf_Data *_data, int _index, GElf_Dyn *_dst); GElf_Ehdr *gelf_getehdr(Elf *_elf, GElf_Ehdr *_dst); GElf_Phdr *gelf_getphdr(Elf *_elf, int _index, GElf_Phdr *_dst); GElf_Rel *gelf_getrel(Elf_Data *_src, int _index, GElf_Rel *_dst); GElf_Rela *gelf_getrela(Elf_Data *_src, int _index, GElf_Rela *_dst); GElf_Shdr *gelf_getshdr(Elf_Scn *_scn, GElf_Shdr *_dst); GElf_Sym *gelf_getsym(Elf_Data *_src, int _index, GElf_Sym *_dst); GElf_Sym *gelf_getsymshndx(Elf_Data *_src, Elf_Data *_shindexsrc, int _index, GElf_Sym *_dst, Elf32_Word *_shindexdst); void * gelf_newehdr(Elf *_elf, int _class); void * gelf_newphdr(Elf *_elf, size_t _phnum); int gelf_update_dyn(Elf_Data *_dst, int _index, GElf_Dyn *_src); int gelf_update_ehdr(Elf *_elf, GElf_Ehdr *_src); int gelf_update_phdr(Elf *_elf, int _index, GElf_Phdr *_src); int gelf_update_rel(Elf_Data *_dst, int _index, GElf_Rel *_src); int gelf_update_rela(Elf_Data *_dst, int _index, GElf_Rela *_src); int gelf_update_shdr(Elf_Scn *_dst, GElf_Shdr *_src); int gelf_update_sym(Elf_Data *_dst, int _index, GElf_Sym *_src); int gelf_update_symshndx(Elf_Data *_symdst, Elf_Data *_shindexdst, int _index, GElf_Sym *_symsrc, Elf32_Word _shindexsrc); Elf_Data *gelf_xlatetof(Elf *_elf, Elf_Data *_dst, const Elf_Data *_src, unsigned int _encode); Elf_Data *gelf_xlatetom(Elf *_elf, Elf_Data *_dst, const Elf_Data *_src, unsigned int _encode); GElf_Cap *gelf_getcap(Elf_Data *_data, int _index, GElf_Cap *_cap); GElf_Move *gelf_getmove(Elf_Data *_src, int _index, GElf_Move *_dst); GElf_Syminfo *gelf_getsyminfo(Elf_Data *_src, int _index, GElf_Syminfo *_dst); int gelf_update_cap(Elf_Data *_dst, int _index, GElf_Cap *_src); int gelf_update_move(Elf_Data *_dst, int _index, GElf_Move *_src); int gelf_update_syminfo(Elf_Data *_dst, int _index, GElf_Syminfo *_src); #ifdef __cplusplus } #endif #endif /* _GELF_H_ */ Index: stable/12/contrib/elftoolchain/libelf/gelf_chdr.c =================================================================== --- stable/12/contrib/elftoolchain/libelf/gelf_chdr.c (nonexistent) +++ stable/12/contrib/elftoolchain/libelf/gelf_chdr.c (revision 367462) @@ -0,0 +1,82 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020 The FreeBSD Foundation + * + * This software was developed by Tiger Gao under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "_libelf.h" + +Elf32_Chdr * +elf32_getchdr(Elf_Scn *s) +{ + return (_libelf_getchdr(s, ELFCLASS32)); +} + +Elf64_Chdr * +elf64_getchdr(Elf_Scn *s) +{ + return (_libelf_getchdr(s, ELFCLASS64)); +} + +GElf_Chdr * +gelf_getchdr(Elf_Scn *s, GElf_Chdr *d) +{ + int ec; + void *ch; + Elf32_Chdr *ch32; + Elf64_Chdr *ch64; + + if (d == NULL) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if ((ch = _libelf_getchdr(s, ELFCLASSNONE)) == NULL) + return (NULL); + + ec = s->s_elf->e_class; + assert(ec == ELFCLASS32 || ec == ELFCLASS64); + + if (ec == ELFCLASS32) { + ch32 = (Elf32_Chdr *)ch; + + d->ch_type = (Elf64_Word)ch32->ch_type; + d->ch_size = (Elf64_Xword)ch32->ch_size; + d->ch_addralign = (Elf64_Xword)ch32->ch_addralign; + } else { + ch64 = (Elf64_Chdr *)ch; + *d = *ch64; + } + + return (d); +} Property changes on: stable/12/contrib/elftoolchain/libelf/gelf_chdr.c ___________________________________________________________________ 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: stable/12/contrib/elftoolchain/libelf/gelf_getchdr.3 =================================================================== --- stable/12/contrib/elftoolchain/libelf/gelf_getchdr.3 (nonexistent) +++ stable/12/contrib/elftoolchain/libelf/gelf_getchdr.3 (revision 367462) @@ -0,0 +1,117 @@ +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2020 The FreeBSD Foundation +.\" +.\" This document was written by Tiger Gao under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" 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: gelf_getchdr.3 3639 2020-10-20 16:07:02Z tig $ +.\" +.Dd October 23, 2020 +.Dt GELF_GETCHDR 3 +.Os +.Sh NAME +.Nm elf32_getchdr , +.Nm elf64_getchdr , +.Nm gelf_getchdr +.Nd retrieve the compression header of a section +.Sh LIBRARY +.Lb libelf +.Sh SYNOPSIS +.In libelf.h +.Ft "Elf32_Chdr *" +.Fn elf32_getchdr "Elf_Scn *s" +.Ft "Elf64_Chdr *" +.Fn elf64_getchdr "Elf_Scn *s" +.In gelf.h +.Ft "GElf_Chdr *" +.Fn gelf_getchdr "Elf_Scn *scn" "GElf_Chdr *chdr" +.Sh DESCRIPTION +These functions return a pointer to the ELF Compression Header data +structure associated with section descriptor +.Ar scn . +.Pp +Function +.Fn elf32_getchdr +retrieves a pointer to an +.Vt Elf32_Chdr +structure. +Section descriptor +.Ar scn +must be associated with an ELF descriptor of class +.Dv ELFCLASS32 . +.Pp +Function +.Fn elf64_getchdr +retrieves a pointer to an +.Vt Elf64_Chdr +structure. +Section descriptor +.Ar scn +must be associated with an ELF descriptor of class +.Dv ELFCLASS64 . +.Pp +Function +.Fn gelf_getchdr +copies the values in the compression header associated with argument +.Ar scn +to the structure pointed to be argument +.Ar dst . +The +.Vt GElf_Chdr +data structure is described in +.Xr gelf 3 . +.Sh RETURN VALUES +Functions +.Fn elf32_getchdr +and +.Fn elf64_getchdr +return a valid pointer to the appropriate compression header on success +or NULL if an error was encountered. +.Pp +Function +.Fn gelf_getchdr +returns argument +.Ar dst +if successful, or NULL if an error was encountered. +.Sh ERRORS +These functions may fail with the following errors: +.Bl -tag -width "[ELF_E_RESOURCE]" +.It Bq Er ELF_E_INVALID_SECTION_FLAGS +Arguments +.Ar scn +has invalid flags. +.It Bq Er ELF_E_INVALID_SECTION_TYPE +Argument +.Ar scn +has invalid type. +.It Bq Er ELF_E_NOT_COMPRESSED +Argument +.Ar scn +is not compressed. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_getscn 3 , +.Xr gelf 3 , Property changes on: stable/12/contrib/elftoolchain/libelf/gelf_getchdr.3 ___________________________________________________________________ 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: stable/12/contrib/elftoolchain/libelf/libelf.h =================================================================== --- stable/12/contrib/elftoolchain/libelf/libelf.h (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/libelf.h (revision 367462) @@ -1,256 +1,261 @@ /*- * Copyright (c) 2006,2008-2010 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: libelf.h 3174 2015-03-27 17:13:41Z emaste $ */ #ifndef _LIBELF_H_ #define _LIBELF_H_ #include #include #include /* Library private data structures */ typedef struct _Elf Elf; typedef struct _Elf_Scn Elf_Scn; /* File types */ typedef enum { ELF_K_NONE = 0, ELF_K_AR, /* `ar' archives */ ELF_K_COFF, /* COFF files (unsupported) */ ELF_K_ELF, /* ELF files */ ELF_K_NUM } Elf_Kind; #define ELF_K_FIRST ELF_K_NONE #define ELF_K_LAST ELF_K_NUM /* Data types */ typedef enum { ELF_T_ADDR, ELF_T_BYTE, ELF_T_CAP, ELF_T_DYN, ELF_T_EHDR, ELF_T_HALF, ELF_T_LWORD, ELF_T_MOVE, ELF_T_MOVEP, ELF_T_NOTE, ELF_T_OFF, ELF_T_PHDR, ELF_T_REL, ELF_T_RELA, ELF_T_SHDR, ELF_T_SWORD, ELF_T_SXWORD, ELF_T_SYMINFO, ELF_T_SYM, ELF_T_VDEF, ELF_T_VNEED, ELF_T_WORD, ELF_T_XWORD, ELF_T_GNUHASH, /* GNU style hash tables. */ ELF_T_NUM } Elf_Type; #define ELF_T_FIRST ELF_T_ADDR #define ELF_T_LAST ELF_T_GNUHASH /* Commands */ typedef enum { ELF_C_NULL = 0, ELF_C_CLR, ELF_C_FDDONE, ELF_C_FDREAD, ELF_C_RDWR, ELF_C_READ, ELF_C_SET, ELF_C_WRITE, ELF_C_NUM } Elf_Cmd; #define ELF_C_FIRST ELF_C_NULL #define ELF_C_LAST ELF_C_NUM /* * An `Elf_Data' structure describes data in an * ELF section. */ typedef struct _Elf_Data { /* * `Public' members that are part of the ELF(3) API. */ uint64_t d_align; void *d_buf; uint64_t d_off; uint64_t d_size; Elf_Type d_type; unsigned int d_version; } Elf_Data; /* * An `Elf_Arhdr' structure describes an archive * header. */ typedef struct { time_t ar_date; char *ar_name; /* archive member name */ gid_t ar_gid; mode_t ar_mode; char *ar_rawname; /* 'raw' member name */ size_t ar_size; uid_t ar_uid; /* * Members that are not part of the public API. */ unsigned int ar_flags; } Elf_Arhdr; /* * An `Elf_Arsym' describes an entry in the archive * symbol table. */ typedef struct { off_t as_off; /* byte offset to member's header */ unsigned long as_hash; /* elf_hash() value for name */ char *as_name; /* null terminated symbol name */ } Elf_Arsym; /* * Error numbers. */ enum Elf_Error { ELF_E_NONE, /* No error */ ELF_E_ARCHIVE, /* Malformed ar(1) archive */ ELF_E_ARGUMENT, /* Invalid argument */ ELF_E_CLASS, /* Mismatched ELF class */ ELF_E_DATA, /* Invalid data descriptor */ ELF_E_HEADER, /* Missing or malformed ELF header */ ELF_E_IO, /* I/O error */ ELF_E_LAYOUT, /* Layout constraint violation */ ELF_E_MODE, /* Wrong mode for ELF descriptor */ ELF_E_RANGE, /* Value out of range */ ELF_E_RESOURCE, /* Resource exhaustion */ ELF_E_SECTION, /* Invalid section descriptor */ ELF_E_SEQUENCE, /* API calls out of sequence */ ELF_E_UNIMPL, /* Feature is unimplemented */ ELF_E_VERSION, /* Unknown API version */ + ELF_E_INVALID_SECTION_FLAGS, /* Invalid ELF section header flags */ + ELF_E_INVALID_SECTION_TYPE, /* Invalid ELF section header type */ + ELF_E_NOT_COMPRESSED, /* Section is not compressed */ ELF_E_NUM /* Max error number */ }; /* * Flags defined by the API. */ #define ELF_F_LAYOUT 0x001U /* application will layout the file */ #define ELF_F_DIRTY 0x002U /* a section or ELF file is dirty */ /* ELF(3) API extensions. */ #define ELF_F_ARCHIVE 0x100U /* archive creation */ #define ELF_F_ARCHIVE_SYSV 0x200U /* SYSV style archive */ #ifdef __cplusplus extern "C" { #endif Elf *elf_begin(int _fd, Elf_Cmd _cmd, Elf *_elf); int elf_cntl(Elf *_elf, Elf_Cmd _cmd); int elf_end(Elf *_elf); const char *elf_errmsg(int _error); int elf_errno(void); void elf_fill(int _fill); unsigned int elf_flagarhdr(Elf_Arhdr *_arh, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagdata(Elf_Data *_data, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagehdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagelf(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagphdr(Elf *_elf, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagscn(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags); unsigned int elf_flagshdr(Elf_Scn *_scn, Elf_Cmd _cmd, unsigned int _flags); Elf_Arhdr *elf_getarhdr(Elf *_elf); Elf_Arsym *elf_getarsym(Elf *_elf, size_t *_ptr); off_t elf_getbase(Elf *_elf); Elf_Data *elf_getdata(Elf_Scn *, Elf_Data *); char *elf_getident(Elf *_elf, size_t *_ptr); int elf_getphdrnum(Elf *_elf, size_t *_dst); int elf_getphnum(Elf *_elf, size_t *_dst); /* Deprecated */ Elf_Scn *elf_getscn(Elf *_elf, size_t _index); int elf_getshdrnum(Elf *_elf, size_t *_dst); int elf_getshnum(Elf *_elf, size_t *_dst); /* Deprecated */ int elf_getshdrstrndx(Elf *_elf, size_t *_dst); int elf_getshstrndx(Elf *_elf, size_t *_dst); /* Deprecated */ unsigned long elf_hash(const char *_name); Elf_Kind elf_kind(Elf *_elf); Elf *elf_memory(char *_image, size_t _size); size_t elf_ndxscn(Elf_Scn *_scn); Elf_Data *elf_newdata(Elf_Scn *_scn); Elf_Scn *elf_newscn(Elf *_elf); Elf_Scn *elf_nextscn(Elf *_elf, Elf_Scn *_scn); Elf_Cmd elf_next(Elf *_elf); Elf *elf_open(int _fd); Elf *elf_openmemory(char *_image, size_t _size); off_t elf_rand(Elf *_elf, off_t _off); Elf_Data *elf_rawdata(Elf_Scn *_scn, Elf_Data *_data); char *elf_rawfile(Elf *_elf, size_t *_size); int elf_setshstrndx(Elf *_elf, size_t _shnum); char *elf_strptr(Elf *_elf, size_t _section, size_t _offset); off_t elf_update(Elf *_elf, Elf_Cmd _cmd); unsigned int elf_version(unsigned int _version); long elf32_checksum(Elf *_elf); size_t elf32_fsize(Elf_Type _type, size_t _count, unsigned int _version); +Elf32_Chdr *elf32_getchdr(Elf_Scn *_scn); Elf32_Ehdr *elf32_getehdr(Elf *_elf); Elf32_Phdr *elf32_getphdr(Elf *_elf); Elf32_Shdr *elf32_getshdr(Elf_Scn *_scn); Elf32_Ehdr *elf32_newehdr(Elf *_elf); Elf32_Phdr *elf32_newphdr(Elf *_elf, size_t _count); Elf_Data *elf32_xlatetof(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); Elf_Data *elf32_xlatetom(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); long elf64_checksum(Elf *_elf); size_t elf64_fsize(Elf_Type _type, size_t _count, unsigned int _version); +Elf64_Chdr *elf64_getchdr(Elf_Scn *_scn); Elf64_Ehdr *elf64_getehdr(Elf *_elf); Elf64_Phdr *elf64_getphdr(Elf *_elf); Elf64_Shdr *elf64_getshdr(Elf_Scn *_scn); Elf64_Ehdr *elf64_newehdr(Elf *_elf); Elf64_Phdr *elf64_newphdr(Elf *_elf, size_t _count); Elf_Data *elf64_xlatetof(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); Elf_Data *elf64_xlatetom(Elf_Data *_dst, const Elf_Data *_src, unsigned int _enc); #ifdef __cplusplus } #endif #endif /* _LIBELF_H_ */ Index: stable/12/contrib/elftoolchain/libelf/libelf_chdr.c =================================================================== --- stable/12/contrib/elftoolchain/libelf/libelf_chdr.c (nonexistent) +++ stable/12/contrib/elftoolchain/libelf/libelf_chdr.c (revision 367462) @@ -0,0 +1,104 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020 The FreeBSD Foundation + * + * This software was developed by Tiger Gao under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "_libelf.h" + +void * +_libelf_getchdr(Elf_Scn *s, int ec) +{ + Elf *e; + void *sh; + Elf32_Shdr *sh32; + Elf64_Shdr *sh64; + + sh32 = NULL; + sh64 = NULL; + + if (s == NULL || (e = s->s_elf) == NULL || e->e_kind != ELF_K_ELF) { + LIBELF_SET_ERROR(ARGUMENT, 0); + return (NULL); + } + + if (ec == ELFCLASSNONE) { + ec = e->e_class; + } else if (ec != e->e_class) { + LIBELF_SET_ERROR(CLASS, 0); + return (NULL); + } + + if ((sh = _libelf_getshdr(s, ec)) == NULL) { + LIBELF_SET_ERROR(HEADER, 0); + return (NULL); + } + + if (ec == ELFCLASS32) { + sh32 = (Elf32_Shdr *)sh; + if ((sh32->sh_flags & SHF_ALLOC) != 0) { + LIBELF_SET_ERROR(INVALID_SECTION_FLAGS, 0); + return (NULL); + } + + if (sh32->sh_type == SHT_NULL || sh32->sh_type == SHT_NOBITS) { + LIBELF_SET_ERROR(INVALID_SECTION_TYPE, 0); + return (NULL); + } + + if ((sh32->sh_flags & SHF_COMPRESSED) == 0) { + LIBELF_SET_ERROR(NOT_COMPRESSED, 0); + return (NULL); + } + } else { + sh64 = (Elf64_Shdr *)sh; + if ((sh64->sh_flags & SHF_ALLOC) != 0) { + LIBELF_SET_ERROR(INVALID_SECTION_FLAGS, 0); + return (NULL); + } + + if (sh64->sh_type == SHT_NULL || sh64->sh_type == SHT_NOBITS) { + LIBELF_SET_ERROR(INVALID_SECTION_TYPE, 0); + return (NULL); + } + + if ((sh64->sh_flags & SHF_COMPRESSED) == 0) { + LIBELF_SET_ERROR(NOT_COMPRESSED, 0); + return (NULL); + } + } + + Elf_Data *d = elf_getdata(s, NULL); + + if (!d) + return (NULL); + + return ((void *)d->d_buf); +} Property changes on: stable/12/contrib/elftoolchain/libelf/libelf_chdr.c ___________________________________________________________________ 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: stable/12/contrib/elftoolchain/libelf/libelf_convert.m4 =================================================================== --- stable/12/contrib/elftoolchain/libelf/libelf_convert.m4 (revision 367461) +++ stable/12/contrib/elftoolchain/libelf/libelf_convert.m4 (revision 367462) @@ -1,1090 +1,1090 @@ /*- * Copyright (c) 2006-2011 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "_libelf.h" ELFTC_VCSID("$Id: libelf_convert.m4 3712 2019-03-16 22:23:34Z jkoshy $"); /* WARNING: GENERATED FROM __file__. */ divert(-1) # Generate conversion routines for converting between in-memory and # file representations of Elf data structures. # # These conversions use the type information defined in `elf_types.m4'. include(SRCDIR`/elf_types.m4') # For the purposes of generating conversion code, ELF types may be # classified according to the following characteristics: # # 1. Whether the ELF type can be directly mapped to an integral C # language type. For example, the ELF_T_WORD type maps directly to # a 'uint32_t', but ELF_T_GNUHASH lacks a matching C type. # # 2. Whether the type has word size dependent variants. For example, # ELT_T_EHDR is represented using C types Elf32_Ehdr and El64_Ehdr, # and the ELF_T_ADDR and ELF_T_OFF types have integral C types that # can be 32- or 64- bit wide. # # 3. Whether the ELF types has a fixed representation or not. For # example, the ELF_T_SYM type has a fixed size file representation, # some types like ELF_T_NOTE and ELF_T_GNUHASH use a variable size # representation. # # We use m4 macros to generate conversion code for ELF types that have # a fixed size representation. Conversion functions for the remaining # types are coded by hand. # #* Handling File and Memory Representations # # `In-memory' representations of an Elf data structure use natural # alignments and native byte ordering. This allows pointer arithmetic # and casting to work as expected. On the other hand, the `file' # representation of an ELF data structure could possibly be packed # tighter than its `in-memory' representation, and could be of a # differing byte order. Reading ELF objects that are members of `ar' # archives present an additional complication: `ar' pads file data to # even addresses, so file data structures in an archive member # residing inside an `ar' archive could be at misaligned memory # addresses when brought into memory. # # In summary, casting the `char *' pointers that point to memory # representations (i.e., source pointers for the *_tof() functions and # the destination pointers for the *_tom() functions), is safe, as # these pointers should be correctly aligned for the memory type # already. However, pointers to file representations have to be # treated as being potentially unaligned and no casting can be done. # NOCVT(TYPE) -- Do not generate the cvt[] structure entry for TYPE define(`NOCVT',`define(`NOCVT_'$1,1)') # NOFUNC(TYPE) -- Do not generate a conversion function for TYPE define(`NOFUNC',`define(`NOFUNC_'$1,1)') # IGNORE(TYPE) -- Completely ignore the type. define(`IGNORE',`NOCVT($1)NOFUNC($1)') # Mark ELF types that should not be processed by the M4 macros below. # Types for which we use functions with non-standard names. IGNORE(`BYTE') # Uses a wrapper around memcpy(). IGNORE(`NOTE') # Not a fixed size type. # Types for which we supply hand-coded functions. NOFUNC(`GNUHASH') # A type with complex internal structure. NOFUNC(`VDEF') # See MAKE_VERSION_CONVERTERS below. NOFUNC(`VNEED') # .. # Unimplemented types. IGNORE(`MOVEP') # ELF types that don't exist in a 32-bit world. NOFUNC(`XWORD32') NOFUNC(`SXWORD32') # `Primitive' ELF types are those that are an alias for an integral # type. As they have no internal structure, they can be copied using # a `memcpy()', and byteswapped in straightforward way. # # Mark all ELF types that directly map to integral C types. define(`PRIM_ADDR', 1) define(`PRIM_BYTE', 1) define(`PRIM_HALF', 1) define(`PRIM_LWORD', 1) define(`PRIM_OFF', 1) define(`PRIM_SWORD', 1) define(`PRIM_SXWORD', 1) define(`PRIM_WORD', 1) define(`PRIM_XWORD', 1) # Note the primitive types that are size-dependent. define(`SIZEDEP_ADDR', 1) define(`SIZEDEP_OFF', 1) # Generate conversion functions for primitive types. # # Macro use: MAKEPRIMFUNCS(ELFTYPE,CTYPE,TYPESIZE,SYMSIZE) # `$1': Name of the ELF type. # `$2': C structure name suffix. # `$3': ELF class specifier for types, one of [`32', `64']. # `$4': Additional ELF class specifier, one of [`', `32', `64']. # # Generates a pair of conversion functions. define(`MAKEPRIMFUNCS',` static int _libelf_cvt_$1$4_tof(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { Elf$3_$2 t, *s = (Elf$3_$2 *) (uintptr_t) src; size_t c; (void) dsz; if (!byteswap) { (void) memcpy(dst, src, count * sizeof(*s)); return (1); } for (c = 0; c < count; c++) { t = *s++; SWAP_$1$4(t); WRITE_$1$4(dst,t); } return (1); } static int _libelf_cvt_$1$4_tom(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { Elf$3_$2 t, *d = (Elf$3_$2 *) (uintptr_t) dst; size_t c; if (dsz < count * sizeof(Elf$3_$2)) return (0); if (!byteswap) { (void) memcpy(dst, src, count * sizeof(*d)); return (1); } for (c = 0; c < count; c++) { READ_$1$4(src,t); SWAP_$1$4(t); *d++ = t; } return (1); } ') # # Handling composite ELF types # # SWAP_FIELD(FIELDNAME,ELFTYPE) -- Generate code to swap one field. define(`SWAP_FIELD', `ifdef(`SIZEDEP_'$2, `SWAP_$2'SZ()`(t.$1); ', `SWAP_$2(t.$1); ')') # SWAP_MEMBERS(STRUCT) -- Iterate over a structure definition. define(`SWAP_MEMBERS', `ifelse($#,1,`/**/', `SWAP_FIELD($1)SWAP_MEMBERS(shift($@))')') # SWAP_STRUCT(CTYPE,SIZE) -- Generate code to swap an ELF structure. define(`SWAP_STRUCT', `pushdef(`SZ',$2)/* Swap an Elf$2_$1 */ SWAP_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') # WRITE_FIELD(ELFTYPE,FIELDNAME) -- Generate code to write one field. define(`WRITE_FIELD', `ifdef(`SIZEDEP_'$2, `WRITE_$2'SZ()`(dst,t.$1); ', `WRITE_$2(dst,t.$1); ')') # WRITE_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition. define(`WRITE_MEMBERS', `ifelse($#,1,`/**/', `WRITE_FIELD($1)WRITE_MEMBERS(shift($@))')') # WRITE_STRUCT(CTYPE,SIZE) -- Generate code to write out an ELF structure. define(`WRITE_STRUCT', `pushdef(`SZ',$2)/* Write an Elf$2_$1 */ WRITE_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') # READ_FIELD(ELFTYPE,CTYPE) -- Generate code to read one field. define(`READ_FIELD', `ifdef(`SIZEDEP_'$2, `READ_$2'SZ()`(s,t.$1); ', `READ_$2(s,t.$1); ')') # READ_MEMBERS(ELFTYPELIST) -- Iterate over a structure definition. define(`READ_MEMBERS', `ifelse($#,1,`/**/', `READ_FIELD($1)READ_MEMBERS(shift($@))')') # READ_STRUCT(CTYPE,SIZE) -- Generate code to read an ELF structure. define(`READ_STRUCT', `pushdef(`SZ',$2)/* Read an Elf$2_$1 */ READ_MEMBERS(Elf$2_$1_DEF)popdef(`SZ')') # MAKECOMPFUNCS -- Generate converters for composite ELF structures. # # When converting data to file representation, the source pointer will # be naturally aligned for a data structure's in-memory # representation. When converting data to memory, the destination # pointer will be similarly aligned. # # For in-place conversions, when converting to file representations, # the source buffer is large enough to hold `file' data. When # converting from file to memory, we need to be careful to work # `backwards', to avoid overwriting unconverted data. # # Macro use: # `$1': Name of the ELF type. # `$2': C structure name suffix. # `$3': ELF class specifier, one of [`', `32', `64'] define(`MAKECOMPFUNCS', `ifdef(`NOFUNC_'$1$3,`',` static int _libelf_cvt_$1$3_tof(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { Elf$3_$2 t, *s; size_t c; (void) dsz; s = (Elf$3_$2 *) (uintptr_t) src; for (c = 0; c < count; c++) { t = *s++; if (byteswap) { SWAP_STRUCT($2,$3) } WRITE_STRUCT($2,$3) } return (1); } static int _libelf_cvt_$1$3_tom(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { Elf$3_$2 t, *d; unsigned char *s,*s0; size_t fsz; fsz = elf$3_fsize(ELF_T_$1, (size_t) 1, EV_CURRENT); d = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1); s0 = src + (count - 1) * fsz; if (dsz < count * sizeof(Elf$3_$2)) return (0); while (count--) { s = s0; READ_STRUCT($2,$3) if (byteswap) { SWAP_STRUCT($2,$3) } *d-- = t; s0 -= fsz; } return (1); } ')') # MAKE_TYPE_CONVERTER(ELFTYPE,CTYPE) # # Make type convertor functions from the type definition # of the ELF type: # - Skip convertors marked as `NOFUNC'. # - Invoke `MAKEPRIMFUNCS' or `MAKECOMPFUNCS' as appropriate. define(`MAKE_TYPE_CONVERTER', `ifdef(`NOFUNC_'$1,`', `ifdef(`PRIM_'$1, `ifdef(`SIZEDEP_'$1, `MAKEPRIMFUNCS($1,$2,32,32)dnl MAKEPRIMFUNCS($1,$2,64,64)', `MAKEPRIMFUNCS($1,$2,64)')', `MAKECOMPFUNCS($1,$2,32)dnl MAKECOMPFUNCS($1,$2,64)')')') # MAKE_TYPE_CONVERTERS(ELFTYPELIST) -- Generate conversion functions. define(`MAKE_TYPE_CONVERTERS', `ifelse($#,1,`', `MAKE_TYPE_CONVERTER($1)MAKE_TYPE_CONVERTERS(shift($@))')') # # Macros to generate entries for the table of convertors. # # CONV(ELFTYPE,SIZE,DIRECTION) # # Generate the name of a convertor function. define(`CONV', `ifdef(`NOFUNC_'$1$2, `.$3$2 = NULL', `ifdef(`PRIM_'$1, `ifdef(`SIZEDEP_'$1, `.$3$2 = _libelf_cvt_$1$2_$3', `.$3$2 = _libelf_cvt_$1_$3')', `.$3$2 = _libelf_cvt_$1$2_$3')')') # CONVERTER_NAME(ELFTYPE) # # Generate the contents of one `struct cvt' instance. define(`CONVERTER_NAME', `ifdef(`NOCVT_'$1,`', ` [ELF_T_$1] = { CONV($1,32,tof), CONV($1,32,tom), CONV($1,64,tof), CONV($1,64,tom) }, ')') # CONVERTER_NAMES(ELFTYPELIST) # # Generate the `struct cvt[]' array. define(`CONVERTER_NAMES', `ifelse($#,1,`', `CONVERTER_NAME($1)CONVERTER_NAMES(shift($@))')') # # Handling ELF version sections. # # _FSZ(FIELD,BASETYPE) - return the file size for a field. define(`_FSZ', `ifelse($2,`HALF',2, $2,`WORD',4)') # FSZ(STRUCT) - determine the file size of a structure. define(`FSZ', `ifelse($#,1,0, `eval(_FSZ($1) + FSZ(shift($@)))')') # MAKE_VERSION_CONVERTERS(TYPE,BASE,AUX,PFX) -- Generate conversion # functions for versioning structures. define(`MAKE_VERSION_CONVERTERS', `MAKE_VERSION_CONVERTER($1,$2,$3,$4,32) MAKE_VERSION_CONVERTER($1,$2,$3,$4,64)') # MAKE_VERSION_CONVERTOR(TYPE,CBASE,CAUX,PFX,SIZE) -- Generate a # conversion function. define(`MAKE_VERSION_CONVERTER',` static int _libelf_cvt_$1$5_tof(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { Elf$5_$2 t; Elf$5_$3 a; const size_t verfsz = FSZ(Elf$5_$2_DEF); const size_t auxfsz = FSZ(Elf$5_$3_DEF); const size_t vermsz = sizeof(Elf$5_$2); const size_t auxmsz = sizeof(Elf$5_$3); unsigned char * const dstend = dst + dsz; unsigned char * const srcend = src + count; unsigned char *dtmp, *dstaux, *srcaux; Elf$5_Word aux, anext, cnt, vnext; for (dtmp = dst, vnext = ~0U; vnext != 0 && dtmp + verfsz <= dstend && src + vermsz <= srcend; dtmp += vnext, src += vnext) { /* Read in an Elf$5_$2 structure. */ t = *((Elf$5_$2 *) (uintptr_t) src); aux = t.$4_aux; cnt = t.$4_cnt; vnext = t.$4_next; if (byteswap) { SWAP_STRUCT($2, $5) } dst = dtmp; WRITE_STRUCT($2, $5) if (aux < verfsz) return (0); /* Process AUX entries. */ for (anext = ~0U, dstaux = dtmp + aux, srcaux = src + aux; cnt != 0 && anext != 0 && dstaux + auxfsz <= dstend && srcaux + auxmsz <= srcend; dstaux += anext, srcaux += anext, cnt--) { /* Read in an Elf$5_$3 structure. */ a = *((Elf$5_$3 *) (uintptr_t) srcaux); anext = a.$4a_next; if (byteswap) { pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t') } dst = dstaux; pushdef(`t',`a')WRITE_STRUCT($3, $5)popdef(`t') } if (anext || cnt) return (0); } if (vnext) return (0); return (1); } static int _libelf_cvt_$1$5_tom(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { Elf$5_$2 t, *dp; Elf$5_$3 a, *ap; const size_t verfsz = FSZ(Elf$5_$2_DEF); const size_t auxfsz = FSZ(Elf$5_$3_DEF); const size_t vermsz = sizeof(Elf$5_$2); const size_t auxmsz = sizeof(Elf$5_$3); unsigned char * const dstend = dst + dsz; unsigned char * const srcend = src + count; unsigned char *dstaux, *s, *srcaux, *stmp; Elf$5_Word aux, anext, cnt, vnext; for (stmp = src, vnext = ~0U; vnext != 0 && stmp + verfsz <= srcend && dst + vermsz <= dstend; stmp += vnext, dst += vnext) { /* Read in a $1 structure. */ s = stmp; READ_STRUCT($2, $5) if (byteswap) { SWAP_STRUCT($2, $5) } dp = (Elf$5_$2 *) (uintptr_t) dst; *dp = t; aux = t.$4_aux; cnt = t.$4_cnt; vnext = t.$4_next; if (aux < vermsz) return (0); /* Process AUX entries. */ for (anext = ~0U, dstaux = dst + aux, srcaux = stmp + aux; cnt != 0 && anext != 0 && dstaux + auxmsz <= dstend && srcaux + auxfsz <= srcend; dstaux += anext, srcaux += anext, cnt--) { s = srcaux; pushdef(`t',`a')READ_STRUCT($3, $5)popdef(`t') if (byteswap) { pushdef(`t',`a')SWAP_STRUCT($3, $5)popdef(`t') } anext = a.$4a_next; ap = ((Elf$5_$3 *) (uintptr_t) dstaux); *ap = a; } if (anext || cnt) return (0); } if (vnext) return (0); return (1); }') divert(0) /* * C macros to byte swap integral quantities. */ #define SWAP_BYTE(X) do { (void) (X); } while (0) #define SWAP_IDENT(X) do { (void) (X); } while (0) #define SWAP_HALF(X) do { \ uint16_t _x = (uint16_t) (X); \ uint32_t _t = _x & 0xFFU; \ _t <<= 8U; _x >>= 8U; _t |= _x & 0xFFU; \ (X) = (uint16_t) _t; \ } while (0) #define _SWAP_WORD(X, T) do { \ uint32_t _x = (uint32_t) (X); \ uint32_t _t = _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ (X) = (T) _t; \ } while (0) #define SWAP_ADDR32(X) _SWAP_WORD(X, Elf32_Addr) #define SWAP_OFF32(X) _SWAP_WORD(X, Elf32_Off) #define SWAP_SWORD(X) _SWAP_WORD(X, Elf32_Sword) #define SWAP_WORD(X) _SWAP_WORD(X, Elf32_Word) #define _SWAP_WORD64(X, T) do { \ uint64_t _x = (uint64_t) (X); \ uint64_t _t = _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ _t <<= 8; _x >>= 8; _t |= _x & 0xFF; \ (X) = (T) _t; \ } while (0) #define SWAP_ADDR64(X) _SWAP_WORD64(X, Elf64_Addr) #define SWAP_LWORD(X) _SWAP_WORD64(X, Elf64_Lword) #define SWAP_OFF64(X) _SWAP_WORD64(X, Elf64_Off) #define SWAP_SXWORD(X) _SWAP_WORD64(X, Elf64_Sxword) #define SWAP_XWORD(X) _SWAP_WORD64(X, Elf64_Xword) /* * C macros to write out various integral values. * * Note: * - The destination pointer could be unaligned. * - Values are written out in native byte order. * - The destination pointer is incremented after the write. */ #define WRITE_BYTE(P,X) do { \ unsigned char *const _p = (unsigned char *) (P); \ _p[0] = (unsigned char) (X); \ (P) = _p + 1; \ } while (0) #define WRITE_HALF(P,X) do { \ uint16_t _t = (X); \ unsigned char *const _p = (unsigned char *) (P); \ const unsigned char *const _q = (unsigned char *) &_t; \ _p[0] = _q[0]; \ _p[1] = _q[1]; \ (P) = _p + 2; \ } while (0) #define WRITE_WORD(P,X) do { \ uint32_t _t = (uint32_t) (X); \ unsigned char *const _p = (unsigned char *) (P); \ const unsigned char *const _q = (unsigned char *) &_t; \ _p[0] = _q[0]; \ _p[1] = _q[1]; \ _p[2] = _q[2]; \ _p[3] = _q[3]; \ (P) = _p + 4; \ } while (0) #define WRITE_ADDR32(P,X) WRITE_WORD(P,X) #define WRITE_OFF32(P,X) WRITE_WORD(P,X) #define WRITE_SWORD(P,X) WRITE_WORD(P,X) #define WRITE_WORD64(P,X) do { \ uint64_t _t = (uint64_t) (X); \ unsigned char *const _p = (unsigned char *) (P); \ const unsigned char *const _q = (unsigned char *) &_t; \ _p[0] = _q[0]; \ _p[1] = _q[1]; \ _p[2] = _q[2]; \ _p[3] = _q[3]; \ _p[4] = _q[4]; \ _p[5] = _q[5]; \ _p[6] = _q[6]; \ _p[7] = _q[7]; \ (P) = _p + 8; \ } while (0) #define WRITE_ADDR64(P,X) WRITE_WORD64(P,X) #define WRITE_LWORD(P,X) WRITE_WORD64(P,X) #define WRITE_OFF64(P,X) WRITE_WORD64(P,X) #define WRITE_SXWORD(P,X) WRITE_WORD64(P,X) #define WRITE_XWORD(P,X) WRITE_WORD64(P,X) #define WRITE_IDENT(P,X) do { \ (void) memcpy((P), (X), sizeof((X))); \ (P) = (P) + EI_NIDENT; \ } while (0) /* * C macros to read in various integral values. * * Note: * - The source pointer could be unaligned. * - Values are read in native byte order. * - The source pointer is incremented appropriately. */ #define READ_BYTE(P,X) do { \ const unsigned char *const _p = \ (const unsigned char *) (P); \ (X) = _p[0]; \ (P) = (P) + 1; \ } while (0) #define READ_HALF(P,X) do { \ uint16_t _t; \ unsigned char *const _q = (unsigned char *) &_t; \ const unsigned char *const _p = \ (const unsigned char *) (P); \ _q[0] = _p[0]; \ _q[1] = _p[1]; \ (P) = (P) + 2; \ (X) = _t; \ } while (0) #define _READ_WORD(P,X,T) do { \ uint32_t _t; \ unsigned char *const _q = (unsigned char *) &_t; \ const unsigned char *const _p = \ (const unsigned char *) (P); \ _q[0] = _p[0]; \ _q[1] = _p[1]; \ _q[2] = _p[2]; \ _q[3] = _p[3]; \ (P) = (P) + 4; \ (X) = (T) _t; \ } while (0) #define READ_ADDR32(P,X) _READ_WORD(P, X, Elf32_Addr) #define READ_OFF32(P,X) _READ_WORD(P, X, Elf32_Off) #define READ_SWORD(P,X) _READ_WORD(P, X, Elf32_Sword) #define READ_WORD(P,X) _READ_WORD(P, X, Elf32_Word) #define _READ_WORD64(P,X,T) do { \ uint64_t _t; \ unsigned char *const _q = (unsigned char *) &_t; \ const unsigned char *const _p = \ (const unsigned char *) (P); \ _q[0] = _p[0]; \ _q[1] = _p[1]; \ _q[2] = _p[2]; \ _q[3] = _p[3]; \ _q[4] = _p[4]; \ _q[5] = _p[5]; \ _q[6] = _p[6]; \ _q[7] = _p[7]; \ (P) = (P) + 8; \ (X) = (T) _t; \ } while (0) #define READ_ADDR64(P,X) _READ_WORD64(P, X, Elf64_Addr) #define READ_LWORD(P,X) _READ_WORD64(P, X, Elf64_Lword) #define READ_OFF64(P,X) _READ_WORD64(P, X, Elf64_Off) #define READ_SXWORD(P,X) _READ_WORD64(P, X, Elf64_Sxword) #define READ_XWORD(P,X) _READ_WORD64(P, X, Elf64_Xword) #define READ_IDENT(P,X) do { \ (void) memcpy((X), (P), sizeof((X))); \ (P) = (P) + EI_NIDENT; \ } while (0) #define ROUNDUP2(V,N) (V) = ((((V) + (N) - 1)) & ~((N) - 1)) /*[*/ MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST) MAKE_VERSION_CONVERTERS(VDEF,Verdef,Verdaux,vd) MAKE_VERSION_CONVERTERS(VNEED,Verneed,Vernaux,vn) /*]*/ /* * Sections of type ELF_T_BYTE are never byteswapped, consequently a * simple memcpy suffices for both directions of conversion. */ static int _libelf_cvt_BYTE_tox(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { (void) byteswap; if (dsz < count) return (0); if (dst != src) (void) memcpy(dst, src, count); return (1); } /* * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit * words. Bloom filter data comes next, followed by hash buckets and the * hash chain. * * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit * wide on ELFCLASS32 objects. The other objects in this section are 32 * bits wide. * * Argument `srcsz' denotes the number of bytes to be converted. In the * 32-bit case we need to translate `srcsz' to a count of 32-bit words. */ static int _libelf_cvt_GNUHASH32_tom(unsigned char *dst, size_t dsz, unsigned char *src, size_t srcsz, int byteswap) { return (_libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t), byteswap)); } static int _libelf_cvt_GNUHASH32_tof(unsigned char *dst, size_t dsz, unsigned char *src, size_t srcsz, int byteswap) { return (_libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t), byteswap)); } static int _libelf_cvt_GNUHASH64_tom(unsigned char *dst, size_t dsz, unsigned char *src, size_t srcsz, int byteswap) { size_t sz; uint64_t t64, *bloom64; Elf_GNU_Hash_Header *gh; uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32; uint32_t *buckets, *chains; sz = 4 * sizeof(uint32_t); /* File header is 4 words long. */ if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz) return (0); /* Read in the section header and byteswap if needed. */ READ_WORD(src, nbuckets); READ_WORD(src, symndx); READ_WORD(src, maskwords); READ_WORD(src, shift2); srcsz -= sz; if (byteswap) { SWAP_WORD(nbuckets); SWAP_WORD(symndx); SWAP_WORD(maskwords); SWAP_WORD(shift2); } /* Check source buffer and destination buffer sizes. */ sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t); if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header)) return (0); gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst; gh->gh_nbuckets = nbuckets; gh->gh_symndx = symndx; gh->gh_maskwords = maskwords; gh->gh_shift2 = shift2; dsz -= sizeof(Elf_GNU_Hash_Header); dst += sizeof(Elf_GNU_Hash_Header); bloom64 = (uint64_t *) (uintptr_t) dst; /* Copy bloom filter data. */ for (n = 0; n < maskwords; n++) { READ_XWORD(src, t64); if (byteswap) SWAP_XWORD(t64); bloom64[n] = t64; } /* The hash buckets follows the bloom filter. */ dst += maskwords * sizeof(uint64_t); buckets = (uint32_t *) (uintptr_t) dst; for (n = 0; n < nbuckets; n++) { READ_WORD(src, t32); if (byteswap) SWAP_WORD(t32); buckets[n] = t32; } dst += nbuckets * sizeof(uint32_t); /* The hash chain follows the hash buckets. */ dsz -= sz; srcsz -= sz; if (dsz < srcsz) /* Destination lacks space. */ return (0); nchains = (uint32_t) (srcsz / sizeof(uint32_t)); chains = (uint32_t *) (uintptr_t) dst; for (n = 0; n < nchains; n++) { READ_WORD(src, t32); if (byteswap) SWAP_WORD(t32); *chains++ = t32; } return (1); } static int _libelf_cvt_GNUHASH64_tof(unsigned char *dst, size_t dsz, unsigned char *src, size_t srcsz, int byteswap) { uint32_t *s32; size_t sz, hdrsz; uint64_t *s64, t64; Elf_GNU_Hash_Header *gh; uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32; hdrsz = 4 * sizeof(uint32_t); /* Header is 4x32 bits. */ if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header)) return (0); gh = (Elf_GNU_Hash_Header *) (uintptr_t) src; t0 = nbuckets = gh->gh_nbuckets; t1 = gh->gh_symndx; t2 = maskwords = gh->gh_maskwords; t3 = gh->gh_shift2; src += sizeof(Elf_GNU_Hash_Header); srcsz -= sizeof(Elf_GNU_Hash_Header); dsz -= hdrsz; sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords * sizeof(uint64_t); if (srcsz < sz || dsz < sz) return (0); /* Write out the header. */ if (byteswap) { SWAP_WORD(t0); SWAP_WORD(t1); SWAP_WORD(t2); SWAP_WORD(t3); } WRITE_WORD(dst, t0); WRITE_WORD(dst, t1); WRITE_WORD(dst, t2); WRITE_WORD(dst, t3); /* Copy the bloom filter and the hash table. */ s64 = (uint64_t *) (uintptr_t) src; for (n = 0; n < maskwords; n++) { t64 = *s64++; if (byteswap) SWAP_XWORD(t64); WRITE_WORD64(dst, t64); } s32 = (uint32_t *) s64; for (n = 0; n < nbuckets; n++) { t32 = *s32++; if (byteswap) SWAP_WORD(t32); WRITE_WORD(dst, t32); } srcsz -= sz; dsz -= sz; /* Copy out the hash chains. */ if (dsz < srcsz) return (0); nchains = (uint32_t) (srcsz / sizeof(uint32_t)); for (n = 0; n < nchains; n++) { t32 = *s32++; if (byteswap) SWAP_WORD(t32); WRITE_WORD(dst, t32); } return (1); } /* * Elf_Note structures comprise a fixed size header followed by variable * length strings. The fixed size header needs to be byte swapped, but * not the strings. * * Argument `count' denotes the total number of bytes to be converted. * The destination buffer needs to be at least `count' bytes in size. */ static int _libelf_cvt_NOTE_tom(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { uint32_t namesz, descsz, type; Elf_Note *en; size_t sz, hdrsz; if (dsz < count) /* Destination buffer is too small. */ return (0); hdrsz = 3 * sizeof(uint32_t); if (count < hdrsz) /* Source too small. */ return (0); if (!byteswap) { (void) memcpy(dst, src, count); return (1); } /* Process all notes in the section. */ while (count > hdrsz) { /* Read the note header. */ READ_WORD(src, namesz); READ_WORD(src, descsz); READ_WORD(src, type); /* Translate. */ SWAP_WORD(namesz); SWAP_WORD(descsz); SWAP_WORD(type); /* Copy out the translated note header. */ en = (Elf_Note *) (uintptr_t) dst; en->n_namesz = namesz; en->n_descsz = descsz; en->n_type = type; dsz -= sizeof(Elf_Note); dst += sizeof(Elf_Note); count -= hdrsz; ROUNDUP2(namesz, 4U); ROUNDUP2(descsz, 4U); sz = namesz + descsz; if (count < sz || dsz < sz) /* Buffers are too small. */ return (0); (void) memcpy(dst, src, sz); src += sz; dst += sz; count -= sz; dsz -= sz; } return (1); } static int _libelf_cvt_NOTE_tof(unsigned char *dst, size_t dsz, unsigned char *src, size_t count, int byteswap) { uint32_t namesz, descsz, type; Elf_Note *en; size_t sz; if (dsz < count) return (0); if (!byteswap) { (void) memcpy(dst, src, count); return (1); } while (count > sizeof(Elf_Note)) { en = (Elf_Note *) (uintptr_t) src; namesz = en->n_namesz; descsz = en->n_descsz; type = en->n_type; sz = namesz; ROUNDUP2(sz, 4U); sz += descsz; ROUNDUP2(sz, 4U); SWAP_WORD(namesz); SWAP_WORD(descsz); SWAP_WORD(type); WRITE_WORD(dst, namesz); WRITE_WORD(dst, descsz); WRITE_WORD(dst, type); src += sizeof(Elf_Note); count -= sizeof(Elf_Note); if (count < sz) - sz = count; + return (0); (void) memcpy(dst, src, sz); src += sz; dst += sz; count -= sz; } return (1); } struct converters { int (*tof32)(unsigned char *dst, size_t dsz, unsigned char *src, size_t cnt, int byteswap); int (*tom32)(unsigned char *dst, size_t dsz, unsigned char *src, size_t cnt, int byteswap); int (*tof64)(unsigned char *dst, size_t dsz, unsigned char *src, size_t cnt, int byteswap); int (*tom64)(unsigned char *dst, size_t dsz, unsigned char *src, size_t cnt, int byteswap); }; static struct converters cvt[ELF_T_NUM] = { /*[*/ CONVERTER_NAMES(ELF_TYPE_LIST) /*]*/ /* * Types that need hand-coded converters follow. */ [ELF_T_BYTE] = { .tof32 = _libelf_cvt_BYTE_tox, .tom32 = _libelf_cvt_BYTE_tox, .tof64 = _libelf_cvt_BYTE_tox, .tom64 = _libelf_cvt_BYTE_tox }, [ELF_T_NOTE] = { .tof32 = _libelf_cvt_NOTE_tof, .tom32 = _libelf_cvt_NOTE_tom, .tof64 = _libelf_cvt_NOTE_tof, .tom64 = _libelf_cvt_NOTE_tom } }; /* * Return a translator function for the specified ELF section type, conversion * direction, ELF class and ELF machine. */ _libelf_translator_function * _libelf_get_translator(Elf_Type t, int direction, int elfclass, int elfmachine) { assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY); assert(t >= ELF_T_FIRST && t <= ELF_T_LAST); /* TODO: Handle MIPS64 REL{,A} sections (ticket #559). */ (void) elfmachine; return ((elfclass == ELFCLASS32) ? (direction == ELF_TOFILE ? cvt[t].tof32 : cvt[t].tom32) : (direction == ELF_TOFILE ? cvt[t].tof64 : cvt[t].tom64)); } Index: stable/12/contrib/elftoolchain/libelftc/_libelftc.h =================================================================== --- stable/12/contrib/elftoolchain/libelftc/_libelftc.h (revision 367461) +++ stable/12/contrib/elftoolchain/libelftc/_libelftc.h (revision 367462) @@ -1,95 +1,96 @@ /*- * Copyright (c) 2009 Kai Wang * Copyright (c) 2007,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. * * $Id: _libelftc.h 3531 2017-06-05 05:08:43Z kaiwang27 $ */ #ifndef __LIBELFTC_H_ #define __LIBELFTC_H_ #include #include "_elftc.h" struct _Elftc_Bfd_Target { const char *bt_name; /* target name. */ unsigned int bt_type; /* target type. */ unsigned int bt_byteorder; /* elf target byteorder. */ unsigned int bt_elfclass; /* elf target class (32/64bit). */ unsigned int bt_machine; /* elf target arch. */ unsigned int bt_osabi; /* elf target abi. */ }; extern struct _Elftc_Bfd_Target _libelftc_targets[]; /** @brief Dynamic vector data for string. */ struct vector_str { /** Current size */ size_t size; /** Total capacity */ size_t capacity; /** String array */ char **container; }; #define BUFFER_GROWFACTOR 1.618 +#define BUFFER_GROW(x) (((x)+0.5)*BUFFER_GROWFACTOR) #define ELFTC_FAILURE 0 #define ELFTC_ISDIGIT(C) (isdigit((C) & 0xFF)) #define ELFTC_SUCCESS 1 #define VECTOR_DEF_CAPACITY 8 #ifdef __cplusplus extern "C" { #endif char *cpp_demangle_ARM(const char *_org); char *cpp_demangle_gnu2(const char *_org); char *cpp_demangle_gnu3(const char *_org); bool is_cpp_mangled_ARM(const char *_org); bool is_cpp_mangled_gnu2(const char *_org); bool is_cpp_mangled_gnu3(const char *_org); unsigned int libelftc_hash_string(const char *); void vector_str_dest(struct vector_str *_vec); int vector_str_find(const struct vector_str *_vs, const char *_str, size_t _len); char *vector_str_get_flat(const struct vector_str *_vs, size_t *_len); bool vector_str_init(struct vector_str *_vs); bool vector_str_pop(struct vector_str *_vs); bool vector_str_push(struct vector_str *_vs, const char *_str, size_t _len); bool vector_str_push_vector(struct vector_str *_dst, struct vector_str *_org); bool vector_str_push_vector_head(struct vector_str *_dst, struct vector_str *_org); char *vector_str_substr(const struct vector_str *_vs, size_t _begin, size_t _end, size_t *_rlen); #ifdef __cplusplus } #endif #endif /* __LIBELFTC_H */ Index: stable/12/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c =================================================================== --- stable/12/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c (revision 367461) +++ stable/12/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c (revision 367462) @@ -1,3992 +1,3992 @@ /*- * Copyright (c) 2007 Hyogeol Lee * Copyright (c) 2015-2017 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 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 3583 2017-10-15 15:38:47Z emaste $"); /** * @file cpp_demangle.c * @brief Decode IA-64 C++ ABI style implementation. * * IA-64 standard ABI(Itanium C++ ABI) references. * * http://www.codesourcery.com/cxx-abi/abi.html#mangling \n * http://www.codesourcery.com/cxx-abi/abi-mangling.html */ enum type_qualifier { TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT, TYPE_CST, TYPE_VEC, TYPE_RREF }; 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 read_cmd_item { enum read_cmd cmd; void *data; }; struct vector_read_cmd { size_t size, capacity; struct read_cmd_item *r_container; }; enum push_qualifier { PUSH_ALL_QUALIFIER, PUSH_CV_QUALIFIER, PUSH_NON_CV_QUALIFIER, }; struct cpp_demangle_data { struct vector_str output; /* output string vector */ struct vector_str subst; /* substitution string vector */ struct vector_str tmpl; struct vector_str class_type; struct vector_str *cur_output; /* ptr to current output vec */ struct vector_read_cmd cmd; bool mem_rst; /* restrict member function */ bool mem_vat; /* volatile member function */ bool mem_cst; /* const member function */ bool mem_ref; /* lvalue-ref member func */ bool mem_rref; /* rvalue-ref member func */ bool is_tmpl; /* template args */ bool is_functype; /* function type */ bool ref_qualifier; /* ref qualifier */ enum type_qualifier ref_qualifier_type; /* ref qualifier type */ enum push_qualifier push_qualifier; /* which qualifiers to push */ int func_type; const char *cur; /* current mangled name ptr */ const char *last_sname; /* last source name */ }; struct type_delimit { bool paren; bool firstp; }; #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_pop_str(struct cpp_demangle_data *); 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 *, struct vector_type_qualifier *); 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 *); 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 *, struct type_delimit *); 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 struct read_cmd_item *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, void *); 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; struct vector_str ret_type; struct type_delimit td; ssize_t org_len; unsigned int limit; char *rtn; bool has_ret, more_type; 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; has_ret = more_type = false; if (!cpp_demangle_read_encoding(&ddata)) goto clean; /* * Pop function name from substitution candidate list. */ if (*ddata.cur != 0 && ddata.subst.size >= 1) { if (!vector_str_pop(&ddata.subst)) goto clean; } td.paren = false; td.firstp = true; limit = 0; /* * The first type is a return type if we just demangled template * args. (the template args is right next to the function name, * which means it's a template function) */ if (ddata.is_tmpl) { ddata.is_tmpl = false; if (!vector_str_init(&ret_type)) goto clean; ddata.cur_output = &ret_type; has_ret = true; } while (*ddata.cur != '\0') { /* * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4 */ if (*ddata.cur == '@' && *(ddata.cur + 1) == '@') break; if (has_ret) { /* Read return type */ if (!cpp_demangle_read_type(&ddata, NULL)) goto clean; } else { /* Read function arg type */ if (!cpp_demangle_read_type(&ddata, &td)) goto clean; } if (has_ret) { /* Push return type to the beginning */ if (!VEC_PUSH_STR(&ret_type, " ")) goto clean; if (!vector_str_push_vector_head(&ddata.output, &ret_type)) goto clean; ddata.cur_output = &ddata.output; vector_str_dest(&ret_type); has_ret = false; more_type = true; } else if (more_type) more_type = false; if (limit++ > CPP_DEMANGLE_TRY_LIMIT) goto clean; } if (more_type) goto clean; if (ddata.output.size == 0) goto clean; if (td.paren && !VEC_PUSH_STR(&ddata.output, ")")) goto clean; if (ddata.mem_vat && !VEC_PUSH_STR(&ddata.output, " volatile")) goto clean; if (ddata.mem_cst && !VEC_PUSH_STR(&ddata.output, " const")) goto clean; if (ddata.mem_rst && !VEC_PUSH_STR(&ddata.output, " restrict")) goto clean; if (ddata.mem_ref && !VEC_PUSH_STR(&ddata.output, " &")) goto clean; if (ddata.mem_rref && !VEC_PUSH_STR(&ddata.output, " &&")) goto clean; rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL); clean: if (has_ret) vector_str_dest(&ret_type); 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); } 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->subst)) goto clean1; if (!vector_str_init(&d->tmpl)) goto clean2; if (!vector_str_init(&d->class_type)) goto clean3; if (!vector_read_cmd_init(&d->cmd)) goto clean4; assert(d->output.container != NULL); assert(d->subst.container != NULL); assert(d->tmpl.container != NULL); assert(d->class_type.container != NULL); d->mem_rst = false; d->mem_vat = false; d->mem_cst = false; d->mem_ref = false; d->mem_rref = false; d->is_tmpl = false; d->is_functype = false; d->ref_qualifier = false; d->push_qualifier = PUSH_ALL_QUALIFIER; d->func_type = 0; d->cur = cur; d->cur_output = &d->output; d->last_sname = NULL; return (1); clean4: vector_str_dest(&d->class_type); clean3: vector_str_dest(&d->tmpl); clean2: vector_str_dest(&d->subst); 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); /* * is_tmpl is used to check if the type (function arg) is right next * to template args, and should always be cleared whenever new string * pushed. */ ddata->is_tmpl = false; return (vector_str_push(ddata->cur_output, str, len)); } static int cpp_demangle_pop_str(struct cpp_demangle_data *ddata) { if (ddata == NULL) return (0); return (vector_str_pop(ddata->cur_output)); } 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; enum type_qualifier t; size_t idx, e_idx, e_len; char *buf; int rtn; bool cv; 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 (!VEC_PUSH_STR(&subst_v, type_str)) goto clean; } cv = true; e_idx = 0; while (idx > 0) { switch (v->q_container[idx - 1]) { case TYPE_PTR: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; if (!DEM_PUSH_STR(ddata, "*")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, "*")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_REF: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; if (!DEM_PUSH_STR(ddata, "&")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, "&")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_RREF: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; if (!DEM_PUSH_STR(ddata, "&&")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, "&&")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_CMX: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; if (!DEM_PUSH_STR(ddata, " complex")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, " complex")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_IMG: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; if (!DEM_PUSH_STR(ddata, " imaginary")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, " imaginary")) goto clean; if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_EXT: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; 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 (!DEM_PUSH_STR(ddata, buf)) { free(buf); goto clean; } if (type_str != NULL) { 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 (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER && cv) break; if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv) break; if (!DEM_PUSH_STR(ddata, " restrict")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, " restrict")) goto clean; if (idx - 1 > 0) { t = v->q_container[idx - 2]; if (t == TYPE_RST || t == TYPE_VAT || t == TYPE_CST) break; } if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_VAT: if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER && cv) break; if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv) break; if (!DEM_PUSH_STR(ddata, " volatile")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, " volatile")) goto clean; if (idx - 1 > 0) { t = v->q_container[idx - 2]; if (t == TYPE_RST || t == TYPE_VAT || t == TYPE_CST) break; } if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_CST: if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER && cv) break; if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv) break; if (!DEM_PUSH_STR(ddata, " const")) goto clean; if (type_str != NULL) { if (!VEC_PUSH_STR(&subst_v, " const")) goto clean; if (idx - 1 > 0) { t = v->q_container[idx - 2]; if (t == TYPE_RST || t == TYPE_VAT || t == TYPE_CST) break; } if (!cpp_demangle_push_subst_v(ddata, &subst_v)) goto clean; } break; case TYPE_VEC: cv = false; if (ddata->push_qualifier == PUSH_CV_QUALIFIER) break; 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 (!DEM_PUSH_STR(ddata, buf)) { free(buf); goto clean; } if (type_str != NULL) { 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, NULL)) return (0); 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, NULL)) return (0); if (!DEM_PUSH_STR(ddata, "[")) return (0); if (!cpp_demangle_push_str(ddata, num, num_len)) return (0); 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, NULL)) { free(exp); return (0); } if (!DEM_PUSH_STR(ddata, "[")) { free(exp); return (0); } if (!cpp_demangle_push_str(ddata, exp, exp_len)) { free(exp); return (0); } 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 (DEM_PUSH_STR(ddata, "false")); case '1': ddata->cur += 2; 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 (!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, NULL)); case SIMPLE_HASH('s', 'r'): ddata->cur += 2; if (!cpp_demangle_read_type(ddata, NULL)) 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->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) { struct type_delimit td; struct read_cmd_item *rc; size_t class_type_size, class_type_len, limit; const char *class_type; int i; bool paren, non_cv_qualifier; 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; } /* Return type */ if (!cpp_demangle_read_type(ddata, NULL)) return (0); if (*ddata->cur != 'E') { if (!DEM_PUSH_STR(ddata, " ")) return (0); non_cv_qualifier = false; if (v->size > 0) { for (i = 0; (size_t) i < v->size; i++) { if (v->q_container[i] != TYPE_RST && v->q_container[i] != TYPE_VAT && v->q_container[i] != TYPE_CST) { non_cv_qualifier = true; break; } } } paren = false; rc = vector_read_cmd_find(&ddata->cmd, READ_PTRMEM); if (non_cv_qualifier || rc != NULL) { if (!DEM_PUSH_STR(ddata, "(")) return (0); paren = true; } /* Push non-cv qualifiers. */ ddata->push_qualifier = PUSH_NON_CV_QUALIFIER; if (!cpp_demangle_push_type_qualifier(ddata, v, NULL)) return (0); if (rc) { if (non_cv_qualifier && !DEM_PUSH_STR(ddata, " ")) return (0); 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 (!DEM_PUSH_STR(ddata, "::*")) return (0); /* Push pointer-to-member qualifiers. */ ddata->push_qualifier = PUSH_ALL_QUALIFIER; if (!cpp_demangle_push_type_qualifier(ddata, rc->data, NULL)) return (0); ++ddata->func_type; } if (paren) { if (!DEM_PUSH_STR(ddata, ")")) return (0); paren = false; } td.paren = false; td.firstp = true; limit = 0; ddata->is_functype = true; for (;;) { if (!cpp_demangle_read_type(ddata, &td)) return (0); if (*ddata->cur == 'E') break; if (limit++ > CPP_DEMANGLE_TRY_LIMIT) return (0); } ddata->is_functype = false; if (td.paren) { if (!DEM_PUSH_STR(ddata, ")")) return (0); td.paren = false; } /* Push CV qualifiers. */ ddata->push_qualifier = PUSH_CV_QUALIFIER; if (!cpp_demangle_push_type_qualifier(ddata, v, NULL)) return (0); ddata->push_qualifier = PUSH_ALL_QUALIFIER; /* Release type qualifier vector. */ vector_type_qualifier_dest(v); if (!vector_type_qualifier_init(v)) return (0); /* Push ref-qualifiers. */ if (ddata->ref_qualifier) { switch (ddata->ref_qualifier_type) { case TYPE_REF: if (!DEM_PUSH_STR(ddata, " &")) return (0); break; case TYPE_RREF: if (!DEM_PUSH_STR(ddata, " &&")) return (0); break; default: return (0); } ddata->ref_qualifier = false; } } ++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 (!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 (!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 (!DEM_PUSH_STR(ddata, num_str)) goto clean2; if (!DEM_PUSH_STR(ddata, " for ")) goto clean2; 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 (!DEM_PUSH_STR(ddata, "non-transaction clone for ")) return (0); break; case 't': default: 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 (!DEM_PUSH_STR(ddata, "guard variable for ")) return (0); ddata->cur += 2; break; case SIMPLE_HASH('T', 'c'): /* virtual function covariant override thunk */ 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 (!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, NULL)) goto clean3; if (!DEM_PUSH_STR(ddata, "-in-")) goto clean3; 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 (!DEM_PUSH_STR(ddata, "typeinfo fn for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, NULL)); case SIMPLE_HASH('T', 'h'): /* virtual function non-virtual override thunk */ 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 (!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 (!DEM_PUSH_STR(ddata, "typeinfo for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, NULL)); case SIMPLE_HASH('T', 'J'): /* java class */ 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, NULL)); case SIMPLE_HASH('T', 'S'): /* RTTI name (NTBS) */ 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, NULL)); case SIMPLE_HASH('T', 'T'): /* VTT table */ if (!DEM_PUSH_STR(ddata, "VTT for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, NULL)); case SIMPLE_HASH('T', 'v'): /* virtual function virtual override thunk */ 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 (!DEM_PUSH_STR(ddata, "vtable for ")) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); return (cpp_demangle_read_type(ddata, NULL)); case SIMPLE_HASH('T', 'W'): /* TLS wrapper function */ 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) { struct vector_str local_name; struct type_delimit td; size_t limit; bool more_type; if (ddata == NULL) return (0); if (*(++ddata->cur) == '\0') return (0); if (!vector_str_init(&local_name)) return (0); ddata->cur_output = &local_name; if (!cpp_demangle_read_encoding(ddata)) { vector_str_dest(&local_name); return (0); } ddata->cur_output = &ddata->output; td.paren = false; td.firstp = true; more_type = false; limit = 0; /* * The first type is a return type if we just demangled template * args. (the template args is right next to the function name, * which means it's a template function) */ if (ddata->is_tmpl) { ddata->is_tmpl = false; /* Read return type */ if (!cpp_demangle_read_type(ddata, NULL)) { vector_str_dest(&local_name); return (0); } more_type = true; } /* Now we can push the name after possible return type is handled. */ if (!vector_str_push_vector(&ddata->output, &local_name)) { vector_str_dest(&local_name); return (0); } vector_str_dest(&local_name); while (*ddata->cur != '\0') { if (!cpp_demangle_read_type(ddata, &td)) return (0); if (more_type) more_type = false; if (*ddata->cur == 'E') break; if (limit++ > CPP_DEMANGLE_TRY_LIMIT) return (0); } if (more_type) return (0); if (*(++ddata->cur) == '\0') return (0); if (td.paren == true) { if (!DEM_PUSH_STR(ddata, ")")) return (0); td.paren = false; } if (*ddata->cur == 's') ++ddata->cur; else { 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->cur_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->cur_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); do { switch (*ddata->cur) { case 'r': ddata->mem_rst = true; break; case 'V': ddata->mem_vat = true; break; case 'K': ddata->mem_cst = true; break; case 'R': ddata->mem_ref = true; break; case 'O': ddata->mem_rref = true; break; default: goto next; } } while (*(++ddata->cur)); next: output = ddata->cur_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 (p_idx == output->size) goto next_comp; 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; next_comp: if (*ddata->cur == 'E') break; else if (*ddata->cur != 'I' && *ddata->cur != 'C' && *ddata->cur != 'D' && p_idx != output->size) { if (!DEM_PUSH_STR(ddata, "::")) goto clean; 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 (!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 && !DEM_PUSH_STR(ddata, "-")) return (0); assert(start != NULL); if (!cpp_demangle_push_str(ddata, start, ddata->cur - start)) return (0); if (!DEM_PUSH_STR(ddata, " ")) return (0); ++ddata->cur; return (1); } static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata, struct vector_type_qualifier *v) { 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, NULL)) 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, v)) 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, NULL)) goto clean3; if (p_func_type == ddata->func_type) { if (!DEM_PUSH_STR(ddata, " ")) goto clean3; if (!cpp_demangle_push_str(ddata, class_type, class_type_len)) goto clean3; 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); vector_type_qualifier_dest(v); if (!vector_type_qualifier_init(v)) return (0); 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 = 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); + assert(ddata->cur_output->size > 0); if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == NULL) ddata->last_sname = - ddata->output.container[ddata->output.size - 1]; + ddata->cur_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 (!DEM_PUSH_STR(ddata, "std::allocator")) return (0); ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::allocator")); return (1); case SIMPLE_HASH('S', 'b'): /* std::basic_string */ 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")); return (1); case SIMPLE_HASH('S', 'd'): /* std::basic_iostream > */ 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 >")); return (1); case SIMPLE_HASH('S', 'i'): /* std::basic_istream > */ 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 >")); return (1); case SIMPLE_HASH('S', 'o'): /* std::basic_ostream > */ 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 >")); return (1); case SIMPLE_HASH('S', 's'): /* * std::basic_string, * std::allocator > * * a.k.a std::string */ if (!DEM_PUSH_STR(ddata, "std::basic_string, std::allocator >")) return (0); ddata->last_sname = "string"; ddata->cur += 2; if (*ddata->cur == 'I') return (cpp_demangle_read_subst_stdtmpl(ddata, "std::basic_string," " std::allocator >")); return (1); case SIMPLE_HASH('S', 't'): /* std:: */ return (cpp_demangle_read_subst_std(ddata)); } if (*(++ddata->cur) == '\0') return (0); /* Skip unknown substitution abbreviations. */ if (!(*ddata->cur >= '0' && *ddata->cur <= '9') && !(*ddata->cur >= 'A' && *ddata->cur <= 'Z') && *ddata->cur != '_') { ++ddata->cur; return (1); } /* 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 (!DEM_PUSH_STR(ddata, "std::")) goto clean; if (!VEC_PUSH_STR(&v, "std::")) goto clean; ddata->cur += 2; output = ddata->cur_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) { struct vector_str *output; size_t p_idx, substr_len, len; int rtn; char *subst_str, *substr; if (ddata == NULL || str == NULL) return (0); if ((len = strlen(str)) == 0) return (0); output = ddata->cur_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': ++ddata->cur; if (!cpp_demangle_read_expression(ddata)) return (0); return (*ddata->cur++ == 'E'); } return (cpp_demangle_read_type(ddata, NULL)); } 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, NULL)) return (0); if (!DEM_PUSH_STR(ddata, "<")) return (0); limit = 0; - v = &ddata->output; + v = ddata->cur_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 (!DEM_PUSH_STR(ddata, " >")) return (0); } else if (!DEM_PUSH_STR(ddata, ">")) return (0); ddata->is_tmpl = true; break; } else if (*ddata->cur != 'I' && !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, struct type_delimit *td) { struct vector_type_qualifier v; struct vector_str *output, sv; size_t p_idx, type_str_len, subst_str_len; int extern_c, is_builtin; long len; const char *p; char *type_str, *exp_str, *num_str, *subst_str; bool skip_ref_qualifier, omit_void; if (ddata == NULL) return (0); output = ddata->cur_output; if (td) { if (td->paren == false) { if (!DEM_PUSH_STR(ddata, "(")) return (0); if (ddata->output.size < 2) return (0); td->paren = true; } if (!td->firstp) { if (*ddata->cur != 'I') { if (!DEM_PUSH_STR(ddata, ", ")) return (0); } } } assert(output != NULL); /* * [r, V, K] [P, R, O, 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; skip_ref_qualifier = false; again: /* Clear ref-qualifier flag */ if (*ddata->cur != 'R' && *ddata->cur != 'O' && *ddata->cur != 'E') ddata->ref_qualifier = false; /* builtin type */ switch (*ddata->cur) { case 'a': /* signed char */ 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 (!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; if (td) td->firstp = false; goto again; case 'c': /* char */ if (!DEM_PUSH_STR(ddata, "char")) goto clean; ++ddata->cur; goto rtn; case 'd': /* double */ if (!DEM_PUSH_STR(ddata, "double")) goto clean; ++ddata->cur; goto rtn; case 'D': ++ddata->cur; switch (*ddata->cur) { case 'a': /* auto */ if (!DEM_PUSH_STR(ddata, "auto")) goto clean; ++ddata->cur; break; case 'c': /* decltype(auto) */ if (!DEM_PUSH_STR(ddata, "decltype(auto)")) goto clean; ++ddata->cur; break; case 'd': /* IEEE 754r decimal floating point (64 bits) */ if (!DEM_PUSH_STR(ddata, "decimal64")) goto clean; ++ddata->cur; break; case 'e': /* IEEE 754r decimal floating point (128 bits) */ if (!DEM_PUSH_STR(ddata, "decimal128")) goto clean; ++ddata->cur; break; case 'f': /* IEEE 754r decimal floating point (32 bits) */ if (!DEM_PUSH_STR(ddata, "decimal32")) goto clean; ++ddata->cur; break; case 'h': /* IEEE 754r half-precision floating point (16 bits) */ if (!DEM_PUSH_STR(ddata, "half")) goto clean; ++ddata->cur; break; case 'i': /* char32_t */ if (!DEM_PUSH_STR(ddata, "char32_t")) goto clean; ++ddata->cur; break; case 'n': /* std::nullptr_t (i.e., decltype(nullptr)) */ if (!DEM_PUSH_STR(ddata, "decltype(nullptr)")) goto clean; ++ddata->cur; break; case 's': /* char16_t */ 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 (!VEC_PUSH_STR(&v.ext_name, exp_str)) goto clean; } else { if (!cpp_demangle_read_number_as_string(ddata, &num_str)) goto clean; 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; if (td) td->firstp = false; goto again; default: goto clean; } goto rtn; case 'e': /* long double */ if (!DEM_PUSH_STR(ddata, "long double")) goto clean; ++ddata->cur; goto rtn; case 'E': /* unexpected end except ref-qualifiers */ if (ddata->ref_qualifier && ddata->is_functype) { skip_ref_qualifier = true; /* Pop the delimiter. */ cpp_demangle_pop_str(ddata); goto rtn; } goto clean; case 'f': /* float */ 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 (!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; if (td) td->firstp = false; goto again; case 'h': /* unsigned char */ if (!DEM_PUSH_STR(ddata, "unsigned char")) goto clean; ++ddata->cur; goto rtn; case 'i': /* int */ if (!DEM_PUSH_STR(ddata, "int")) goto clean; ++ddata->cur; goto rtn; case 'I': /* template args. */ /* handles */ p_idx = output->size; if (!cpp_demangle_read_tmpl_args(ddata)) goto clean; if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, &subst_str_len)) == NULL) goto clean; if (!vector_str_init(&sv)) { free(subst_str); goto clean; } if (!vector_str_push(&sv, subst_str, subst_str_len)) { free(subst_str); vector_str_dest(&sv); goto clean; } free(subst_str); if (!cpp_demangle_push_subst_v(ddata, &sv)) { vector_str_dest(&sv); goto clean; } vector_str_dest(&sv); goto rtn; case 'j': /* unsigned int */ 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; if (td) td->firstp = false; goto again; case 'l': /* long */ if (!DEM_PUSH_STR(ddata, "long")) goto clean; ++ddata->cur; goto rtn; case 'm': /* unsigned long */ 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, &v)) goto clean; is_builtin = 0; goto rtn; case 'n': /* __int128 */ if (!DEM_PUSH_STR(ddata, "__int128")) goto clean; ++ddata->cur; goto rtn; case 'o': /* unsigned __int128 */ if (!DEM_PUSH_STR(ddata, "unsigned __int128")) goto clean; ++ddata->cur; goto rtn; case 'O': /* rvalue reference */ if (ddata->ref_qualifier) goto clean; if (!vector_type_qualifier_push(&v, TYPE_RREF)) goto clean; ddata->ref_qualifier = true; ddata->ref_qualifier_type = TYPE_RREF; ++ddata->cur; if (td) td->firstp = false; goto again; case 'P': /* pointer */ if (!vector_type_qualifier_push(&v, TYPE_PTR)) goto clean; ++ddata->cur; if (td) td->firstp = false; goto again; case 'r': /* restrict */ if (!vector_type_qualifier_push(&v, TYPE_RST)) goto clean; ++ddata->cur; if (td) td->firstp = false; goto again; case 'R': /* reference */ if (ddata->ref_qualifier) goto clean; if (!vector_type_qualifier_push(&v, TYPE_REF)) goto clean; ddata->ref_qualifier = true; ddata->ref_qualifier_type = TYPE_REF; ++ddata->cur; if (td) td->firstp = false; goto again; case 's': /* short, local string */ 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 (!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 */ ++ddata->cur; if (!cpp_demangle_read_number(ddata, &len)) goto clean; if (len <= 0) goto clean; if (!vector_str_push(&v.ext_name, ddata->cur, len)) goto clean; ddata->cur += len; if (!vector_type_qualifier_push(&v, TYPE_EXT)) goto clean; if (td) td->firstp = false; goto again; case 'v': /* void */ omit_void = false; if (td && td->firstp) { /* * peek into next bytes and see if we should omit * the "void". */ omit_void = true; for (p = ddata->cur + 1; *p != '\0'; p++) { if (*p == 'E') break; if (*p != 'R' && *p != 'O') { omit_void = false; break; } } } if (!omit_void && !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; if (td) td->firstp = false; goto again; case 'w': /* wchar_t */ if (!DEM_PUSH_STR(ddata, "wchar_t")) goto clean; ++ddata->cur; goto rtn; case 'x': /* long long */ if (!DEM_PUSH_STR(ddata, "long long")) goto clean; ++ddata->cur; goto rtn; case 'y': /* unsigned long long */ if (!DEM_PUSH_STR(ddata, "unsigned long long")) goto clean; ++ddata->cur; goto rtn; case 'z': /* ellipsis */ if (!DEM_PUSH_STR(ddata, "...")) goto clean; ++ddata->cur; goto rtn; } if (!cpp_demangle_read_name(ddata)) goto clean; is_builtin = 0; rtn: type_str = vector_str_substr(output, p_idx, output->size - 1, &type_str_len); 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 (!skip_ref_qualifier && !cpp_demangle_push_type_qualifier(ddata, &v, type_str)) goto clean; if (td) td->firstp = false; free(type_str); free(exp_str); free(num_str); vector_type_qualifier_dest(&v); 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->cur_output; p_idx = output->size; if (!cpp_demangle_read_type(ddata, NULL)) 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 (!DEM_PUSH_STR(ddata, "operator&&")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'd'): /* operator & (unary) */ if (!DEM_PUSH_STR(ddata, "operator&")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'n'): /* operator & */ if (!DEM_PUSH_STR(ddata, "operator&")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'N'): /* operator &= */ if (!DEM_PUSH_STR(ddata, "operator&=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('a', 'S'): /* operator = */ if (!DEM_PUSH_STR(ddata, "operator=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'l'): /* operator () */ if (!DEM_PUSH_STR(ddata, "operator()")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'm'): /* operator , */ if (!DEM_PUSH_STR(ddata, "operator,")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'o'): /* operator ~ */ if (!DEM_PUSH_STR(ddata, "operator~")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('c', 'v'): /* operator (cast) */ if (!DEM_PUSH_STR(ddata, "operator(cast)")) return (0); ddata->cur += 2; return (cpp_demangle_read_type(ddata, NULL)); case SIMPLE_HASH('d', 'a'): /* operator delete [] */ if (!DEM_PUSH_STR(ddata, "operator delete []")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'e'): /* operator * (unary) */ if (!DEM_PUSH_STR(ddata, "operator*")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'l'): /* operator delete */ if (!DEM_PUSH_STR(ddata, "operator delete")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'v'): /* operator / */ if (!DEM_PUSH_STR(ddata, "operator/")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('d', 'V'): /* operator /= */ if (!DEM_PUSH_STR(ddata, "operator/=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'o'): /* operator ^ */ if (!DEM_PUSH_STR(ddata, "operator^")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'O'): /* operator ^= */ if (!DEM_PUSH_STR(ddata, "operator^=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('e', 'q'): /* operator == */ if (!DEM_PUSH_STR(ddata, "operator==")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('g', 'e'): /* operator >= */ if (!DEM_PUSH_STR(ddata, "operator>=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('g', 't'): /* operator > */ if (!DEM_PUSH_STR(ddata, "operator>")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('i', 'x'): /* operator [] */ if (!DEM_PUSH_STR(ddata, "operator[]")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 'e'): /* operator <= */ if (!DEM_PUSH_STR(ddata, "operator<=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 's'): /* operator << */ if (!DEM_PUSH_STR(ddata, "operator<<")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 'S'): /* operator <<= */ if (!DEM_PUSH_STR(ddata, "operator<<=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('l', 't'): /* operator < */ if (!DEM_PUSH_STR(ddata, "operator<")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'i'): /* operator - */ if (!DEM_PUSH_STR(ddata, "operator-")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'I'): /* operator -= */ if (!DEM_PUSH_STR(ddata, "operator-=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'l'): /* operator * */ if (!DEM_PUSH_STR(ddata, "operator*")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'L'): /* operator *= */ if (!DEM_PUSH_STR(ddata, "operator*=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('m', 'm'): /* operator -- */ if (!DEM_PUSH_STR(ddata, "operator--")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'a'): /* operator new[] */ if (!DEM_PUSH_STR(ddata, "operator new []")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'e'): /* operator != */ if (!DEM_PUSH_STR(ddata, "operator!=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'g'): /* operator - (unary) */ if (!DEM_PUSH_STR(ddata, "operator-")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 't'): /* operator ! */ if (!DEM_PUSH_STR(ddata, "operator!")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('n', 'w'): /* operator new */ if (!DEM_PUSH_STR(ddata, "operator new")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'o'): /* operator || */ if (!DEM_PUSH_STR(ddata, "operator||")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'r'): /* operator | */ if (!DEM_PUSH_STR(ddata, "operator|")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('o', 'R'): /* operator |= */ if (!DEM_PUSH_STR(ddata, "operator|=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'l'): /* operator + */ if (!DEM_PUSH_STR(ddata, "operator+")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'L'): /* operator += */ if (!DEM_PUSH_STR(ddata, "operator+=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'm'): /* operator ->* */ if (!DEM_PUSH_STR(ddata, "operator->*")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 'p'): /* operator ++ */ if (!DEM_PUSH_STR(ddata, "operator++")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 's'): /* operator + (unary) */ if (!DEM_PUSH_STR(ddata, "operator+")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('p', 't'): /* operator -> */ if (!DEM_PUSH_STR(ddata, "operator->")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('q', 'u'): /* operator ? */ if (!DEM_PUSH_STR(ddata, "operator?")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'm'): /* operator % */ if (!DEM_PUSH_STR(ddata, "operator%")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'M'): /* operator %= */ if (!DEM_PUSH_STR(ddata, "operator%=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 's'): /* operator >> */ if (!DEM_PUSH_STR(ddata, "operator>>")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'S'): /* operator >>= */ if (!DEM_PUSH_STR(ddata, "operator>>=")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('r', 'z'): /* operator sizeof */ if (!DEM_PUSH_STR(ddata, "operator sizeof ")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('s', 'r'): /* scope resolution operator */ if (!DEM_PUSH_STR(ddata, "scope resolution operator ")) return (0); ddata->cur += 2; return (1); case SIMPLE_HASH('s', 'v'): /* operator sizeof */ 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 (!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'): case SIMPLE_HASH('C', '2'): case SIMPLE_HASH('C', '3'): if (ddata->last_sname == NULL) return (0); if ((len = strlen(ddata->last_sname)) == 0) return (0); 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'): case SIMPLE_HASH('D', '1'): case SIMPLE_HASH('D', '2'): if (ddata->last_sname == NULL) return (0); if ((len = strlen(ddata->last_sname)) == 0) return (0); 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 (!DEM_PUSH_STR(ddata, "offset : ")) return (0); if (!cpp_demangle_read_offset_number(ddata)) return (0); 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); } static struct read_cmd_item * vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst) { int i; if (v == NULL || dst == READ_FAIL) return (NULL); for (i = (int) v->size - 1; i >= 0; i--) if (v->r_container[i].cmd == dst) return (&v->r_container[i]); return (NULL); } 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(*v->r_container) * 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].cmd = READ_FAIL; v->r_container[v->size].data = NULL; return (1); } static int vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd, void *data) { struct read_cmd_item *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; + tmp_cap = BUFFER_GROW(v->capacity); if ((tmp_r_ctn = malloc(sizeof(*tmp_r_ctn) * 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 = cmd; v->r_container[v->size].data = data; ++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)) { 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; + tmp_cap = BUFFER_GROW(v->capacity); 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: stable/12/contrib/elftoolchain/libelftc/libelftc_vstr.c =================================================================== --- stable/12/contrib/elftoolchain/libelftc/libelftc_vstr.c (revision 367461) +++ stable/12/contrib/elftoolchain/libelftc/libelftc_vstr.c (revision 367462) @@ -1,359 +1,359 @@ /*- * 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 "_libelftc.h" ELFTC_VCSID("$Id: libelftc_vstr.c 3531 2017-06-05 05:08:43Z kaiwang27 $"); /** * @file vector_str.c * @brief Dynamic vector data for string implementation. * * Resemble to std::vector in C++. */ static size_t get_strlen_sum(const struct vector_str *v); static bool vector_str_grow(struct vector_str *v); static size_t get_strlen_sum(const struct vector_str *v) { size_t i, len = 0; if (v == NULL) return (0); assert(v->size > 0); for (i = 0; i < v->size; ++i) len += strlen(v->container[i]); return (len); } /** * @brief Deallocate resource in vector_str. */ void vector_str_dest(struct vector_str *v) { size_t i; if (v == NULL) return; for (i = 0; i < v->size; ++i) free(v->container[i]); free(v->container); } /** * @brief Find string in vector_str. * @param v Destination vector. * @param o String to find. * @param l Length of the string. * @return -1 at failed, 0 at not found, 1 at found. */ int vector_str_find(const struct vector_str *v, const char *o, size_t l) { size_t i; if (v == NULL || o == NULL) return (-1); for (i = 0; i < v->size; ++i) if (strncmp(v->container[i], o, l) == 0) return (1); return (0); } /** * @brief Get new allocated flat string from vector. * * If l is not NULL, return length of the string. * @param v Destination vector. * @param l Length of the string. * @return NULL at failed or NUL terminated new allocated string. */ char * vector_str_get_flat(const struct vector_str *v, size_t *l) { ssize_t elem_pos, elem_size, rtn_size; size_t i; char *rtn; if (v == NULL || v->size == 0) return (NULL); if ((rtn_size = get_strlen_sum(v)) == 0) return (NULL); if ((rtn = malloc(sizeof(char) * (rtn_size + 1))) == NULL) return (NULL); elem_pos = 0; for (i = 0; i < v->size; ++i) { elem_size = strlen(v->container[i]); memcpy(rtn + elem_pos, v->container[i], elem_size); elem_pos += elem_size; } rtn[rtn_size] = '\0'; if (l != NULL) *l = rtn_size; return (rtn); } static bool vector_str_grow(struct vector_str *v) { size_t i, tmp_cap; char **tmp_ctn; if (v == NULL) return (false); assert(v->capacity > 0); - tmp_cap = v->capacity * BUFFER_GROWFACTOR; + tmp_cap = BUFFER_GROW(v->capacity); assert(tmp_cap > v->capacity); if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL) return (false); for (i = 0; i < v->size; ++i) tmp_ctn[i] = v->container[i]; free(v->container); v->container = tmp_ctn; v->capacity = tmp_cap; return (true); } /** * @brief Initialize vector_str. * @return false at failed, true at success. */ bool vector_str_init(struct vector_str *v) { if (v == NULL) return (false); v->size = 0; v->capacity = VECTOR_DEF_CAPACITY; assert(v->capacity > 0); if ((v->container = malloc(sizeof(char *) * v->capacity)) == NULL) return (false); assert(v->container != NULL); return (true); } /** * @brief Remove last element in vector_str. * @return false at failed, true at success. */ bool vector_str_pop(struct vector_str *v) { if (v == NULL) return (false); if (v->size == 0) return (true); --v->size; free(v->container[v->size]); v->container[v->size] = NULL; return (true); } /** * @brief Push back string to vector. * @return false at failed, true at success. */ bool vector_str_push(struct vector_str *v, const char *str, size_t len) { if (v == NULL || str == NULL) return (false); if (v->size == v->capacity && vector_str_grow(v) == false) return (false); if ((v->container[v->size] = malloc(sizeof(char) * (len + 1))) == NULL) return (false); snprintf(v->container[v->size], len + 1, "%s", str); ++v->size; return (true); } /** * @brief Push front org vector to det vector. * @return false at failed, true at success. */ bool vector_str_push_vector_head(struct vector_str *dst, struct vector_str *org) { size_t i, j, tmp_cap; char **tmp_ctn; if (dst == NULL || org == NULL) return (false); - tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR; + tmp_cap = BUFFER_GROW(dst->size + org->size); if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL) return (false); for (i = 0; i < org->size; ++i) if ((tmp_ctn[i] = strdup(org->container[i])) == NULL) { for (j = 0; j < i; ++j) free(tmp_ctn[j]); free(tmp_ctn); return (false); } for (i = 0; i < dst->size; ++i) tmp_ctn[i + org->size] = dst->container[i]; free(dst->container); dst->container = tmp_ctn; dst->capacity = tmp_cap; dst->size += org->size; return (true); } /** * @brief Push org vector to the tail of det vector. * @return false at failed, true at success. */ bool vector_str_push_vector(struct vector_str *dst, struct vector_str *org) { size_t i, j, tmp_cap; char **tmp_ctn; if (dst == NULL || org == NULL) return (false); - tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR; + tmp_cap = BUFFER_GROW(dst->size + org->size); if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL) return (false); for (i = 0; i < dst->size; ++i) tmp_ctn[i] = dst->container[i]; for (i = 0; i < org->size; ++i) if ((tmp_ctn[i + dst->size] = strdup(org->container[i])) == NULL) { for (j = 0; j < i + dst->size; ++j) free(tmp_ctn[j]); free(tmp_ctn); return (false); } free(dst->container); dst->container = tmp_ctn; dst->capacity = tmp_cap; dst->size += org->size; return (true); } /** * @brief Get new allocated flat string from vector between begin and end. * * If r_len is not NULL, string length will be returned. * @return NULL at failed or NUL terminated new allocated string. */ char * vector_str_substr(const struct vector_str *v, size_t begin, size_t end, size_t *r_len) { size_t cur, i, len; char *rtn; if (v == NULL || begin > end) return (NULL); len = 0; for (i = begin; i < end + 1; ++i) len += strlen(v->container[i]); if ((rtn = malloc(sizeof(char) * (len + 1))) == NULL) return (NULL); if (r_len != NULL) *r_len = len; cur = 0; for (i = begin; i < end + 1; ++i) { len = strlen(v->container[i]); memcpy(rtn + cur, v->container[i], len); cur += len; } rtn[cur] = '\0'; return (rtn); } Index: stable/12/contrib/elftoolchain/readelf/readelf.1 =================================================================== --- stable/12/contrib/elftoolchain/readelf/readelf.1 (revision 367461) +++ stable/12/contrib/elftoolchain/readelf/readelf.1 (revision 367462) @@ -1,199 +1,207 @@ .\" Copyright (c) 2009,2011 Joseph Koshy .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer .\" in this position and unchanged. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $Id: readelf.1 3753 2019-06-28 01:13:13Z emaste $ .\" -.Dd June 27, 2019 +.Dd October 31, 2020 .Dt READELF 1 .Os .Sh NAME .Nm readelf .Nd display information about ELF objects .Sh SYNOPSIS .Nm .Op Fl a | Fl -all .Op Fl c | Fl -archive-index .Op Fl d | Fl -dynamic .Op Fl e | Fl -headers .Op Fl g | Fl -section-groups .Op Fl h | Fl -file-header .Op Fl l | Fl -program-headers .Op Fl n | Fl -notes .Op Fl p Ar section | Fl -string-dump Ns = Ns Ar section .Op Fl r | Fl -relocs .Op Fl t | Fl -section-details .Op Fl v | Fl -version .Oo .Fl w Ns Oo Ns Ar afilmoprsFLR Ns Oc | .Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ... .Oc .Op Fl x Ar section | Fl -hex-dump Ns = Ns Ar section +.Op Fl z | Fl -decompress .Op Fl A | Fl -arch-specific .Op Fl D | Fl -use-dynamic .Op Fl H | Fl -help .Op Fl I | Fl -histogram .Op Fl N | -full-section-name .Op Fl S | Fl -sections | Fl -section-headers .Op Fl V | Fl -version-info .Op Fl W | Fl -wide .Ar file... .Sh DESCRIPTION The .Nm utility displays information about ELF objects and .Xr ar 1 archives. .Pp The .Nm utility recognizes the following options: .Bl -tag -width indent .It Fl a | Fl -all Turn on the following flags: .Fl d , .Fl h , .Fl I , .Fl l , .Fl r , .Fl s , .Fl A , .Fl S and .Fl V . .It Fl c | Fl -archive-index Print the archive symbol table for archives. .It Fl d | Fl -dynamic Print the contents of the .Li SHT_DYNAMIC sections in the ELF object. .It Fl e | Fl -headers Print all program, file and section headers in the ELF object. .It Fl g | Fl -section-groups Print the contents of the section groups in the ELF object. .It Fl h | Fl -file-header Print the file header of the ELF object. .It Fl l | Fl -program-headers Print the content of the program header table for the object. .It Fl n | Fl -notes Print the contents of .Li PT_NOTE segments or .Li SHT_NOTE sections present in the ELF object. .It Fl p Ar section | Fl -string-dump Ns = Ns Ar section Print the contents of the specified section as printable strings. The argument .Ar section should be the name of a section or a numeric section index. .It Fl r | Fl -relocs Print relocation information. .It Fl s | Fl -syms | Fl -symbols Print symbol tables. .It Fl t | Fl -section-details Print additional information about sections, such as the flags fields in section headers. Implies .Fl S . .It Fl v | Fl -version Prints a version identifier for .Nm and exits. .It Fl w Ns Oo afilmoprsFLR Oc | Xo .Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ... .Xc Display DWARF information. The .Fl w option is used with the short options in the following table; the .Fl -debug-dump option is used with a comma-separated list of the corresponding long option names: .Bl -column ".Em Short Option" "aranges|ranges" .It Em Short Option Ta Em Long Option Ta Em Description .It a Ta abbrev Ta Show abbreviation information. .It f Ta frames Ta Show frame information, displaying frame instructions. .It i Ta info Ta Show debugging information entries. .It l Ta rawline Ta Show line information in raw form. .It m Ta macro Ta Show macro information. .It o Ta loc Ta Show location list information. .It p Ta pubnames Ta Show global names. .It r Ta aranges|ranges Ta Show address range information. .It s Ta str Ta Show the debug string table. .It F Ta frames-interp Ta Show frame information, displaying register rules. .It L Ta decodedline Ta Show line information in decoded form. .It R Ta Ranges Ta Show range lists. .El .Pp If no sub-options are specified, the default is to show information corresponding to the .Ar a , f , i, l , o , p , r , s and .Ar R short options. .It Fl x Ar section | Fl -hex-dump Ns = Ns Ar section Display the contents of the specified section in hexadecimal. The argument .Ar section should be the name of a section or a numeric section index. +.It Fl z | Fl -decompress +Decompress contents of sections specified by +.Fl x +or +.Fl p +before displaying. +If the specified section is not compressed, it is displayed as is. .It Fl A | Fl -arch-specific This option is accepted but is currently unimplemented. .It Fl D | Fl -use-dynamic Print the symbol table specified by the .Li DT_SYMTAB entry in the .Dq Li .dynamic section. .It Fl H | Fl -help Print a help message. .It Fl I | Fl -histogram Print information on bucket list lengths for sections of type .Li SHT_HASH and .Li SHT_GNU_HASH . .It Fl N | Fl -full-section-name This option is accepted but is currently unimplemented. .It Fl S | Fl -sections | Fl -section-headers Print information in the section headers for each ELF object. .It Fl V | Fl -version-info Print symbol versioning information. .It Fl W | Fl -wide Print information about ELF structures using one long line per structure. If this option is not specified, .Nm will list information in the headers of 64 bit ELF objects on two separate lines. .El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr nm 1 , .Xr addr2line 1 , .Xr elfcopy 1 , .Sh AUTHORS The .Nm utility was written by .An Kai Wang Aq Mt kaiwang27@users.sourceforge.net . Index: stable/12/contrib/elftoolchain/readelf/readelf.c =================================================================== --- stable/12/contrib/elftoolchain/readelf/readelf.c (revision 367461) +++ stable/12/contrib/elftoolchain/readelf/readelf.c (revision 367462) @@ -1,7633 +1,7894 @@ /*- * 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 +#include #include "_elftc.h" ELFTC_VCSID("$Id: readelf.c 3769 2019-06-29 15:15:02Z emaste $"); /* Backwards compatability for older FreeBSD releases. */ #ifndef STB_GNU_UNIQUE #define STB_GNU_UNIQUE 10 #endif #ifndef STT_SPARC_REGISTER #define STT_SPARC_REGISTER 13 #endif /* * 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 +#define RE_Z 0x00200000 /* * 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}, + {"decompress", no_argument, 0, 'z'}, {"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 flag_desc { uint64_t flag; const char *desc; }; struct mips_option { uint64_t flag; const char *desc; }; +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; +}; + 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_flags(struct flag_desc *fd, uint64_t flags); 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_abiflags(struct readelf *re, struct section *s); 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_notes_data(const char *name, uint32_t type, const char *buf, - size_t sz); +static void dump_notes_data(struct readelf *re, const char *name, + uint32_t type, const char *buf, size_t sz); 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_gnu_property_type_0(struct readelf *re, const char *buf, + size_t sz); 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 int get_mips_register_size(uint8_t flag); 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 int loc_at_comparator(const void *la1, const void *la2); 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); + Dwarf_Unsigned lowpc, struct loc_at **la_list, + size_t *la_list_len, size_t *la_list_cap); 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 riscv_eflags_desc[] = { {EF_RISCV_RVC, "RVC"}, {EF_RISCV_RVE, "RVE"}, {EF_RISCV_TSO, "TSO"}, {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]; 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"; } 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); } 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"; case 4: return "NT_FREEBSD_FEATURE_CTL"; 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 17: return "NT_PTLWPINFO"; 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 0x400: return "NT_ARM_VFP (arm VFP registers)"; 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)"; case 5: return "NT_GNU_PROPERTY_TYPE_0"; 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"; + case 18: return "XEN_ELFNOTE_PHYS32_ENTRY"; 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_RISCV: switch (reg) { case 0: return "zero"; case 1: return "ra"; case 2: return "sp"; case 3: return "gp"; case 4: return "tp"; case 5: return "t0"; case 6: return "t1"; case 7: return "t2"; case 8: return "s0"; case 9: return "s1"; case 10: return "a0"; case 11: return "a1"; case 12: return "a2"; case 13: return "a3"; case 14: return "a4"; case 15: return "a5"; case 16: return "a6"; case 17: return "a7"; case 18: return "s2"; case 19: return "s3"; case 20: return "s4"; case 21: return "s5"; case 22: return "s6"; case 23: return "s7"; case 24: return "s8"; case 25: return "s9"; case 26: return "s10"; case 27: return "s11"; case 28: return "t3"; case 29: return "t4"; case 30: return "t5"; case 31: return "t6"; case 32: return "ft0"; case 33: return "ft1"; case 34: return "ft2"; case 35: return "ft3"; case 36: return "ft4"; case 37: return "ft5"; case 38: return "ft6"; case 39: return "ft7"; case 40: return "fs0"; case 41: return "fs1"; case 42: return "fa0"; case 43: return "fa1"; case 44: return "fa2"; case 45: return "fa3"; case 46: return "fa4"; case 47: return "fa5"; case 48: return "fa6"; case 49: return "fa7"; case 50: return "fs2"; case 51: return "fs3"; case 52: return "fs4"; case 53: return "fs5"; case 54: return "fs6"; case 55: return "fs7"; case 56: return "fs8"; case 57: return "fs9"; case 58: return "fs10"; case 59: return "fs11"; case 60: return "ft8"; case 61: return "ft9"; case 62: return "ft10"; case 63: return "ft11"; 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 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", " 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_PPC64: switch (e_flags) { case 0: printf(", Unspecified or Power ELF V1 ABI"); break; case 1: printf(", Power ELF V1 ABI"); break; case 2: printf(", OpenPOWER ELF V2 ABI"); break; default: break; } /* FALLTHROUGH */ case EM_PPC: edesc = powerpc_eflags_desc; break; case EM_RISCV: switch (e_flags & EF_RISCV_FLOAT_ABI_MASK) { case EF_RISCV_FLOAT_ABI_SOFT: printf(", soft-float ABI"); break; case EF_RISCV_FLOAT_ABI_SINGLE: printf(", single-float ABI"); break; case EF_RISCV_FLOAT_ABI_DOUBLE: printf(", double-float ABI"); break; case EF_RISCV_FLOAT_ABI_QUAD: printf(", quad-float ABI"); break; } edesc = riscv_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].off < phdr.p_offset) continue; if (re->sl[j].off + re->sl[j].sz > phdr.p_offset + phdr.p_filesz && re->sl[j].type != SHT_NOBITS) continue; if (re->sl[j].addr < phdr.p_vaddr || re->sl[j].addr + re->sl[j].sz > phdr.p_vaddr + phdr.p_memsz) continue; if (phdr.p_type == PT_TLS && (re->sl[j].flags & SHF_TLS) == 0) continue; 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) { 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_MIPS_TIME_STAMP: printf(" %s\n", timestamp(dyn->d_un.d_val)); break; default: printf("\n"); break; } break; default: printf("\n"); break; } } static void dump_flags(struct flag_desc *desc, uint64_t val) { struct flag_desc *fd; for (fd = desc; fd->flag != 0; fd++) { if (val & fd->flag) { val &= ~fd->flag; printf(" %s", fd->desc); } } if (val != 0) printf(" unknown (0x%jx)", (uintmax_t)val); printf("\n"); } static struct flag_desc dt_flags[] = { { DF_ORIGIN, "ORIGIN" }, { DF_SYMBOLIC, "SYMBOLIC" }, { DF_TEXTREL, "TEXTREL" }, { DF_BIND_NOW, "BIND_NOW" }, { DF_STATIC_TLS, "STATIC_TLS" }, { 0, NULL } }; static struct flag_desc dt_flags_1[] = { { DF_1_BIND_NOW, "NOW" }, { DF_1_GLOBAL, "GLOBAL" }, { 0x4, "GROUP" }, { DF_1_NODELETE, "NODELETE" }, { DF_1_LOADFLTR, "LOADFLTR" }, { 0x20, "INITFIRST" }, { DF_1_NOOPEN, "NOOPEN" }, { DF_1_ORIGIN, "ORIGIN" }, { 0x100, "DIRECT" }, { DF_1_INTERPOSE, "INTERPOSE" }, { DF_1_NODEFLIB, "NODEFLIB" }, { 0x1000, "NODUMP" }, { 0x2000, "CONFALT" }, { 0x4000, "ENDFILTEE" }, { 0x8000, "DISPRELDNE" }, { 0x10000, "DISPRELPND" }, { 0x20000, "NODIRECT" }, { 0x40000, "IGNMULDEF" }, { 0x80000, "NOKSYMS" }, { 0x100000, "NOHDR" }, { 0x200000, "EDITED" }, { 0x400000, "NORELOC" }, { 0x800000, "SYMINTPOSE" }, { 0x1000000, "GLOBAUDIT" }, + { 0x02000000, "SINGLETON" }, + { 0x04000000, "STUB" }, + { DF_1_PIE, "PIE" }, { 0, NULL } }; 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 && dyn->d_tag != DT_AUXILIARY && dyn->d_tag != DT_FILTER) { dump_arch_dyn_val(re, dyn); return; } /* These entry values are index into the string table. */ name = NULL; if (dyn->d_tag == DT_AUXILIARY || dyn->d_tag == DT_FILTER || 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_PREINIT_ARRAYSZ: 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_AUXILIARY: printf(" Auxiliary library: [%s]\n", name); break; case DT_FILTER: printf(" Filter library: [%s]\n", name); 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; case DT_FLAGS: dump_flags(dt_flags, dyn->d_un.d_val); break; case DT_FLAGS_1: dump_flags(dt_flags_1, 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; } else { type2 = type3 = 0; } 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; } else { type2 = type3 = 0; } 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 struct flag_desc gnu_property_x86_feature_1_and_bits[] = { + { GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT" }, + { GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK" }, + { 0, NULL } +}; + static void +dump_gnu_property_type_0(struct readelf *re, const char *buf, size_t sz) +{ + size_t i; + uint32_t type, prop_sz; + + printf(" Properties: "); + while (sz > 0) { + if (sz < 8) + goto bad; + + type = *(const uint32_t *)(const void *)buf; + prop_sz = *(const uint32_t *)(const void *)(buf + 4); + buf += 8; + sz -= 8; + + if (prop_sz > sz) + goto bad; + + if (type >= GNU_PROPERTY_LOPROC && + type <= GNU_PROPERTY_HIPROC) { + if (re->ehdr.e_machine != EM_X86_64) { + printf("machine type %x unknown\n", + re->ehdr.e_machine); + goto unknown; + } + switch (type) { + case GNU_PROPERTY_X86_FEATURE_1_AND: + printf("x86 features:"); + if (prop_sz != 4) + goto bad; + dump_flags(gnu_property_x86_feature_1_and_bits, + *(const uint32_t *)(const void *)buf); + break; + } + } + + buf += roundup2(prop_sz, 8); + sz -= roundup2(prop_sz, 8); + } + return; +bad: + printf("corrupt GNU property\n"); +unknown: + printf("remaining description data:"); + for (i = 0; i < sz; i++) + printf(" %02x", (unsigned char)buf[i]); + printf("\n"); +} + +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 struct flag_desc note_feature_ctl_flags[] = { { NT_FREEBSD_FCTL_ASLR_DISABLE, "ASLR_DISABLE" }, + { NT_FREEBSD_FCTL_PROTMAX_DISABLE, "PROTMAX_DISABLE" }, + { NT_FREEBSD_FCTL_STKGAP_DISABLE, "STKGAP_DISABLE" }, + { NT_FREEBSD_FCTL_WXNEEDED, "WXNEEDED" }, { 0, NULL } }; +static bool +dump_note_string(const char *description, const char *s, size_t len) +{ + size_t i; + + if (len == 0 || s[--len] != '\0') { + return (false); + } else { + for (i = 0; i < len; i++) + if (!isprint(s[i])) + return (false); + } + + printf(" %s: %s\n", description, s); + return (true); +} + +struct note_desc { + uint32_t type; + const char *description; + bool (*fp)(const char *, const char *, size_t); +}; + +static struct note_desc xen_notes[] = { + { 5, "Xen version", dump_note_string }, + { 6, "Guest OS", dump_note_string }, + { 7, "Guest version", dump_note_string }, + { 8, "Loader", dump_note_string }, + { 9, "PAE mode", dump_note_string }, + { 10, "Features", dump_note_string }, + { 11, "BSD symtab", dump_note_string }, + { 0, NULL, NULL } +}; + static void -dump_notes_data(const char *name, uint32_t type, const char *buf, size_t sz) +dump_notes_data(struct readelf *re, const char *name, uint32_t type, + const char *buf, size_t sz) { + struct note_desc *nd; size_t i; const uint32_t *ubuf; /* Note data is at least 4-byte aligned. */ if (((uintptr_t)buf & 3) != 0) { warnx("bad note data alignment"); goto unknown; } ubuf = (const uint32_t *)(const void *)buf; if (strcmp(name, "FreeBSD") == 0) { switch (type) { case NT_FREEBSD_ABI_TAG: if (sz != 4) goto unknown; printf(" ABI tag: %u\n", ubuf[0]); return; /* NT_FREEBSD_NOINIT_TAG carries no data, treat as unknown. */ case NT_FREEBSD_ARCH_TAG: if (sz != 4) goto unknown; printf(" Arch tag: %x\n", ubuf[0]); return; case NT_FREEBSD_FEATURE_CTL: if (sz != 4) goto unknown; printf(" Features:"); dump_flags(note_feature_ctl_flags, ubuf[0]); return; } + } else if (strcmp(name, "GNU") == 0) { + switch (type) { + case NT_GNU_PROPERTY_TYPE_0: + dump_gnu_property_type_0(re, buf, sz); + return; + case NT_GNU_BUILD_ID: + printf(" Build ID: "); + for (i = 0; i < sz; i++) + printf("%02x", (unsigned char)buf[i]); + printf("\n"); + return; + } + } else if (strcmp(name, "Xen") == 0) { + for (nd = xen_notes; nd->description != NULL; nd++) { + if (nd->type == type) { + if (nd->fp(nd->description, buf, sz)) + return; + else + break; + } + } } unknown: printf(" description data:"); for (i = 0; i < sz; i++) printf(" %02x", (unsigned char)buf[i]); printf("\n"); } static void dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off) { Elf_Note *note; const char *end, *name; + uint32_t namesz, descsz; 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; + namesz = roundup2(note->n_namesz, 4); + descsz = roundup2(note->n_descsz, 4); + if (namesz < note->n_namesz || descsz < note->n_descsz || + buf + namesz + descsz > end) { + warnx("invalid note header"); + return; + } buf += sizeof(Elf_Note); name = buf; - buf += roundup2(note->n_namesz, 4); + buf += namesz; /* * 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)); - dump_notes_data(name, note->n_type, buf, note->n_descsz); - buf += roundup2(note->n_descsz, 4); + dump_notes_data(re, name, note->n_type, buf, note->n_descsz); + buf += descsz; } } /* * 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. */ #ifndef GRP_COMDAT #define GRP_COMDAT 0x1 #endif 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; 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); } } if (s->name != NULL && (!strcmp(s->name, ".MIPS.abiflags") || (s->type == SHT_MIPS_ABIFLAGS))) dump_mips_abiflags(re, s); /* * Dump .reginfo if present (although it will be ignored by an OS if a * .MIPS.options section is present, according to SGI mips64 spec). */ 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_abiflags(struct readelf *re, struct section *s) { Elf_Data *d; uint8_t *p; int elferr; uint32_t isa_ext, ases, flags1, flags2; uint16_t version; uint8_t isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size, fp_abi; 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 != 24) { warnx("invalid MIPS abiflags section size"); return; } p = d->d_buf; version = re->dw_decode(&p, 2); printf("MIPS ABI Flags Version: %u", version); if (version != 0) { printf(" (unknown)\n\n"); return; } printf("\n\n"); isa_level = re->dw_decode(&p, 1); isa_rev = re->dw_decode(&p, 1); gpr_size = re->dw_decode(&p, 1); cpr1_size = re->dw_decode(&p, 1); cpr2_size = re->dw_decode(&p, 1); fp_abi = re->dw_decode(&p, 1); isa_ext = re->dw_decode(&p, 4); ases = re->dw_decode(&p, 4); flags1 = re->dw_decode(&p, 4); flags2 = re->dw_decode(&p, 4); printf("ISA: "); if (isa_rev <= 1) printf("MIPS%u\n", isa_level); else printf("MIPS%ur%u\n", isa_level, isa_rev); printf("GPR size: %d\n", get_mips_register_size(gpr_size)); printf("CPR1 size: %d\n", get_mips_register_size(cpr1_size)); printf("CPR2 size: %d\n", get_mips_register_size(cpr2_size)); printf("FP ABI: "); switch (fp_abi) { case 3: printf("Soft float"); break; default: printf("%u", fp_abi); break; } printf("\nISA Extension: %u\n", isa_ext); printf("ASEs: %u\n", ases); printf("FLAGS 1: %08x\n", flags1); printf("FLAGS 2: %08x\n", flags2); } static int get_mips_register_size(uint8_t flag) { switch (flag) { case 0: return 0; case 1: return 32; case 2: return 64; case 3: return 128; default: return -1; } } 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 && file[0] != '/') 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) { free(vec); 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) { free(vec); 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 int +loc_at_comparator(const void *la1, const void *la2) +{ + const struct loc_at *left, *right; -static TAILQ_HEAD(, loc_at) lalist = TAILQ_HEAD_INITIALIZER(lalist); + left = (const struct loc_at *)la1; + right = (const struct loc_at *)la2; + if (left->la_off > right->la_off) + return (1); + else if (left->la_off < right->la_off) + return (-1); + else + return (0); +} + static void -search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc) +search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc, + struct loc_at **la_list, size_t *la_list_len, size_t *la_list_cap) { + struct loc_at *la; 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_list_cap == *la_list_len) { + *la_list = realloc(*la_list, + *la_list_cap * 2 * sizeof(**la_list)); + if (*la_list == NULL) + err(EXIT_FAILURE, "realloc failed"); + *la_list_cap *= 2; } - 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); - } + la = &((*la_list)[*la_list_len]); + la->la_at = attr_list[i]; + la->la_off = off; + la->la_lowpc = lowpc; + la->la_cu_psize = re->cu_psize; + la->la_cu_osize = re->cu_osize; + la->la_cu_ver = re->cu_ver; + (*la_list_len)++; } 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_loclist_at(re, ret_die, lowpc, la_list, + la_list_len, la_list_cap); /* 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); + search_loclist_at(re, ret_die, lowpc, la_list, + la_list_len, la_list_cap); } 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; + struct loc_at *la_list, *left, *right, *la; + size_t la_list_len, la_list_cap; + unsigned int duplicates, k; int i, j, ret, has_content; + la_list_len = 0; + la_list_cap = 200; + if ((la_list = calloc(la_list_cap, sizeof(struct loc_at))) == NULL) + errx(EXIT_FAILURE, "calloc failed"); /* Search .debug_info section. */ while ((ret = dwarf_next_cu_header_b(re->dbg, NULL, &version, NULL, &pointer_size, &off_size, NULL, NULL, &de)) == DW_DLV_OK) { set_cu_context(re, pointer_size, off_size, version); die = NULL; if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK) continue; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); continue; } /* XXX: What about DW_TAG_partial_unit? */ lowpc = 0; if (tag == DW_TAG_compile_unit) { if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lowpc, &de) != DW_DLV_OK) lowpc = 0; } /* Search attributes for reference to .debug_loc section. */ - search_loclist_at(re, die, lowpc); + search_loclist_at(re, die, lowpc, &la_list, + &la_list_len, &la_list_cap); } 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); + search_loclist_at(re, die, lowpc, &la_list, + &la_list_len, &la_list_cap); } 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)) + if (la_list_len == 0) { + free(la_list); return; + } + /* Sort la_list using loc_at_comparator. */ + qsort(la_list, la_list_len, sizeof(struct loc_at), loc_at_comparator); + + /* Get rid of the duplicates in la_list. */ + duplicates = 0; + for (k = 1; k < la_list_len; ++k) { + left = &la_list[k - 1 - duplicates]; + right = &la_list[k]; + + if (left->la_off == right->la_off) + duplicates++; + else + la_list[k - duplicates] = *right; + } + la_list_len -= duplicates; + has_content = 0; - TAILQ_FOREACH(la, &lalist, la_next) { + for (k = 0; k < la_list_len; ++k) { + la = &la_list[k]; if ((ret = dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de)) != DW_DLV_OK) { 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"); + + free(la_list); } /* * Retrieve a string using string table section index and the string offset. */ static const char* get_string(struct readelf *re, int strtab, size_t off) { const char *name; if ((name = elf_strptr(re->elf, strtab, off)) == NULL) return (""); return (name); } /* * Retrieve the name of a symbol using the section index of the symbol * table and the index of the symbol within that table. */ static const char * get_symbol_name(struct readelf *re, int symtab, int i) { struct section *s; const char *name; GElf_Sym sym; Elf_Data *data; int elferr; s = &re->sl[symtab]; if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM) return (""); (void) elf_errno(); if ((data = elf_getdata(s->scn, NULL)) == NULL) { elferr = elf_errno(); if (elferr != 0) warnx("elf_getdata failed: %s", elf_errmsg(elferr)); return (""); } if (gelf_getsym(data, i, &sym) != &sym) return (""); /* Return section name for STT_SECTION symbol. */ if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) { 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); } +/* + * Decompress a data section if needed (using ZLIB). + * Returns true if sucessful, false otherwise. + */ +static bool decompress_section(struct section *s, + unsigned char *compressed_data_buffer, size_t compressed_size, + unsigned char **ret_buf, size_t *ret_sz) +{ + GElf_Shdr sh; + + if (gelf_getshdr(s->scn, &sh) == NULL) + errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); + + if (sh.sh_flags & SHF_COMPRESSED) { + int ret; + GElf_Chdr chdr; + Elf64_Xword inflated_size; + unsigned char *uncompressed_data_buffer = NULL; + Elf64_Xword uncompressed_size; + z_stream strm; + + if (gelf_getchdr(s->scn, &chdr) == NULL) + errx(EXIT_FAILURE, "gelf_getchdr() failed: %s", elf_errmsg(-1)); + if (chdr.ch_type != ELFCOMPRESS_ZLIB) { + warnx("unknown compression type: %d", chdr.ch_type); + return (false); + } + + inflated_size = 0; + uncompressed_size = chdr.ch_size; + uncompressed_data_buffer = malloc(uncompressed_size); + compressed_data_buffer += sizeof(chdr); + compressed_size -= sizeof(chdr); + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = compressed_size; + strm.avail_out = uncompressed_size; + ret = inflateInit(&strm); + + if (ret != Z_OK) + goto fail; + /* + * The section can contain several compressed buffers, + * so decompress in a loop until all data is inflated. + */ + while (inflated_size < compressed_size) { + strm.next_in = compressed_data_buffer + inflated_size; + strm.next_out = uncompressed_data_buffer + inflated_size; + ret = inflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END) + goto fail; + inflated_size = uncompressed_size - strm.avail_out; + ret = inflateReset(&strm); + if (ret != Z_OK) + goto fail; + } + if (strm.avail_out != 0) + warnx("Warning: wrong info in compression header."); + ret = inflateEnd(&strm); + if (ret != Z_OK) + goto fail; + *ret_buf = uncompressed_data_buffer; + *ret_sz = uncompressed_size; + return (true); +fail: + inflateEnd(&strm); + if (strm.msg) + warnx("%s", strm.msg); + else + warnx("ZLIB error: %d", ret); + free(uncompressed_data_buffer); + return (false); + } + return (false); +} + static void hex_dump(struct readelf *re) { struct section *s; Elf_Data *d; - uint8_t *buf; + uint8_t *buf, *new_buf; size_t sz, nbytes; uint64_t addr; int elferr, i, j; for (i = 1; (size_t) i < re->shnum; i++) { + new_buf = NULL; 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; + if (re->options & RE_Z) { + if (decompress_section(s, d->d_buf, d->d_size, + &new_buf, &sz)) + buf = new_buf; + } 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; } + free(new_buf); } } static void str_dump(struct readelf *re) { struct section *s; Elf_Data *d; - unsigned char *start, *end, *buf_end; + unsigned char *start, *end, *buf_end, *new_buf; unsigned int len; + size_t sz; int i, j, elferr, found; for (i = 1; (size_t) i < re->shnum; i++) { + new_buf = NULL; 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; + start = d->d_buf; + sz = d->d_size; + if (re->options & RE_Z) { + if (decompress_section(s, d->d_buf, d->d_size, + &new_buf, &sz)) + start = new_buf; + } + buf_end = start + sz; 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; } + free(new_buf); 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 = ""; } if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) { if ((elferr = elf_errno()) != 0) { warnx("elf_ndxscn failed: %s", elf_errmsg(elferr)); continue; } } if (ndx >= re->shnum) { warnx("section index of '%s' out of range", name); continue; } 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) { - 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); elf_end(e); } 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 ((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)); goto done; } switch (elf_kind(re->elf)) { case ELF_K_NONE: warnx("Not an ELF file."); goto done; 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."); } done: 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\ + -z | --decompress Decompress the contents of a section before displaying it.\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 fd, 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:", + while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:z", 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_SS | 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 'z': + re->options |= RE_Z; 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]; fd = open(re->filename, O_RDONLY); if (fd < 0) { warn("open %s failed", re->filename); } else { dump_object(re, fd); close(fd); } } exit(EXIT_SUCCESS); } Index: stable/12/contrib/elftoolchain/strings/strings.c =================================================================== --- stable/12/contrib/elftoolchain/strings/strings.c (revision 367461) +++ stable/12/contrib/elftoolchain/strings/strings.c (revision 367462) @@ -1,448 +1,450 @@ /*- * 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 3648 2018-11-22 23:26:43Z emaste $"); 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 getcharacter(FILE *, long *); 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); +int handle_elf(const char *, FILE *); +int handle_binary(const char *, FILE *, size_t); +int find_strings(const char *, FILE *, 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 = 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 == 0) min_len = 4; if (*argv == NULL) - rc = find_strings("{standard input}", 0, 0); + rc = find_strings("{standard input}", stdin, 0, 0); else while (*argv != NULL) { if (handle_file(*argv) != 0) rc = 1; argv++; } return (rc); } int handle_file(const char *name) { - int fd, rt; + FILE *pfile; + int rt; if (name == NULL) return (1); - if (freopen(name, "rb", stdin) == NULL) { + pfile = fopen(name, "rb"); + if (pfile == NULL) { warnx("'%s': %s", name, strerror(errno)); return (1); } - fd = fileno(stdin); - if (fd < 0) - return (1); - rt = handle_elf(name, fd); + rt = handle_elf(name, pfile); + fclose(pfile); 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) +handle_binary(const char *name, FILE *pfile, size_t size) { - struct stat buf; - memset(&buf, 0, sizeof(buf)); - (void)lseek(fd, 0, SEEK_SET); - if (!fstat(fd, &buf)) - return (find_strings(name, 0, buf.st_size)); - return (1); + (void)fseeko(pfile, 0, SEEK_SET); + return (find_strings(name, pfile, 0, size)); } /* * 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) +handle_elf(const char *name, FILE *pfile) { + struct stat buf; GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf *elf; Elf_Scn *scn; - int rc; + int rc, fd; rc = 0; + fd = fileno(pfile); + if (fstat(fd, &buf) < 0) + return (1); + /* If entire file is chosen, treat it as a binary file */ if (entire_file) - return (handle_binary(name, fd)); + return (handle_binary(name, pfile, buf.st_size)); (void)lseek(fd, 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)); + return (handle_binary(name, pfile, buf.st_size)); } if (gelf_getehdr(elf, &elfhdr) == NULL) { (void)elf_end(elf); warnx("%s: ELF file could not be processed", name); return (1); } if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { (void)elf_end(elf); - return (handle_binary(name, fd)); + return (handle_binary(name, pfile, buf.st_size)); } 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, + rc = find_strings(name, pfile, 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) +int +getcharacter(FILE *pfile, long *rt) { - long rt; - int i; - char buf[4], c; + int i, c; + char buf[4]; - rt = EOF; for(i = 0; i < encoding_size; i++) { - c = getc(stdin); - if (feof(stdin)) - return (EOF); + c = getc(pfile); + if (c == EOF) + return (-1); buf[i] = c; } switch (encoding) { case ENCODING_7BIT: case ENCODING_8BIT: - rt = buf[0]; + *rt = buf[0]; break; case ENCODING_16BIT_BIG: - rt = (buf[0] << 8) | buf[1]; + *rt = (buf[0] << 8) | buf[1]; break; case ENCODING_16BIT_LITTLE: - rt = buf[0] | (buf[1] << 8); - break; + *rt = buf[0] | (buf[1] << 8); + break; case ENCODING_32BIT_BIG: - rt = ((long) buf[0] << 24) | ((long) buf[1] << 16) | + *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) | + *rt = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) | ((long) buf[3] << 24); break; + default: + return (-1); } - return (rt); + + return (0); } /* - * Input stream stdin is read until the end of file is reached or until + * Input stream 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) +find_strings(const char *name, FILE *pfile, 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) { fprintf(stderr, "Unable to allocate memory: %s\n", strerror(errno)); return (1); } - (void)fseeko(stdin, offset, SEEK_SET); + (void)fseeko(pfile, offset, SEEK_SET); cur_off = offset; start_off = 0; for (;;) { 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)) + if (getcharacter(pfile, &c) < 0) 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: printf("%7ju ", (uintmax_t)start_off); break; case RADIX_HEX: printf("%7jx ", (uintmax_t)start_off); break; case RADIX_OCTAL: printf("%7jo ", (uintmax_t)start_off); break; } } printf("%s", obuf); for (;;) { if ((offset + size) && (cur_off >= offset + size)) break; - c = getcharacter(); + if (getcharacter(pfile, &c) < 0) + break; cur_off += encoding_size; if (encoding == ENCODING_8BIT && (uint8_t)c > 127) { putchar(c); continue; } - if (!PRINTABLE(c) || c == EOF) + if (!PRINTABLE(c)) break; putchar(c); } putchar('\n'); } } _exit1: free(obuf); 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) { fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(EXIT_FAILURE); } void show_version(void) { printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(EXIT_SUCCESS); } Index: stable/12/lib/libelf/Makefile =================================================================== --- stable/12/lib/libelf/Makefile (revision 367461) +++ stable/12/lib/libelf/Makefile (revision 367462) @@ -1,201 +1,203 @@ # $FreeBSD$ PACKAGE=lib${LIB} SHLIBDIR?= /lib .include ELFTCDIR=${SRCTOP}/contrib/elftoolchain SRCDIR= ${ELFTCDIR}/libelf .PATH: ${SRCDIR} LIB= elf SRCS= elf.c \ elf_begin.c \ elf_cntl.c \ elf_end.c elf_errmsg.c elf_errno.c \ elf_data.c \ elf_fill.c \ elf_flag.c \ elf_getarhdr.c \ elf_getarsym.c \ elf_getbase.c \ elf_getident.c \ elf_hash.c \ elf_kind.c \ elf_memory.c \ elf_next.c \ elf_open.c \ elf_rand.c \ elf_rawfile.c \ elf_phnum.c \ elf_shnum.c \ elf_shstrndx.c \ elf_scn.c \ elf_strptr.c \ elf_update.c \ elf_version.c \ gelf_cap.c \ + gelf_chdr.c \ gelf_checksum.c \ gelf_dyn.c \ gelf_ehdr.c \ gelf_getclass.c \ gelf_fsize.c \ gelf_mips64el.c \ gelf_move.c \ gelf_phdr.c \ gelf_rel.c \ gelf_rela.c \ gelf_shdr.c \ gelf_sym.c \ gelf_syminfo.c \ gelf_symshndx.c \ gelf_xlate.c \ libelf_align.c \ libelf_allocate.c \ libelf_ar.c \ libelf_ar_util.c \ + libelf_chdr.c \ libelf_checksum.c \ libelf_data.c \ libelf_ehdr.c \ libelf_elfmachine.c \ libelf_extended.c \ libelf_memory.c \ libelf_open.c \ libelf_phdr.c \ libelf_shdr.c \ libelf_xlate.c \ ${GENSRCS} INCS= libelf.h gelf.h # This same hack is in lib/libdwarf/Makefile and usr.bin/readelf/Makefile # We need to link against the correct version of these files. One # solution is to include ../../sys in the include path. This causes # problems when a header file in sys depends on a file in another # part of the tree, e.g. a machine dependent header. # SRCS+= sys/elf32.h sys/elf64.h sys/elf_common.h # Allow bootstrapping elftoolchain on Linux: .if defined(BOOTSTRAPPING) && ${.MAKE.OS} == "Linux" native-elf-format.h: ${ELFTCDIR}/common/native-elf-format > ${.TARGET} || rm ${.TARGET} SRCS+= native-elf-format.h .endif GENSRCS= libelf_fsize.c libelf_msize.c libelf_convert.c CLEANFILES= ${GENSRCS} CLEANDIRS= sys CFLAGS+= -I. -I${SRCDIR} -I${ELFTCDIR}/common sys/elf32.h sys/elf64.h sys/elf_common.h: ${SRCTOP}/sys/${.TARGET} .NOMETA mkdir -p ${.OBJDIR}/sys ln -sf ${.ALLSRC} ${.TARGET} SHLIB_MAJOR= 2 MAN= elf.3 \ elf_begin.3 \ elf_cntl.3 \ elf_end.3 \ elf_errmsg.3 \ elf_fill.3 \ elf_flagdata.3 \ elf_getarhdr.3 \ elf_getarsym.3 \ elf_getbase.3 \ elf_getdata.3 \ elf_getident.3 \ elf_getscn.3 \ elf_getphdrnum.3 \ elf_getphnum.3 \ elf_getshdrnum.3 \ elf_getshnum.3 \ elf_getshdrstrndx.3 \ elf_getshstrndx.3 \ elf_hash.3 \ elf_kind.3 \ elf_memory.3 \ elf_next.3 \ elf_open.3 \ elf_rawfile.3 \ elf_rand.3 \ elf_strptr.3 \ elf_update.3 \ elf_version.3 \ gelf.3 \ gelf_checksum.3 \ gelf_fsize.3 \ gelf_getcap.3 \ gelf_getclass.3 \ gelf_getdyn.3 \ gelf_getehdr.3 \ gelf_getmove.3 \ gelf_getphdr.3 \ gelf_getrel.3 \ gelf_getrela.3 \ gelf_getshdr.3 \ gelf_getsym.3 \ gelf_getsyminfo.3 \ gelf_getsymshndx.3 \ gelf_newehdr.3 \ gelf_newphdr.3 \ gelf_update_ehdr.3 \ gelf_xlatetof.3 MLINKS+= \ elf_errmsg.3 elf_errno.3 \ elf_flagdata.3 elf_flagarhdr.3 \ elf_flagdata.3 elf_flagehdr.3 \ elf_flagdata.3 elf_flagelf.3 \ elf_flagdata.3 elf_flagphdr.3 \ elf_flagdata.3 elf_flagscn.3 \ elf_flagdata.3 elf_flagshdr.3 \ elf_getdata.3 elf_newdata.3 \ elf_getdata.3 elf_rawdata.3 \ elf_getscn.3 elf_ndxscn.3 \ elf_getscn.3 elf_newscn.3 \ elf_getscn.3 elf_nextscn.3 \ elf_getshstrndx.3 elf_setshstrndx.3 \ elf_open.3 elf_openmemory.3 \ gelf_getcap.3 gelf_update_cap.3 \ gelf_getdyn.3 gelf_update_dyn.3 \ gelf_getmove.3 gelf_update_move.3 \ gelf_getrel.3 gelf_update_rel.3 \ gelf_getrela.3 gelf_update_rela.3 \ gelf_getsym.3 gelf_update_sym.3 \ gelf_getsyminfo.3 gelf_update_syminfo.3 \ gelf_getsymshndx.3 gelf_update_symshndx.3 \ gelf_update_ehdr.3 gelf_update_phdr.3 \ gelf_update_ehdr.3 gelf_update_shdr.3 \ gelf_xlatetof.3 gelf_xlatetom.3 .for E in 32 64 MLINKS+= \ gelf_checksum.3 elf${E}_checksum.3 \ gelf_fsize.3 elf${E}_fsize.3 \ gelf_getehdr.3 elf${E}_getehdr.3 \ gelf_getphdr.3 elf${E}_getphdr.3 \ gelf_getshdr.3 elf${E}_getshdr.3 \ gelf_newehdr.3 elf${E}_newehdr.3 \ gelf_newphdr.3 elf${E}_newphdr.3 \ gelf_xlatetof.3 elf${E}_xlatetof.3 \ gelf_xlatetof.3 elf${E}_xlatetom.3 .endfor VERSION_MAP= ${SRCDIR}/Version.map libelf_convert.c: elf_types.m4 libelf_convert.m4 libelf_fsize.c: elf_types.m4 libelf_fsize.m4 libelf_msize.c: elf_types.m4 libelf_msize.m4 .include # Keep the .SUFFIXES line after the include of bsd.lib.mk .SUFFIXES: .m4 .c .m4.c: m4 -D SRCDIR=${SRCDIR} ${M4FLAGS} ${.IMPSRC} > ${.TARGET} Index: stable/12/sys/sys/elf_common.h =================================================================== --- stable/12/sys/sys/elf_common.h (revision 367461) +++ stable/12/sys/sys/elf_common.h (revision 367462) @@ -1,1430 +1,1431 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2017, 2018 Dell EMC * Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien * Copyright (c) 1998 John D. Polstra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_ELF_COMMON_H_ #define _SYS_ELF_COMMON_H_ 1 /* * ELF definitions that are independent of architecture or word size. */ /* * Note header. The ".note" section contains an array of notes. Each * begins with this header, aligned to a word boundary. Immediately * following the note header is n_namesz bytes of name, padded to the * next word boundary. Then comes n_descsz bytes of descriptor, again * padded to a word boundary. The values of n_namesz and n_descsz do * not include the padding. */ typedef struct { u_int32_t n_namesz; /* Length of name. */ u_int32_t n_descsz; /* Length of descriptor. */ u_int32_t n_type; /* Type of this note. */ } Elf_Note; typedef Elf_Note Elf_Nhdr; /* * Option kinds. */ #define ODK_NULL 0 /* undefined */ #define ODK_REGINFO 1 /* register usage info */ #define ODK_EXCEPTIONS 2 /* exception processing info */ #define ODK_PAD 3 /* section padding */ #define ODK_HWPATCH 4 /* hardware patch applied */ #define ODK_FILL 5 /* fill value used by the linker */ #define ODK_TAGS 6 /* reserved space for tools */ #define ODK_HWAND 7 /* hardware AND patch applied */ #define ODK_HWOR 8 /* hardware OR patch applied */ #define ODK_GP_GROUP 9 /* GP group for text/data sections */ #define ODK_IDENT 10 /* ID information */ #define ODK_PAGESIZE 11 /* page size information */ /* * ODK_EXCEPTIONS info field masks. */ #define OEX_FPU_MIN 0x0000001f /* min FPU exception required */ #define OEX_FPU_MAX 0x00001f00 /* max FPU exception allowed */ #define OEX_PAGE0 0x00010000 /* page zero must be mapped */ #define OEX_SMM 0x00020000 /* run in sequential memory mode */ #define OEX_PRECISEFP 0x00040000 /* run in precise FP exception mode */ #define OEX_DISMISS 0x00080000 /* dismiss invalid address traps */ /* * ODK_PAD info field masks. */ #define OPAD_PREFIX 0x0001 #define OPAD_POSTFIX 0x0002 #define OPAD_SYMBOL 0x0004 /* * ODK_HWPATCH info field masks. */ #define OHW_R4KEOP 0x00000001 /* patch for R4000 branch at end-of-page bug */ #define OHW_R8KPFETCH 0x00000002 /* R8000 prefetch bug may occur */ #define OHW_R5KEOP 0x00000004 /* patch for R5000 branch at end-of-page bug */ #define OHW_R5KCVTL 0x00000008 /* R5000 cvt.[ds].l bug: clean == 1 */ #define OHW_R10KLDL 0x00000010UL /* need patch for R10000 misaligned load */ /* * ODK_HWAND/ODK_HWOR info field and hwp_flags[12] masks. */ #define OHWA0_R4KEOP_CHECKED 0x00000001 /* object checked for R4000 end-of-page bug */ #define OHWA0_R4KEOP_CLEAN 0x00000002 /* object verified clean for R4000 end-of-page bug */ #define OHWO0_FIXADE 0x00000001 /* object requires call to fixade */ /* * ODK_IDENT/ODK_GP_GROUP info field masks. */ #define OGP_GROUP 0x0000ffff /* GP group number */ #define OGP_SELF 0x00010000 /* GP group is self-contained */ /* * The header for GNU-style hash sections. */ typedef struct { u_int32_t gh_nbuckets; /* Number of hash buckets. */ u_int32_t gh_symndx; /* First visible symbol in .dynsym. */ u_int32_t gh_maskwords; /* #maskwords used in bloom filter. */ u_int32_t gh_shift2; /* Bloom filter shift count. */ } Elf_GNU_Hash_Header; /* Indexes into the e_ident array. Keep synced with http://www.sco.com/developers/gabi/latest/ch4.eheader.html */ #define EI_MAG0 0 /* Magic number, byte 0. */ #define EI_MAG1 1 /* Magic number, byte 1. */ #define EI_MAG2 2 /* Magic number, byte 2. */ #define EI_MAG3 3 /* Magic number, byte 3. */ #define EI_CLASS 4 /* Class of machine. */ #define EI_DATA 5 /* Data format. */ #define EI_VERSION 6 /* ELF format version. */ #define EI_OSABI 7 /* Operating system / ABI identification */ #define EI_ABIVERSION 8 /* ABI version */ #define OLD_EI_BRAND 8 /* Start of architecture identification. */ #define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ #define EI_NIDENT 16 /* Size of e_ident array. */ /* Values for the magic number bytes. */ #define ELFMAG0 0x7f #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' #define ELFMAG "\177ELF" /* magic string */ #define SELFMAG 4 /* magic string size */ /* Values for e_ident[EI_VERSION] and e_version. */ #define EV_NONE 0 #define EV_CURRENT 1 /* Values for e_ident[EI_CLASS]. */ #define ELFCLASSNONE 0 /* Unknown class. */ #define ELFCLASS32 1 /* 32-bit architecture. */ #define ELFCLASS64 2 /* 64-bit architecture. */ /* Values for e_ident[EI_DATA]. */ #define ELFDATANONE 0 /* Unknown data format. */ #define ELFDATA2LSB 1 /* 2's complement little-endian. */ #define ELFDATA2MSB 2 /* 2's complement big-endian. */ /* Values for e_ident[EI_OSABI]. */ #define ELFOSABI_NONE 0 /* UNIX System V ABI */ #define ELFOSABI_HPUX 1 /* HP-UX operating system */ #define ELFOSABI_NETBSD 2 /* NetBSD */ #define ELFOSABI_LINUX 3 /* GNU/Linux */ #define ELFOSABI_HURD 4 /* GNU/Hurd */ #define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ #define ELFOSABI_SOLARIS 6 /* Solaris */ #define ELFOSABI_AIX 7 /* AIX */ #define ELFOSABI_IRIX 8 /* IRIX */ #define ELFOSABI_FREEBSD 9 /* FreeBSD */ #define ELFOSABI_TRU64 10 /* TRU64 UNIX */ #define ELFOSABI_MODESTO 11 /* Novell Modesto */ #define ELFOSABI_OPENBSD 12 /* OpenBSD */ #define ELFOSABI_OPENVMS 13 /* Open VMS */ #define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ #define ELFOSABI_AROS 15 /* Amiga Research OS */ #define ELFOSABI_FENIXOS 16 /* FenixOS */ #define ELFOSABI_CLOUDABI 17 /* Nuxi CloudABI */ #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ #define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ #define ELFOSABI_GNU ELFOSABI_LINUX /* e_ident */ #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ (ehdr).e_ident[EI_MAG3] == ELFMAG3) /* Values for e_type. */ #define ET_NONE 0 /* Unknown type. */ #define ET_REL 1 /* Relocatable. */ #define ET_EXEC 2 /* Executable. */ #define ET_DYN 3 /* Shared object. */ #define ET_CORE 4 /* Core file. */ #define ET_LOOS 0xfe00 /* First operating system specific. */ #define ET_HIOS 0xfeff /* Last operating system-specific. */ #define ET_LOPROC 0xff00 /* First processor-specific. */ #define ET_HIPROC 0xffff /* Last processor-specific. */ /* Values for e_machine. */ #define EM_NONE 0 /* Unknown machine. */ #define EM_M32 1 /* AT&T WE32100. */ #define EM_SPARC 2 /* Sun SPARC. */ #define EM_386 3 /* Intel i386. */ #define EM_68K 4 /* Motorola 68000. */ #define EM_88K 5 /* Motorola 88000. */ #define EM_IAMCU 6 /* Intel MCU. */ #define EM_860 7 /* Intel i860. */ #define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ #define EM_S370 9 /* IBM System/370. */ #define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ #define EM_PARISC 15 /* HP PA-RISC. */ #define EM_VPP500 17 /* Fujitsu VPP500. */ #define EM_SPARC32PLUS 18 /* SPARC v8plus. */ #define EM_960 19 /* Intel 80960. */ #define EM_PPC 20 /* PowerPC 32-bit. */ #define EM_PPC64 21 /* PowerPC 64-bit. */ #define EM_S390 22 /* IBM System/390. */ #define EM_V800 36 /* NEC V800. */ #define EM_FR20 37 /* Fujitsu FR20. */ #define EM_RH32 38 /* TRW RH-32. */ #define EM_RCE 39 /* Motorola RCE. */ #define EM_ARM 40 /* ARM. */ #define EM_SH 42 /* Hitachi SH. */ #define EM_SPARCV9 43 /* SPARC v9 64-bit. */ #define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ #define EM_ARC 45 /* Argonaut RISC Core. */ #define EM_H8_300 46 /* Hitachi H8/300. */ #define EM_H8_300H 47 /* Hitachi H8/300H. */ #define EM_H8S 48 /* Hitachi H8S. */ #define EM_H8_500 49 /* Hitachi H8/500. */ #define EM_IA_64 50 /* Intel IA-64 Processor. */ #define EM_MIPS_X 51 /* Stanford MIPS-X. */ #define EM_COLDFIRE 52 /* Motorola ColdFire. */ #define EM_68HC12 53 /* Motorola M68HC12. */ #define EM_MMA 54 /* Fujitsu MMA. */ #define EM_PCP 55 /* Siemens PCP. */ #define EM_NCPU 56 /* Sony nCPU. */ #define EM_NDR1 57 /* Denso NDR1 microprocessor. */ #define EM_STARCORE 58 /* Motorola Star*Core processor. */ #define EM_ME16 59 /* Toyota ME16 processor. */ #define EM_ST100 60 /* STMicroelectronics ST100 processor. */ #define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ #define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ #define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ #define EM_PDSP 63 /* Sony DSP Processor. */ #define EM_FX66 66 /* Siemens FX66 microcontroller. */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 microcontroller. */ #define EM_ST7 68 /* STmicroelectronics ST7 8-bit microcontroller. */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller. */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller. */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller. */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller. */ #define EM_SVX 73 /* Silicon Graphics SVx. */ #define EM_ST19 74 /* STMicroelectronics ST19 8-bit mc. */ #define EM_VAX 75 /* Digital VAX. */ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor. */ #define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor. */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor. */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor. */ #define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc. */ #define EM_HUANY 81 /* Harvard University machine-independent object files. */ #define EM_PRISM 82 /* SiTera Prism. */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller. */ #define EM_FR30 84 /* Fujitsu FR30. */ #define EM_D10V 85 /* Mitsubishi D10V. */ #define EM_D30V 86 /* Mitsubishi D30V. */ #define EM_V850 87 /* NEC v850. */ #define EM_M32R 88 /* Mitsubishi M32R. */ #define EM_MN10300 89 /* Matsushita MN10300. */ #define EM_MN10200 90 /* Matsushita MN10200. */ #define EM_PJ 91 /* picoJava. */ #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor. */ #define EM_ARC_A5 93 /* ARC Cores Tangent-A5. */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture. */ #define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor. */ #define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Processor. */ #define EM_NS32K 97 /* National Semiconductor 32000 series. */ #define EM_TPC 98 /* Tenor Network TPC processor. */ #define EM_SNP1K 99 /* Trebia SNP 1000 processor. */ #define EM_ST200 100 /* STMicroelectronics ST200 microcontroller. */ #define EM_IP2K 101 /* Ubicom IP2xxx microcontroller family. */ #define EM_MAX 102 /* MAX Processor. */ #define EM_CR 103 /* National Semiconductor CompactRISC microprocessor. */ #define EM_F2MC16 104 /* Fujitsu F2MC16. */ #define EM_MSP430 105 /* Texas Instruments embedded microcontroller msp430. */ #define EM_BLACKFIN 106 /* Analog Devices Blackfin (DSP) processor. */ #define EM_SE_C33 107 /* S1C33 Family of Seiko Epson processors. */ #define EM_SEP 108 /* Sharp embedded microprocessor. */ #define EM_ARCA 109 /* Arca RISC Microprocessor. */ #define EM_UNICORE 110 /* Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University */ #define EM_AARCH64 183 /* AArch64 (64-bit ARM) */ #define EM_RISCV 243 /* RISC-V */ /* Non-standard or deprecated. */ #define EM_486 6 /* Intel i486. */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ #define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ #define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ /** * e_flags */ #define EF_ARM_RELEXEC 0x1 #define EF_ARM_HASENTRY 0x2 #define EF_ARM_SYMSARESORTED 0x4 #define EF_ARM_DYNSYMSUSESEGIDX 0x8 #define EF_ARM_MAPSYMSFIRST 0x10 #define EF_ARM_LE8 0x00400000 #define EF_ARM_BE8 0x00800000 #define EF_ARM_EABIMASK 0xFF000000 #define EF_ARM_EABI_UNKNOWN 0x00000000 #define EF_ARM_EABI_VER1 0x01000000 #define EF_ARM_EABI_VER2 0x02000000 #define EF_ARM_EABI_VER3 0x03000000 #define EF_ARM_EABI_VER4 0x04000000 #define EF_ARM_EABI_VER5 0x05000000 #define EF_ARM_INTERWORK 0x00000004 #define EF_ARM_APCS_26 0x00000008 #define EF_ARM_APCS_FLOAT 0x00000010 #define EF_ARM_PIC 0x00000020 #define EF_ARM_ALIGN8 0x00000040 #define EF_ARM_NEW_ABI 0x00000080 #define EF_ARM_OLD_ABI 0x00000100 #define EF_ARM_ABI_FLOAT_SOFT 0x00000200 #define EF_ARM_SOFT_FLOAT EF_ARM_ABI_FLOAT_SOFT /* Pre-V5 ABI name */ #define EF_ARM_ABI_FLOAT_HARD 0x00000400 #define EF_ARM_VFP_FLOAT EF_ARM_ABI_FLOAT_HARD /* Pre-V5 ABI name */ #define EF_ARM_MAVERICK_FLOAT 0x00000800 #define EF_MIPS_NOREORDER 0x00000001 #define EF_MIPS_PIC 0x00000002 /* Contains PIC code */ #define EF_MIPS_CPIC 0x00000004 /* STD PIC calling sequence */ #define EF_MIPS_UCODE 0x00000010 #define EF_MIPS_ABI2 0x00000020 /* N32 */ #define EF_MIPS_OPTIONS_FIRST 0x00000080 #define EF_MIPS_ABI 0x0000F000 #define EF_MIPS_ABI_O32 0x00001000 #define EF_MIPS_ABI_O64 0x00002000 #define EF_MIPS_ABI_EABI32 0x00003000 #define EF_MIPS_ABI_EABI64 0x00004000 #define EF_MIPS_ARCH_ASE 0x0F000000 /* Architectural extensions */ #define EF_MIPS_ARCH_ASE_MDMX 0x08000000 /* MDMX multimedia extension */ #define EF_MIPS_ARCH_ASE_M16 0x04000000 /* MIPS-16 ISA extensions */ #define EF_MIPS_ARCH 0xF0000000 /* Architecture field */ #define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code */ #define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code */ #define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code */ #define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code */ #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code */ #define EF_MIPS_ARCH_32 0x50000000 /* -mips32 code */ #define EF_MIPS_ARCH_64 0x60000000 /* -mips64 code */ #define EF_MIPS_ARCH_32R2 0x70000000 /* -mips32r2 code */ #define EF_MIPS_ARCH_64R2 0x80000000 /* -mips64r2 code */ #define EF_PPC_EMB 0x80000000 #define EF_PPC_RELOCATABLE 0x00010000 #define EF_PPC_RELOCATABLE_LIB 0x00008000 #define EF_RISCV_RVC 0x00000001 #define EF_RISCV_FLOAT_ABI_MASK 0x00000006 #define EF_RISCV_FLOAT_ABI_SOFT 0x00000000 #define EF_RISCV_FLOAT_ABI_SINGLE 0x000002 #define EF_RISCV_FLOAT_ABI_DOUBLE 0x000004 #define EF_RISCV_FLOAT_ABI_QUAD 0x00000006 #define EF_RISCV_RVE 0x00000008 #define EF_RISCV_TSO 0x00000010 #define EF_SPARC_EXT_MASK 0x00ffff00 #define EF_SPARC_32PLUS 0x00000100 #define EF_SPARC_SUN_US1 0x00000200 #define EF_SPARC_HAL_R1 0x00000200 #define EF_SPARC_SUN_US3 0x00000800 #define EF_SPARCV9_MM 0x00000003 #define EF_SPARCV9_TSO 0x00000000 #define EF_SPARCV9_PSO 0x00000001 #define EF_SPARCV9_RMO 0x00000002 /* Special section indexes. */ #define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ #define SHN_LORESERVE 0xff00 /* First of reserved range. */ #define SHN_LOPROC 0xff00 /* First processor-specific. */ #define SHN_HIPROC 0xff1f /* Last processor-specific. */ #define SHN_LOOS 0xff20 /* First operating system-specific. */ #define SHN_FBSD_CACHED SHN_LOOS /* Transient, for sys/kern/link_elf_obj linker only: Cached global in local symtab. */ #define SHN_HIOS 0xff3f /* Last operating system-specific. */ #define SHN_ABS 0xfff1 /* Absolute values. */ #define SHN_COMMON 0xfff2 /* Common data. */ #define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ #define SHN_HIRESERVE 0xffff /* Last of reserved range. */ /* sh_type */ #define SHT_NULL 0 /* inactive */ #define SHT_PROGBITS 1 /* program defined information */ #define SHT_SYMTAB 2 /* symbol table section */ #define SHT_STRTAB 3 /* string table section */ #define SHT_RELA 4 /* relocation section with addends */ #define SHT_HASH 5 /* symbol hash table section */ #define SHT_DYNAMIC 6 /* dynamic section */ #define SHT_NOTE 7 /* note section */ #define SHT_NOBITS 8 /* no space section */ #define SHT_REL 9 /* relocation section - no addends */ #define SHT_SHLIB 10 /* reserved - purpose unknown */ #define SHT_DYNSYM 11 /* dynamic symbol table section */ #define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ #define SHT_FINI_ARRAY 15 /* Termination function pointers. */ #define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ #define SHT_GROUP 17 /* Section group. */ #define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ #define SHT_LOOS 0x60000000 /* First of OS specific semantics */ #define SHT_LOSUNW 0x6ffffff4 #define SHT_SUNW_dof 0x6ffffff4 #define SHT_SUNW_cap 0x6ffffff5 #define SHT_GNU_ATTRIBUTES 0x6ffffff5 #define SHT_SUNW_SIGNATURE 0x6ffffff6 #define SHT_GNU_HASH 0x6ffffff6 #define SHT_GNU_LIBLIST 0x6ffffff7 #define SHT_SUNW_ANNOTATE 0x6ffffff7 #define SHT_SUNW_DEBUGSTR 0x6ffffff8 #define SHT_SUNW_DEBUG 0x6ffffff9 #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_SUNW_verdef 0x6ffffffd #define SHT_GNU_verdef 0x6ffffffd /* Symbol versions provided */ #define SHT_SUNW_verneed 0x6ffffffe #define SHT_GNU_verneed 0x6ffffffe /* Symbol versions required */ #define SHT_SUNW_versym 0x6fffffff #define SHT_GNU_versym 0x6fffffff /* Symbol version table */ #define SHT_HISUNW 0x6fffffff #define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ #define SHT_LOPROC 0x70000000 /* reserved range for processor */ #define SHT_X86_64_UNWIND 0x70000001 /* unwind information */ #define SHT_AMD64_UNWIND SHT_X86_64_UNWIND #define SHT_ARM_EXIDX 0x70000001 /* Exception index table. */ #define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map. */ #define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes. */ #define SHT_ARM_DEBUGOVERLAY 0x70000004 /* See DBGOVL for details. */ #define SHT_ARM_OVERLAYSECTION 0x70000005 /* See DBGOVL for details. */ #define SHT_MIPS_LIBLIST 0x70000000 #define SHT_MIPS_MSYM 0x70000001 #define SHT_MIPS_CONFLICT 0x70000002 #define SHT_MIPS_GPTAB 0x70000003 #define SHT_MIPS_UCODE 0x70000004 #define SHT_MIPS_DEBUG 0x70000005 #define SHT_MIPS_REGINFO 0x70000006 #define SHT_MIPS_PACKAGE 0x70000007 #define SHT_MIPS_PACKSYM 0x70000008 #define SHT_MIPS_RELD 0x70000009 #define SHT_MIPS_IFACE 0x7000000b #define SHT_MIPS_CONTENT 0x7000000c #define SHT_MIPS_OPTIONS 0x7000000d #define SHT_MIPS_DELTASYM 0x7000001b #define SHT_MIPS_DELTAINST 0x7000001c #define SHT_MIPS_DELTACLASS 0x7000001d #define SHT_MIPS_DWARF 0x7000001e /* MIPS gcc uses MIPS_DWARF */ #define SHT_MIPS_DELTADECL 0x7000001f #define SHT_MIPS_SYMBOL_LIB 0x70000020 #define SHT_MIPS_EVENTS 0x70000021 #define SHT_MIPS_TRANSLATE 0x70000022 #define SHT_MIPS_PIXIE 0x70000023 #define SHT_MIPS_XLATE 0x70000024 #define SHT_MIPS_XLATE_DEBUG 0x70000025 #define SHT_MIPS_WHIRL 0x70000026 #define SHT_MIPS_EH_REGION 0x70000027 #define SHT_MIPS_XLATE_OLD 0x70000028 #define SHT_MIPS_PDR_EXCEPTION 0x70000029 #define SHT_MIPS_ABIFLAGS 0x7000002a #define SHT_SPARC_GOTDATA 0x70000000 #define SHTORDERED #define SHT_HIPROC 0x7fffffff /* specific section header types */ #define SHT_LOUSER 0x80000000 /* reserved range for application */ #define SHT_HIUSER 0xffffffff /* specific indexes */ /* Flags for sh_flags. */ #define SHF_WRITE 0x1 /* Section contains writable data. */ #define SHF_ALLOC 0x2 /* Section occupies memory. */ #define SHF_EXECINSTR 0x4 /* Section contains instructions. */ #define SHF_MERGE 0x10 /* Section may be merged. */ #define SHF_STRINGS 0x20 /* Section contains strings. */ #define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ #define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ #define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ #define SHF_GROUP 0x200 /* Member of section group. */ #define SHF_TLS 0x400 /* Section contains TLS data. */ #define SHF_COMPRESSED 0x800 /* Section contains compressed data. */ #define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ #define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ /* Flags for section groups. */ #define GRP_COMDAT 0x1 /* COMDAT semantics. */ /* * Flags / mask for .gnu.versym sections. */ #define VERSYM_VERSION 0x7fff #define VERSYM_HIDDEN 0x8000 /* Values for p_type. */ #define PT_NULL 0 /* Unused entry. */ #define PT_LOAD 1 /* Loadable segment. */ #define PT_DYNAMIC 2 /* Dynamic linking information segment. */ #define PT_INTERP 3 /* Pathname of interpreter. */ #define PT_NOTE 4 /* Auxiliary information. */ #define PT_SHLIB 5 /* Reserved (not used). */ #define PT_PHDR 6 /* Location of program header itself. */ #define PT_TLS 7 /* Thread local storage segment */ #define PT_LOOS 0x60000000 /* First OS-specific. */ #define PT_SUNW_UNWIND 0x6464e550 /* amd64 UNWIND program header */ #define PT_GNU_EH_FRAME 0x6474e550 #define PT_GNU_STACK 0x6474e551 #define PT_GNU_RELRO 0x6474e552 #define PT_DUMP_DELTA 0x6fb5d000 /* va->pa map for kernel dumps (currently arm). */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* describes the stack segment */ #define PT_SUNWDTRACE 0x6ffffffc /* private */ #define PT_SUNWCAP 0x6ffffffd /* hard/soft capabilities segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6fffffff /* Last OS-specific. */ #define PT_LOPROC 0x70000000 /* First processor-specific type. */ #define PT_ARM_ARCHEXT 0x70000000 /* ARM arch compat information. */ #define PT_ARM_EXIDX 0x70000001 /* ARM exception unwind tables. */ #define PT_MIPS_REGINFO 0x70000000 /* MIPS register usage info */ #define PT_MIPS_RTPROC 0x70000001 /* MIPS runtime procedure tbl */ #define PT_MIPS_OPTIONS 0x70000002 /* MIPS e_flags value*/ #define PT_MIPS_ABIFLAGS 0x70000003 /* MIPS fp mode */ #define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ #define PT_OPENBSD_RANDOMIZE 0x65A3DBE6 /* OpenBSD random data segment */ #define PT_OPENBSD_WXNEEDED 0x65A3DBE7 /* OpenBSD EXEC/WRITE pages needed */ #define PT_OPENBSD_BOOTDATA 0x65A41BE6 /* OpenBSD section for boot args */ /* Values for p_flags. */ #define PF_X 0x1 /* Executable. */ #define PF_W 0x2 /* Writable. */ #define PF_R 0x4 /* Readable. */ #define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ #define PF_MASKPROC 0xf0000000 /* Processor-specific. */ /* Extended program header index. */ #define PN_XNUM 0xffff /* Values for d_tag. */ #define DT_NULL 0 /* Terminating entry. */ #define DT_NEEDED 1 /* String table offset of a needed shared library. */ #define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ #define DT_PLTGOT 3 /* Processor-dependent address. */ #define DT_HASH 4 /* Address of symbol hash table. */ #define DT_STRTAB 5 /* Address of string table. */ #define DT_SYMTAB 6 /* Address of symbol table. */ #define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ #define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ #define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ #define DT_STRSZ 10 /* Size of string table. */ #define DT_SYMENT 11 /* Size of each symbol table entry. */ #define DT_INIT 12 /* Address of initialization function. */ #define DT_FINI 13 /* Address of finalization function. */ #define DT_SONAME 14 /* String table offset of shared object name. */ #define DT_RPATH 15 /* String table offset of library path. [sup] */ #define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ #define DT_REL 17 /* Address of ElfNN_Rel relocations. */ #define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ #define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ #define DT_PLTREL 20 /* Type of relocation used for PLT. */ #define DT_DEBUG 21 /* Reserved (not used). */ #define DT_TEXTREL 22 /* Indicates there may be relocations in non-writable segments. [sup] */ #define DT_JMPREL 23 /* Address of PLT relocations. */ #define DT_BIND_NOW 24 /* [sup] */ #define DT_INIT_ARRAY 25 /* Address of the array of pointers to initialization functions */ #define DT_FINI_ARRAY 26 /* Address of the array of pointers to termination functions */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of initialization functions. */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of termination functions. */ #define DT_RUNPATH 29 /* String table offset of a null-terminated library search path string. */ #define DT_FLAGS 30 /* Object specific flag values. */ #define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING and less than DT_LOOS follow the rules for the interpretation of the d_un union as follows: even == 'd_ptr', odd == 'd_val' or none */ #define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to pre-initialization functions. */ #define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of pre-initialization functions. */ #define DT_MAXPOSTAGS 34 /* number of positive tags */ #define DT_LOOS 0x6000000d /* First OS-specific */ #define DT_SUNW_AUXILIARY 0x6000000d /* symbol auxiliary name */ #define DT_SUNW_RTLDINF 0x6000000e /* ld.so.1 info (private) */ #define DT_SUNW_FILTER 0x6000000f /* symbol filter name */ #define DT_SUNW_CAP 0x60000010 /* hardware/software */ #define DT_SUNW_ASLR 0x60000023 /* ASLR control */ #define DT_HIOS 0x6ffff000 /* Last OS-specific */ /* * DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the * Dyn.d_un.d_val field of the Elf*_Dyn structure. */ #define DT_VALRNGLO 0x6ffffd00 #define DT_GNU_PRELINKED 0x6ffffdf5 /* prelinking timestamp */ #define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* size of conflict section */ #define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* size of library list */ #define DT_CHECKSUM 0x6ffffdf8 /* elf checksum */ #define DT_PLTPADSZ 0x6ffffdf9 /* pltpadding size */ #define DT_MOVEENT 0x6ffffdfa /* move table entry size */ #define DT_MOVESZ 0x6ffffdfb /* move table size */ #define DT_FEATURE 0x6ffffdfc /* feature holder */ #define DT_FEATURE_1 DT_FEATURE #define DT_POSFLAG_1 0x6ffffdfd /* flags for DT_* entries, effecting */ /* the following DT_* entry. */ /* See DF_P1_* definitions */ #define DT_SYMINSZ 0x6ffffdfe /* syminfo table size (in bytes) */ #define DT_SYMINENT 0x6ffffdff /* syminfo entry size (in bytes) */ #define DT_VALRNGHI 0x6ffffdff /* * DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the * Dyn.d_un.d_ptr field of the Elf*_Dyn structure. * * If any adjustment is made to the ELF object after it has been * built, these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 #define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table */ #define DT_TLSDESC_PLT 0x6ffffef6 /* loc. of PLT for tlsdesc resolver */ #define DT_TLSDESC_GOT 0x6ffffef7 /* loc. of GOT for tlsdesc resolver */ #define DT_GNU_CONFLICT 0x6ffffef8 /* address of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* address of library list */ #define DT_CONFIG 0x6ffffefa /* configuration information */ #define DT_DEPAUDIT 0x6ffffefb /* dependency auditing */ #define DT_AUDIT 0x6ffffefc /* object auditing */ #define DT_PLTPAD 0x6ffffefd /* pltpadding (sparcv9) */ #define DT_MOVETAB 0x6ffffefe /* move table */ #define DT_SYMINFO 0x6ffffeff /* syminfo table */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_VERSYM 0x6ffffff0 /* Address of versym section. */ #define DT_RELACOUNT 0x6ffffff9 /* number of RELATIVE relocations */ #define DT_RELCOUNT 0x6ffffffa /* number of RELATIVE relocations */ #define DT_FLAGS_1 0x6ffffffb /* state flags - see DF_1_* defs */ #define DT_VERDEF 0x6ffffffc /* Address of verdef section. */ #define DT_VERDEFNUM 0x6ffffffd /* Number of elems in verdef section */ #define DT_VERNEED 0x6ffffffe /* Address of verneed section. */ #define DT_VERNEEDNUM 0x6fffffff /* Number of elems in verneed section */ #define DT_LOPROC 0x70000000 /* First processor-specific type. */ #define DT_ARM_SYMTABSZ 0x70000001 #define DT_ARM_PREEMPTMAP 0x70000002 #define DT_SPARC_REGISTER 0x70000001 #define DT_DEPRECATED_SPARC_REGISTER 0x7000001 #define DT_MIPS_RLD_VERSION 0x70000001 #define DT_MIPS_TIME_STAMP 0x70000002 #define DT_MIPS_ICHECKSUM 0x70000003 #define DT_MIPS_IVERSION 0x70000004 #define DT_MIPS_FLAGS 0x70000005 #define DT_MIPS_BASE_ADDRESS 0x70000006 #define DT_MIPS_CONFLICT 0x70000008 #define DT_MIPS_LIBLIST 0x70000009 #define DT_MIPS_LOCAL_GOTNO 0x7000000a #define DT_MIPS_CONFLICTNO 0x7000000b #define DT_MIPS_LIBLISTNO 0x70000010 #define DT_MIPS_SYMTABNO 0x70000011 #define DT_MIPS_UNREFEXTNO 0x70000012 #define DT_MIPS_GOTSYM 0x70000013 #define DT_MIPS_HIPAGENO 0x70000014 #define DT_MIPS_RLD_MAP 0x70000016 #define DT_MIPS_DELTA_CLASS 0x70000017 #define DT_MIPS_DELTA_CLASS_NO 0x70000018 #define DT_MIPS_DELTA_INSTANCE 0x70000019 #define DT_MIPS_DELTA_INSTANCE_NO 0x7000001A #define DT_MIPS_DELTA_RELOC 0x7000001B #define DT_MIPS_DELTA_RELOC_NO 0x7000001C #define DT_MIPS_DELTA_SYM 0x7000001D #define DT_MIPS_DELTA_SYM_NO 0x7000001E #define DT_MIPS_DELTA_CLASSSYM 0x70000020 #define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 #define DT_MIPS_CXX_FLAGS 0x70000022 #define DT_MIPS_PIXIE_INIT 0x70000023 #define DT_MIPS_SYMBOL_LIB 0x70000024 #define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 #define DT_MIPS_LOCAL_GOTIDX 0x70000026 #define DT_MIPS_HIDDEN_GOTIDX 0x70000027 #define DT_MIPS_PROTECTED_GOTIDX 0x70000028 #define DT_MIPS_OPTIONS 0x70000029 #define DT_MIPS_INTERFACE 0x7000002A #define DT_MIPS_DYNSTR_ALIGN 0x7000002B #define DT_MIPS_INTERFACE_SIZE 0x7000002C #define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002D #define DT_MIPS_PERF_SUFFIX 0x7000002E #define DT_MIPS_COMPACT_SIZE 0x7000002F #define DT_MIPS_GP_VALUE 0x70000030 #define DT_MIPS_AUX_DYNAMIC 0x70000031 #define DT_MIPS_PLTGOT 0x70000032 #define DT_MIPS_RLD_OBJ_UPDATE 0x70000033 #define DT_MIPS_RWPLT 0x70000034 #define DT_PPC_GOT 0x70000000 #define DT_PPC_TLSOPT 0x70000001 #define DT_PPC64_GLINK 0x70000000 #define DT_PPC64_OPD 0x70000001 #define DT_PPC64_OPDSZ 0x70000002 #define DT_PPC64_TLSOPT 0x70000003 #define DT_AUXILIARY 0x7ffffffd /* shared library auxiliary name */ #define DT_USED 0x7ffffffe /* ignored - same as needed */ #define DT_FILTER 0x7fffffff /* shared library filter name */ #define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ /* Values for DT_FLAGS */ #define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may make reference to the $ORIGIN substitution string */ #define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ #define DF_TEXTREL 0x0004 /* Indicates there may be relocations in non-writable segments. */ #define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should process all relocations for the object containing this entry before transferring control to the program. */ #define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or executable contains code using a static thread-local storage scheme. */ /* Values for DT_FLAGS_1 */ #define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */ #define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */ #define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */ #define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filtees */ #define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ #define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */ #define DF_1_INTERPOSE 0x00000400 /* Interpose all objects but main */ #define DF_1_NODEFLIB 0x00000800 /* Do not search default paths */ #define DF_1_PIE 0x08000000 /* Is position-independent executable */ /* Values for l_flags. */ #define LL_NONE 0x0 /* no flags */ #define LL_EXACT_MATCH 0x1 /* require an exact match */ #define LL_IGNORE_INT_VER 0x2 /* ignore version incompatibilities */ #define LL_REQUIRE_MINOR 0x4 #define LL_EXPORTS 0x8 #define LL_DELAY_LOAD 0x10 #define LL_DELTA 0x20 /* Note section names */ #define ELF_NOTE_FREEBSD "FreeBSD" #define ELF_NOTE_NETBSD "NetBSD" #define ELF_NOTE_SOLARIS "SUNW Solaris" #define ELF_NOTE_GNU "GNU" /* Values for n_type used in executables. */ #define NT_FREEBSD_ABI_TAG 1 #define NT_FREEBSD_NOINIT_TAG 2 #define NT_FREEBSD_ARCH_TAG 3 #define NT_FREEBSD_FEATURE_CTL 4 /* NT_FREEBSD_FEATURE_CTL desc[0] bits */ #define NT_FREEBSD_FCTL_ASLR_DISABLE 0x00000001 #define NT_FREEBSD_FCTL_PROTMAX_DISABLE 0x00000002 #define NT_FREEBSD_FCTL_STKGAP_DISABLE 0x00000004 #define NT_FREEBSD_FCTL_WXNEEDED 0x00000008 +#define NT_FREEBSD_FCTL_LA48 0x00000010 /* Values for n_type. Used in core files. */ #define NT_PRSTATUS 1 /* Process status. */ #define NT_FPREGSET 2 /* Floating point registers. */ #define NT_PRPSINFO 3 /* Process state info. */ #define NT_THRMISC 7 /* Thread miscellaneous info. */ #define NT_PROCSTAT_PROC 8 /* Procstat proc data. */ #define NT_PROCSTAT_FILES 9 /* Procstat files data. */ #define NT_PROCSTAT_VMMAP 10 /* Procstat vmmap data. */ #define NT_PROCSTAT_GROUPS 11 /* Procstat groups data. */ #define NT_PROCSTAT_UMASK 12 /* Procstat umask data. */ #define NT_PROCSTAT_RLIMIT 13 /* Procstat rlimit data. */ #define NT_PROCSTAT_OSREL 14 /* Procstat osreldate data. */ #define NT_PROCSTAT_PSSTRINGS 15 /* Procstat ps_strings data. */ #define NT_PROCSTAT_AUXV 16 /* Procstat auxv data. */ #define NT_PTLWPINFO 17 /* Thread ptrace miscellaneous info. */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_X86_XSTATE 0x202 /* x86 XSAVE extended state. */ #define NT_ARM_VFP 0x400 /* ARM VFP registers */ /* GNU note types. */ #define NT_GNU_ABI_TAG 1 #define NT_GNU_HWCAP 2 #define NT_GNU_BUILD_ID 3 #define NT_GNU_GOLD_VERSION 4 #define NT_GNU_PROPERTY_TYPE_0 5 #define GNU_PROPERTY_LOPROC 0xc0000000 #define GNU_PROPERTY_HIPROC 0xdfffffff #define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002 #define GNU_PROPERTY_X86_FEATURE_1_IBT 0x00000001 #define GNU_PROPERTY_X86_FEATURE_1_SHSTK 0x00000002 /* Symbol Binding - ELFNN_ST_BIND - st_info */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* like global - lower precedence */ #define STB_LOOS 10 /* Start of operating system reserved range. */ #define STB_GNU_UNIQUE 10 /* Unique symbol (GNU) */ #define STB_HIOS 12 /* End of operating system reserved range. */ #define STB_LOPROC 13 /* reserved range for processor */ #define STB_HIPROC 15 /* specific semantics. */ /* Symbol type - ELFNN_ST_TYPE - st_info */ #define STT_NOTYPE 0 /* Unspecified type. */ #define STT_OBJECT 1 /* Data object. */ #define STT_FUNC 2 /* Function. */ #define STT_SECTION 3 /* Section. */ #define STT_FILE 4 /* Source file. */ #define STT_COMMON 5 /* Uninitialized common block. */ #define STT_TLS 6 /* TLS object. */ #define STT_NUM 7 #define STT_LOOS 10 /* Reserved range for operating system */ #define STT_GNU_IFUNC 10 #define STT_HIOS 12 /* specific semantics. */ #define STT_LOPROC 13 /* Start of processor reserved range. */ #define STT_SPARC_REGISTER 13 /* SPARC register information. */ #define STT_HIPROC 15 /* End of processor reserved range. */ /* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ #define STV_DEFAULT 0x0 /* Default visibility (see binding). */ #define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ #define STV_HIDDEN 0x2 /* Not visible. */ #define STV_PROTECTED 0x3 /* Visible but not preemptible. */ #define STV_EXPORTED 0x4 #define STV_SINGLETON 0x5 #define STV_ELIMINATE 0x6 /* Special symbol table indexes. */ #define STN_UNDEF 0 /* Undefined symbol index. */ /* Symbol versioning flags. */ #define VER_DEF_CURRENT 1 #define VER_DEF_IDX(x) VER_NDX(x) #define VER_FLG_BASE 0x01 #define VER_FLG_WEAK 0x02 #define VER_NEED_CURRENT 1 #define VER_NEED_WEAK (1u << 15) #define VER_NEED_HIDDEN VER_NDX_HIDDEN #define VER_NEED_IDX(x) VER_NDX(x) #define VER_NDX_LOCAL 0 #define VER_NDX_GLOBAL 1 #define VER_NDX_GIVEN 2 #define VER_NDX_HIDDEN (1u << 15) #define VER_NDX(x) ((x) & ~(1u << 15)) #define CA_SUNW_NULL 0 #define CA_SUNW_HW_1 1 /* first hardware capabilities entry */ #define CA_SUNW_SF_1 2 /* first software capabilities entry */ /* * Syminfo flag values */ #define SYMINFO_FLG_DIRECT 0x0001 /* symbol ref has direct association */ /* to object containing defn. */ #define SYMINFO_FLG_PASSTHRU 0x0002 /* ignored - see SYMINFO_FLG_FILTER */ #define SYMINFO_FLG_COPY 0x0004 /* symbol is a copy-reloc */ #define SYMINFO_FLG_LAZYLOAD 0x0008 /* object containing defn should be */ /* lazily-loaded */ #define SYMINFO_FLG_DIRECTBIND 0x0010 /* ref should be bound directly to */ /* object containing defn. */ #define SYMINFO_FLG_NOEXTDIRECT 0x0020 /* don't let an external reference */ /* directly bind to this symbol */ #define SYMINFO_FLG_FILTER 0x0002 /* symbol ref is associated to a */ #define SYMINFO_FLG_AUXILIARY 0x0040 /* standard or auxiliary filter */ /* * Syminfo.si_boundto values. */ #define SYMINFO_BT_SELF 0xffff /* symbol bound to self */ #define SYMINFO_BT_PARENT 0xfffe /* symbol bound to parent */ #define SYMINFO_BT_NONE 0xfffd /* no special symbol binding */ #define SYMINFO_BT_EXTERN 0xfffc /* symbol defined as external */ #define SYMINFO_BT_LOWRESERVE 0xff00 /* beginning of reserved entries */ /* * Syminfo version values. */ #define SYMINFO_NONE 0 /* Syminfo version */ #define SYMINFO_CURRENT 1 #define SYMINFO_NUM 2 /* Values for ch_type (compressed section headers). */ #define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE */ #define ELFCOMPRESS_LOOS 0x60000000 /* OS-specific */ #define ELFCOMPRESS_HIOS 0x6fffffff #define ELFCOMPRESS_LOPROC 0x70000000 /* Processor-specific */ #define ELFCOMPRESS_HIPROC 0x7fffffff /* * Relocation types. * * All machine architectures are defined here to allow tools on one to * handle others. */ #define R_386_NONE 0 /* No relocation. */ #define R_386_32 1 /* Add symbol value. */ #define R_386_PC32 2 /* Add PC-relative symbol value. */ #define R_386_GOT32 3 /* Add PC-relative GOT offset. */ #define R_386_PLT32 4 /* Add PC-relative PLT offset. */ #define R_386_COPY 5 /* Copy data from shared object. */ #define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ #define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ #define R_386_RELATIVE 8 /* Add load address of shared object. */ #define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ #define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ #define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ #define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ #define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ #define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ #define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ #define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ #define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ #define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ #define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ #define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ #define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ #define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ #define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ #define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ #define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ #define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ #define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ #define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ #define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ #define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ #define R_386_IRELATIVE 42 /* PLT entry resolved indirectly at runtime */ #define R_AARCH64_NONE 0 /* No relocation */ #define R_AARCH64_ABS64 257 /* Absolute offset */ #define R_AARCH64_ABS32 258 /* Absolute, 32-bit overflow check */ #define R_AARCH64_ABS16 259 /* Absolute, 16-bit overflow check */ #define R_AARCH64_PREL64 260 /* PC relative */ #define R_AARCH64_PREL32 261 /* PC relative, 32-bit overflow check */ #define R_AARCH64_PREL16 262 /* PC relative, 16-bit overflow check */ #define R_AARCH64_TSTBR14 279 /* TBZ/TBNZ immediate */ #define R_AARCH64_CONDBR19 280 /* Conditional branch immediate */ #define R_AARCH64_JUMP26 282 /* Branch immediate */ #define R_AARCH64_CALL26 283 /* Call immediate */ #define R_AARCH64_COPY 1024 /* Copy data from shared object */ #define R_AARCH64_GLOB_DAT 1025 /* Set GOT entry to data address */ #define R_AARCH64_JUMP_SLOT 1026 /* Set GOT entry to code address */ #define R_AARCH64_RELATIVE 1027 /* Add load address of shared object */ #define R_AARCH64_TLS_DTPREL64 1028 #define R_AARCH64_TLS_DTPMOD64 1029 #define R_AARCH64_TLS_TPREL64 1030 #define R_AARCH64_TLSDESC 1031 /* Identify the TLS descriptor */ #define R_AARCH64_IRELATIVE 1032 #define R_ARM_NONE 0 /* No relocation. */ #define R_ARM_PC24 1 #define R_ARM_ABS32 2 #define R_ARM_REL32 3 #define R_ARM_PC13 4 #define R_ARM_ABS16 5 #define R_ARM_ABS12 6 #define R_ARM_THM_ABS5 7 #define R_ARM_ABS8 8 #define R_ARM_SBREL32 9 #define R_ARM_THM_PC22 10 #define R_ARM_THM_PC8 11 #define R_ARM_AMP_VCALL9 12 #define R_ARM_SWI24 13 #define R_ARM_THM_SWI8 14 #define R_ARM_XPC25 15 #define R_ARM_THM_XPC22 16 /* TLS relocations */ #define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ #define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ #define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ #define R_ARM_COPY 20 /* Copy data from shared object. */ #define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ #define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ #define R_ARM_RELATIVE 23 /* Add load address of shared object. */ #define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ #define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ #define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ #define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ #define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTINHERIT 101 #define R_ARM_RSBREL32 250 #define R_ARM_THM_RPC22 251 #define R_ARM_RREL32 252 #define R_ARM_RABS32 253 #define R_ARM_RPC24 254 #define R_ARM_RBASE 255 /* Name Value Field Calculation */ #define R_IA_64_NONE 0 /* None */ #define R_IA_64_IMM14 0x21 /* immediate14 S + A */ #define R_IA_64_IMM22 0x22 /* immediate22 S + A */ #define R_IA_64_IMM64 0x23 /* immediate64 S + A */ #define R_IA_64_DIR32MSB 0x24 /* word32 MSB S + A */ #define R_IA_64_DIR32LSB 0x25 /* word32 LSB S + A */ #define R_IA_64_DIR64MSB 0x26 /* word64 MSB S + A */ #define R_IA_64_DIR64LSB 0x27 /* word64 LSB S + A */ #define R_IA_64_GPREL22 0x2a /* immediate22 @gprel(S + A) */ #define R_IA_64_GPREL64I 0x2b /* immediate64 @gprel(S + A) */ #define R_IA_64_GPREL32MSB 0x2c /* word32 MSB @gprel(S + A) */ #define R_IA_64_GPREL32LSB 0x2d /* word32 LSB @gprel(S + A) */ #define R_IA_64_GPREL64MSB 0x2e /* word64 MSB @gprel(S + A) */ #define R_IA_64_GPREL64LSB 0x2f /* word64 LSB @gprel(S + A) */ #define R_IA_64_LTOFF22 0x32 /* immediate22 @ltoff(S + A) */ #define R_IA_64_LTOFF64I 0x33 /* immediate64 @ltoff(S + A) */ #define R_IA_64_PLTOFF22 0x3a /* immediate22 @pltoff(S + A) */ #define R_IA_64_PLTOFF64I 0x3b /* immediate64 @pltoff(S + A) */ #define R_IA_64_PLTOFF64MSB 0x3e /* word64 MSB @pltoff(S + A) */ #define R_IA_64_PLTOFF64LSB 0x3f /* word64 LSB @pltoff(S + A) */ #define R_IA_64_FPTR64I 0x43 /* immediate64 @fptr(S + A) */ #define R_IA_64_FPTR32MSB 0x44 /* word32 MSB @fptr(S + A) */ #define R_IA_64_FPTR32LSB 0x45 /* word32 LSB @fptr(S + A) */ #define R_IA_64_FPTR64MSB 0x46 /* word64 MSB @fptr(S + A) */ #define R_IA_64_FPTR64LSB 0x47 /* word64 LSB @fptr(S + A) */ #define R_IA_64_PCREL60B 0x48 /* immediate60 form1 S + A - P */ #define R_IA_64_PCREL21B 0x49 /* immediate21 form1 S + A - P */ #define R_IA_64_PCREL21M 0x4a /* immediate21 form2 S + A - P */ #define R_IA_64_PCREL21F 0x4b /* immediate21 form3 S + A - P */ #define R_IA_64_PCREL32MSB 0x4c /* word32 MSB S + A - P */ #define R_IA_64_PCREL32LSB 0x4d /* word32 LSB S + A - P */ #define R_IA_64_PCREL64MSB 0x4e /* word64 MSB S + A - P */ #define R_IA_64_PCREL64LSB 0x4f /* word64 LSB S + A - P */ #define R_IA_64_LTOFF_FPTR22 0x52 /* immediate22 @ltoff(@fptr(S + A)) */ #define R_IA_64_LTOFF_FPTR64I 0x53 /* immediate64 @ltoff(@fptr(S + A)) */ #define R_IA_64_LTOFF_FPTR32MSB 0x54 /* word32 MSB @ltoff(@fptr(S + A)) */ #define R_IA_64_LTOFF_FPTR32LSB 0x55 /* word32 LSB @ltoff(@fptr(S + A)) */ #define R_IA_64_LTOFF_FPTR64MSB 0x56 /* word64 MSB @ltoff(@fptr(S + A)) */ #define R_IA_64_LTOFF_FPTR64LSB 0x57 /* word64 LSB @ltoff(@fptr(S + A)) */ #define R_IA_64_SEGREL32MSB 0x5c /* word32 MSB @segrel(S + A) */ #define R_IA_64_SEGREL32LSB 0x5d /* word32 LSB @segrel(S + A) */ #define R_IA_64_SEGREL64MSB 0x5e /* word64 MSB @segrel(S + A) */ #define R_IA_64_SEGREL64LSB 0x5f /* word64 LSB @segrel(S + A) */ #define R_IA_64_SECREL32MSB 0x64 /* word32 MSB @secrel(S + A) */ #define R_IA_64_SECREL32LSB 0x65 /* word32 LSB @secrel(S + A) */ #define R_IA_64_SECREL64MSB 0x66 /* word64 MSB @secrel(S + A) */ #define R_IA_64_SECREL64LSB 0x67 /* word64 LSB @secrel(S + A) */ #define R_IA_64_REL32MSB 0x6c /* word32 MSB BD + A */ #define R_IA_64_REL32LSB 0x6d /* word32 LSB BD + A */ #define R_IA_64_REL64MSB 0x6e /* word64 MSB BD + A */ #define R_IA_64_REL64LSB 0x6f /* word64 LSB BD + A */ #define R_IA_64_LTV32MSB 0x74 /* word32 MSB S + A */ #define R_IA_64_LTV32LSB 0x75 /* word32 LSB S + A */ #define R_IA_64_LTV64MSB 0x76 /* word64 MSB S + A */ #define R_IA_64_LTV64LSB 0x77 /* word64 LSB S + A */ #define R_IA_64_PCREL21BI 0x79 /* immediate21 form1 S + A - P */ #define R_IA_64_PCREL22 0x7a /* immediate22 S + A - P */ #define R_IA_64_PCREL64I 0x7b /* immediate64 S + A - P */ #define R_IA_64_IPLTMSB 0x80 /* function descriptor MSB special */ #define R_IA_64_IPLTLSB 0x81 /* function descriptor LSB speciaal */ #define R_IA_64_SUB 0x85 /* immediate64 A - S */ #define R_IA_64_LTOFF22X 0x86 /* immediate22 special */ #define R_IA_64_LDXMOV 0x87 /* immediate22 special */ #define R_IA_64_TPREL14 0x91 /* imm14 @tprel(S + A) */ #define R_IA_64_TPREL22 0x92 /* imm22 @tprel(S + A) */ #define R_IA_64_TPREL64I 0x93 /* imm64 @tprel(S + A) */ #define R_IA_64_TPREL64MSB 0x96 /* word64 MSB @tprel(S + A) */ #define R_IA_64_TPREL64LSB 0x97 /* word64 LSB @tprel(S + A) */ #define R_IA_64_LTOFF_TPREL22 0x9a /* imm22 @ltoff(@tprel(S+A)) */ #define R_IA_64_DTPMOD64MSB 0xa6 /* word64 MSB @dtpmod(S + A) */ #define R_IA_64_DTPMOD64LSB 0xa7 /* word64 LSB @dtpmod(S + A) */ #define R_IA_64_LTOFF_DTPMOD22 0xaa /* imm22 @ltoff(@dtpmod(S+A)) */ #define R_IA_64_DTPREL14 0xb1 /* imm14 @dtprel(S + A) */ #define R_IA_64_DTPREL22 0xb2 /* imm22 @dtprel(S + A) */ #define R_IA_64_DTPREL64I 0xb3 /* imm64 @dtprel(S + A) */ #define R_IA_64_DTPREL32MSB 0xb4 /* word32 MSB @dtprel(S + A) */ #define R_IA_64_DTPREL32LSB 0xb5 /* word32 LSB @dtprel(S + A) */ #define R_IA_64_DTPREL64MSB 0xb6 /* word64 MSB @dtprel(S + A) */ #define R_IA_64_DTPREL64LSB 0xb7 /* word64 LSB @dtprel(S + A) */ #define R_IA_64_LTOFF_DTPREL22 0xba /* imm22 @ltoff(@dtprel(S+A)) */ #define R_MIPS_NONE 0 /* No reloc */ #define R_MIPS_16 1 /* Direct 16 bit */ #define R_MIPS_32 2 /* Direct 32 bit */ #define R_MIPS_REL32 3 /* PC relative 32 bit */ #define R_MIPS_26 4 /* Direct 26 bit shifted */ #define R_MIPS_HI16 5 /* High 16 bit */ #define R_MIPS_LO16 6 /* Low 16 bit */ #define R_MIPS_GPREL16 7 /* GP relative 16 bit */ #define R_MIPS_LITERAL 8 /* 16 bit literal entry */ #define R_MIPS_GOT16 9 /* 16 bit GOT entry */ #define R_MIPS_PC16 10 /* PC relative 16 bit */ #define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ #define R_MIPS_GPREL32 12 /* GP relative 32 bit */ #define R_MIPS_64 18 /* Direct 64 bit */ #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 /* GOT HI 16 bit */ #define R_MIPS_GOT_LO16 23 /* GOT LO 16 bit */ #define R_MIPS_SUB 24 #define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ #define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ #define R_MIPS_JALR 37 #define R_MIPS_TLS_GD 42 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 #define R_PPC_NONE 0 /* No relocation. */ #define R_PPC_ADDR32 1 #define R_PPC_ADDR24 2 #define R_PPC_ADDR16 3 #define R_PPC_ADDR16_LO 4 #define R_PPC_ADDR16_HI 5 #define R_PPC_ADDR16_HA 6 #define R_PPC_ADDR14 7 #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 #define R_PPC_REL14 11 #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* * 64-bit relocations */ #define R_PPC64_ADDR64 38 #define R_PPC64_ADDR16_HIGHER 39 #define R_PPC64_ADDR16_HIGHERA 40 #define R_PPC64_ADDR16_HIGHEST 41 #define R_PPC64_ADDR16_HIGHESTA 42 #define R_PPC64_UADDR64 43 #define R_PPC64_REL64 44 #define R_PPC64_PLT64 45 #define R_PPC64_PLTREL64 46 #define R_PPC64_TOC16 47 #define R_PPC64_TOC16_LO 48 #define R_PPC64_TOC16_HI 49 #define R_PPC64_TOC16_HA 50 #define R_PPC64_TOC 51 #define R_PPC64_DTPMOD64 68 #define R_PPC64_TPREL64 73 #define R_PPC64_DTPREL64 78 /* * TLS relocations */ #define R_PPC_TLS 67 #define R_PPC_DTPMOD32 68 #define R_PPC_TPREL16 69 #define R_PPC_TPREL16_LO 70 #define R_PPC_TPREL16_HI 71 #define R_PPC_TPREL16_HA 72 #define R_PPC_TPREL32 73 #define R_PPC_DTPREL16 74 #define R_PPC_DTPREL16_LO 75 #define R_PPC_DTPREL16_HI 76 #define R_PPC_DTPREL16_HA 77 #define R_PPC_DTPREL32 78 #define R_PPC_GOT_TLSGD16 79 #define R_PPC_GOT_TLSGD16_LO 80 #define R_PPC_GOT_TLSGD16_HI 81 #define R_PPC_GOT_TLSGD16_HA 82 #define R_PPC_GOT_TLSLD16 83 #define R_PPC_GOT_TLSLD16_LO 84 #define R_PPC_GOT_TLSLD16_HI 85 #define R_PPC_GOT_TLSLD16_HA 86 #define R_PPC_GOT_TPREL16 87 #define R_PPC_GOT_TPREL16_LO 88 #define R_PPC_GOT_TPREL16_HI 89 #define R_PPC_GOT_TPREL16_HA 90 /* * The remaining relocs are from the Embedded ELF ABI, and are not in the * SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* * RISC-V relocation types. */ /* Relocation types used by the dynamic linker. */ #define R_RISCV_NONE 0 #define R_RISCV_32 1 #define R_RISCV_64 2 #define R_RISCV_RELATIVE 3 #define R_RISCV_COPY 4 #define R_RISCV_JUMP_SLOT 5 #define R_RISCV_TLS_DTPMOD32 6 #define R_RISCV_TLS_DTPMOD64 7 #define R_RISCV_TLS_DTPREL32 8 #define R_RISCV_TLS_DTPREL64 9 #define R_RISCV_TLS_TPREL32 10 #define R_RISCV_TLS_TPREL64 11 /* Relocation types not used by the dynamic linker. */ #define R_RISCV_BRANCH 16 #define R_RISCV_JAL 17 #define R_RISCV_CALL 18 #define R_RISCV_CALL_PLT 19 #define R_RISCV_GOT_HI20 20 #define R_RISCV_TLS_GOT_HI20 21 #define R_RISCV_TLS_GD_HI20 22 #define R_RISCV_PCREL_HI20 23 #define R_RISCV_PCREL_LO12_I 24 #define R_RISCV_PCREL_LO12_S 25 #define R_RISCV_HI20 26 #define R_RISCV_LO12_I 27 #define R_RISCV_LO12_S 28 #define R_RISCV_TPREL_HI20 29 #define R_RISCV_TPREL_LO12_I 30 #define R_RISCV_TPREL_LO12_S 31 #define R_RISCV_TPREL_ADD 32 #define R_RISCV_ADD8 33 #define R_RISCV_ADD16 34 #define R_RISCV_ADD32 35 #define R_RISCV_ADD64 36 #define R_RISCV_SUB8 37 #define R_RISCV_SUB16 38 #define R_RISCV_SUB32 39 #define R_RISCV_SUB64 40 #define R_RISCV_GNU_VTINHERIT 41 #define R_RISCV_GNU_VTENTRY 42 #define R_RISCV_ALIGN 43 #define R_RISCV_RVC_BRANCH 44 #define R_RISCV_RVC_JUMP 45 #define R_RISCV_RVC_LUI 46 #define R_RISCV_GPREL_I 47 #define R_RISCV_GPREL_S 48 #define R_RISCV_TPREL_I 49 #define R_RISCV_TPREL_S 50 #define R_RISCV_RELAX 51 #define R_RISCV_SUB6 52 #define R_RISCV_SET6 53 #define R_RISCV_SET8 54 #define R_RISCV_SET16 55 #define R_RISCV_SET32 56 #define R_RISCV_32_PCREL 57 #define R_RISCV_IRELATIVE 58 #define R_SPARC_NONE 0 #define R_SPARC_8 1 #define R_SPARC_16 2 #define R_SPARC_32 3 #define R_SPARC_DISP8 4 #define R_SPARC_DISP16 5 #define R_SPARC_DISP32 6 #define R_SPARC_WDISP30 7 #define R_SPARC_WDISP22 8 #define R_SPARC_HI22 9 #define R_SPARC_22 10 #define R_SPARC_13 11 #define R_SPARC_LO10 12 #define R_SPARC_GOT10 13 #define R_SPARC_GOT13 14 #define R_SPARC_GOT22 15 #define R_SPARC_PC10 16 #define R_SPARC_PC22 17 #define R_SPARC_WPLT30 18 #define R_SPARC_COPY 19 #define R_SPARC_GLOB_DAT 20 #define R_SPARC_JMP_SLOT 21 #define R_SPARC_RELATIVE 22 #define R_SPARC_UA32 23 #define R_SPARC_PLT32 24 #define R_SPARC_HIPLT22 25 #define R_SPARC_LOPLT10 26 #define R_SPARC_PCPLT32 27 #define R_SPARC_PCPLT22 28 #define R_SPARC_PCPLT10 29 #define R_SPARC_10 30 #define R_SPARC_11 31 #define R_SPARC_64 32 #define R_SPARC_OLO10 33 #define R_SPARC_HH22 34 #define R_SPARC_HM10 35 #define R_SPARC_LM22 36 #define R_SPARC_PC_HH22 37 #define R_SPARC_PC_HM10 38 #define R_SPARC_PC_LM22 39 #define R_SPARC_WDISP16 40 #define R_SPARC_WDISP19 41 #define R_SPARC_GLOB_JMP 42 #define R_SPARC_7 43 #define R_SPARC_5 44 #define R_SPARC_6 45 #define R_SPARC_DISP64 46 #define R_SPARC_PLT64 47 #define R_SPARC_HIX22 48 #define R_SPARC_LOX10 49 #define R_SPARC_H44 50 #define R_SPARC_M44 51 #define R_SPARC_L44 52 #define R_SPARC_REGISTER 53 #define R_SPARC_UA64 54 #define R_SPARC_UA16 55 #define R_SPARC_TLS_GD_HI22 56 #define R_SPARC_TLS_GD_LO10 57 #define R_SPARC_TLS_GD_ADD 58 #define R_SPARC_TLS_GD_CALL 59 #define R_SPARC_TLS_LDM_HI22 60 #define R_SPARC_TLS_LDM_LO10 61 #define R_SPARC_TLS_LDM_ADD 62 #define R_SPARC_TLS_LDM_CALL 63 #define R_SPARC_TLS_LDO_HIX22 64 #define R_SPARC_TLS_LDO_LOX10 65 #define R_SPARC_TLS_LDO_ADD 66 #define R_SPARC_TLS_IE_HI22 67 #define R_SPARC_TLS_IE_LO10 68 #define R_SPARC_TLS_IE_LD 69 #define R_SPARC_TLS_IE_LDX 70 #define R_SPARC_TLS_IE_ADD 71 #define R_SPARC_TLS_LE_HIX22 72 #define R_SPARC_TLS_LE_LOX10 73 #define R_SPARC_TLS_DTPMOD32 74 #define R_SPARC_TLS_DTPMOD64 75 #define R_SPARC_TLS_DTPOFF32 76 #define R_SPARC_TLS_DTPOFF64 77 #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 #define R_X86_64_NONE 0 /* No relocation. */ #define R_X86_64_64 1 /* Add 64 bit symbol value. */ #define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ #define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ #define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ #define R_X86_64_COPY 5 /* Copy data from shared object. */ #define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ #define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ #define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ #define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ #define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ #define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ #define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ #define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ #define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ #define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ #define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ #define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ #define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ #define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ #define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ #define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ #define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ #define R_X86_64_PC64 24 /* PC-relative 64 bit signed sym value. */ #define R_X86_64_GOTOFF64 25 #define R_X86_64_GOTPC32 26 #define R_X86_64_GOT64 27 #define R_X86_64_GOTPCREL64 28 #define R_X86_64_GOTPC64 29 #define R_X86_64_GOTPLT64 30 #define R_X86_64_PLTOFF64 31 #define R_X86_64_SIZE32 32 #define R_X86_64_SIZE64 33 #define R_X86_64_GOTPC32_TLSDESC 34 #define R_X86_64_TLSDESC_CALL 35 #define R_X86_64_TLSDESC 36 #define R_X86_64_IRELATIVE 37 #endif /* !_SYS_ELF_COMMON_H_ */ Index: stable/12/usr.bin/elfctl/elfctl.c =================================================================== --- stable/12/usr.bin/elfctl/elfctl.c (revision 367461) +++ stable/12/usr.bin/elfctl/elfctl.c (revision 367462) @@ -1,401 +1,405 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2019 The FreeBSD Foundation. * * This software was developed by Bora Ozarslan under sponsorship from * the FreeBSD Foundation. * * 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 "_elftc.h" __FBSDID("$FreeBSD$"); static bool convert_to_feature_val(char *, uint32_t *); static bool edit_file_features(Elf *, int, int, char *); static bool get_file_features(Elf *, int, int, uint32_t *, uint64_t *); static void print_features(void); static bool print_file_features(Elf *, int, int, char *); static void usage(void); struct ControlFeatures { const char *alias; unsigned long value; const char *desc; }; static struct ControlFeatures featurelist[] = { { "aslr", NT_FREEBSD_FCTL_ASLR_DISABLE, "Disable ASLR" }, { "protmax", NT_FREEBSD_FCTL_PROTMAX_DISABLE, "Disable implicit PROT_MAX" }, { "stackgap", NT_FREEBSD_FCTL_STKGAP_DISABLE, "Disable stack gap" }, + { "wxneeded", NT_FREEBSD_FCTL_WXNEEDED, "Requires W+X mappings" }, +#ifdef NT_FREEBSD_FCTL_LA48 + { "la48", NT_FREEBSD_FCTL_LA48, "amd64: Limit user VA to 48bit" }, +#endif }; static struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; #if BYTE_ORDER == LITTLE_ENDIAN #define SUPPORTED_ENDIAN ELFDATA2LSB #else #define SUPPORTED_ENDIAN ELFDATA2MSB #endif int main(int argc, char **argv) { GElf_Ehdr ehdr; Elf *elf; Elf_Kind kind; int ch, fd, retval; char *features; bool editfeatures, lflag; lflag = 0; editfeatures = false; retval = 0; features = NULL; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "elf_version error"); while ((ch = getopt_long(argc, argv, "hle:", long_opts, NULL)) != -1) { switch (ch) { case 'l': print_features(); lflag = true; break; case 'e': features = optarg; editfeatures = true; break; case 'h': default: usage(); } } argc -= optind; argv += optind; if (argc == 0) { if (lflag) exit(0); else { warnx("no file(s) specified"); usage(); } } while (argc) { elf = NULL; if ((fd = open(argv[0], editfeatures ? O_RDWR : O_RDONLY, 0)) < 0) { warn("error opening file %s", argv[0]); retval = 1; goto fail; } if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warnx("elf_begin failed: %s", elf_errmsg(-1)); retval = 1; goto fail; } if ((kind = elf_kind(elf)) != ELF_K_ELF) { if (kind == ELF_K_AR) warnx("file '%s' is an archive", argv[0]); else warnx("file '%s' is not an ELF file", argv[0]); retval = 1; goto fail; } if (gelf_getehdr(elf, &ehdr) == NULL) { warnx("gelf_getehdr: %s", elf_errmsg(-1)); retval = 1; goto fail; } /* * XXX need to support cross-endian operation, but for now * exit on error rather than misbehaving. */ if (ehdr.e_ident[EI_DATA] != SUPPORTED_ENDIAN) { warnx("file endianness must match host"); retval = 1; goto fail; } if (!editfeatures) { if (!print_file_features(elf, ehdr.e_phnum, fd, argv[0])) { retval = 1; goto fail; } } else if (!edit_file_features(elf, ehdr.e_phnum, fd, features)) { retval = 1; goto fail; } fail: if (elf != NULL) elf_end(elf); if (fd >= 0) close(fd); argc--; argv++; } return (retval); } #define USAGE_MESSAGE \ "\ Usage: %s [options] file...\n\ Set or display the control features for an ELF object.\n\n\ Supported options are:\n\ -l List known control features.\n\ -e [+-=]feature,list Edit features from a comma separated list.\n\ -h | --help Print a usage message and exit.\n" static void usage(void) { fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(1); } static bool convert_to_feature_val(char *feature_str, uint32_t *feature_val) { char *feature; int i, len; uint32_t input; char operation; input = 0; operation = *feature_str; feature_str++; len = nitems(featurelist); while ((feature = strsep(&feature_str, ",")) != NULL) { for (i = 0; i < len; ++i) { if (strcmp(featurelist[i].alias, feature) == 0) { input |= featurelist[i].value; break; } } if (i == len) { warnx("%s is not a valid feature", feature); return (false); } } if (operation == '+') { *feature_val |= input; } else if (operation == '=') { *feature_val = input; } else if (operation == '-') { *feature_val &= ~input; } else { warnx("'%c' not an operator - use '+', '-', '='", feature_str[0]); return (false); } return (true); } static bool edit_file_features(Elf *elf, int phcount, int fd, char *val) { uint32_t features; uint64_t off; if (!get_file_features(elf, phcount, fd, &features, &off)) { warnx("NT_FREEBSD_FEATURE_CTL note not found"); return (false); } if (!convert_to_feature_val(val, &features)) return (false); if (lseek(fd, off, SEEK_SET) == -1 || write(fd, &features, sizeof(features)) < (ssize_t)sizeof(features)) { warnx("error writing feature value"); return (false); } return (true); } static void print_features(void) { size_t i; printf("Known features are:\n"); for (i = 0; i < nitems(featurelist); ++i) printf("%-16s%s\n", featurelist[i].alias, featurelist[i].desc); } static bool print_file_features(Elf *elf, int phcount, int fd, char *filename) { uint32_t features; unsigned long i; if (!get_file_features(elf, phcount, fd, &features, NULL)) { return (false); } printf("File '%s' features:\n", filename); for (i = 0; i < nitems(featurelist); ++i) { printf("%-16s'%s' is ", featurelist[i].alias, featurelist[i].desc); if ((featurelist[i].value & features) == 0) printf("un"); printf("set.\n"); } return (true); } static bool get_file_features(Elf *elf, int phcount, int fd, uint32_t *features, uint64_t *off) { GElf_Phdr phdr; Elf_Note note; unsigned long read_total; int namesz, descsz, i; char *name; /* * Go through each program header to find one that is of type PT_NOTE * and has a note for feature control. */ for (i = 0; i < phcount; ++i) { if (gelf_getphdr(elf, i, &phdr) == NULL) { warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); return (false); } if (phdr.p_type != PT_NOTE) continue; if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { warn("lseek() failed:"); return (false); } read_total = 0; while (read_total < phdr.p_filesz) { if (read(fd, ¬e, sizeof(note)) < (ssize_t)sizeof(note)) { warnx("elf note header too short"); return (false); } read_total += sizeof(note); /* * XXX: Name and descriptor are 4 byte aligned, however, * the size given doesn't include the padding. */ namesz = roundup2(note.n_namesz, 4); name = malloc(namesz); if (name == NULL) { warn("malloc() failed."); return (false); } descsz = roundup2(note.n_descsz, 4); if (read(fd, name, namesz) < namesz) { warnx("elf note name too short"); free(name); return (false); } read_total += namesz; if (note.n_namesz != 8 || strncmp("FreeBSD", name, 7) != 0 || note.n_type != NT_FREEBSD_FEATURE_CTL) { /* Not the right note. Skip the description */ if (lseek(fd, descsz, SEEK_CUR) < 0) { warn("lseek() failed."); free(name); return (false); } read_total += descsz; free(name); continue; } if (note.n_descsz < sizeof(uint32_t)) { warnx("Feature descriptor can't " "be less than 4 bytes"); free(name); return (false); } /* * XXX: For now we look at only 4 bytes of the * descriptor. This should respect descsz. */ if (note.n_descsz > sizeof(uint32_t)) warnx("Feature note is bigger than expected"); if (read(fd, features, sizeof(uint32_t)) < (ssize_t)sizeof(uint32_t)) { warnx("feature note data too short"); free(name); return (false); } if (off != NULL) *off = phdr.p_offset + read_total; free(name); return (true); } } warnx("NT_FREEBSD_FEATURE_CTL note not found"); return (false); } Index: stable/12/usr.bin/readelf/Makefile =================================================================== --- stable/12/usr.bin/readelf/Makefile (revision 367461) +++ stable/12/usr.bin/readelf/Makefile (revision 367462) @@ -1,28 +1,28 @@ # $FreeBSD$ ELFTCDIR= ${SRCTOP}/contrib/elftoolchain READELFDIR= ${ELFTCDIR}/readelf .PATH: ${READELFDIR} PROG= readelf SRCS= readelf.c -LIBADD= dwarf elftc elf +LIBADD= dwarf elftc elf z CFLAGS+=-I${ELFTCDIR}/libelftc -I${ELFTCDIR}/common # This same hack is in lib/libelf/Makefile and lib/libdwarf/Makefile # We need to link against the correct version of these files. One # solution is to include SRCTOP/sys in the include path. This causes # problems when a header file in sys depends on a file in another # part of the tree, e.g. a machine dependent header. # SRCS+= sys/elf32.h sys/elf64.h sys/elf_common.h CLEANDIRS= sys CFLAGS+= -I. sys/elf32.h sys/elf64.h sys/elf_common.h: ${SRCTOP}/sys/${.TARGET} .NOMETA mkdir -p ${.OBJDIR}/sys ln -sf ${.ALLSRC} ${.TARGET} .include Index: stable/12 =================================================================== --- stable/12 (revision 367461) +++ stable/12 (revision 367462) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r345360-345362,345364,345431,346323,346327,348776,349510,350511,354544,357540-357541,358499,358631,358637,358639,358685,358706,358708,358713,359189,361662,364517,365489,366977,367209,367238,367322