diff options
Diffstat (limited to 'src/readelf.c')
-rw-r--r-- | src/readelf.c | 727 |
1 files changed, 568 insertions, 159 deletions
diff --git a/src/readelf.c b/src/readelf.c index 6950204e..decfaf15 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -1,5 +1,6 @@ /* Print information from ELF file in human-readable form. Copyright (C) 1999-2018 Red Hat, Inc. + Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org> This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -301,13 +302,29 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr); static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr); static void print_scngrp (Ebl *ebl); static void print_dynamic (Ebl *ebl); -static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr); +static void print_relocs (Ebl *ebl, Dwfl_Module *mod, GElf_Ehdr *ehdr); static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr); static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr); +static void handle_relocs_relr (Ebl *ebl, Dwfl_Module *mod, Elf_Scn *scn, + GElf_Shdr *shdr); static bool print_symtab (Ebl *ebl, int type); -static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static bool handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static bool handle_dynamic_symtab (Ebl *ebl); +static void +process_symtab( + Ebl * ebl, + unsigned int nsyms, + Elf64_Word idx, + Elf32_Word verneed_stridx, + Elf32_Word verdef_stridx, + Elf_Data * symdata, + Elf_Data * versym_data, + Elf_Data * symstr_data, + Elf_Data * verneed_data, + Elf_Data * verdef_data, + Elf_Data * xndx_data); static void print_verinfo (Ebl *ebl); static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); @@ -322,12 +339,17 @@ static void dump_data (Ebl *ebl); static void dump_strings (Ebl *ebl); static void print_strings (Ebl *ebl); static void dump_archive_index (Elf *, const char *); +static void print_dwarf_addr (Dwfl_Module *dwflmod, int address_size, + Dwarf_Addr address, Dwarf_Addr raw); enum dyn_idx { + i_symtab_shndx, i_strsz, i_verneed, + i_verneednum, i_verdef, + i_verdefnum, i_versym, i_symtab, i_strtab, @@ -1035,14 +1057,14 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) if (print_dynamic_table) print_dynamic (ebl); if (print_relocations) - print_relocs (pure_ebl, ehdr); + print_relocs (pure_ebl, dwflmod, ehdr); if (print_histogram) handle_hash (ebl); if (print_symbol_table || print_dynsym_table) symtab_printed |= print_symtab (ebl, SHT_DYNSYM); if (print_version_info) print_verinfo (ebl); - if (print_symbol_table) + if (print_symbol_table && !use_dynamic_segment) symtab_printed |= print_symtab (ebl, SHT_SYMTAB); if ((print_symbol_table || print_dynsym_table) @@ -1606,7 +1628,7 @@ static const char * section_name (Ebl *ebl, GElf_Shdr *shdr) { size_t shstrndx; - if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0) + if (shdr == NULL || elf_getshdrstrndx (ebl->elf, &shstrndx) < 0) return "???"; return elf_strptr (ebl->elf, shstrndx, shdr->sh_name) ?: "???"; } @@ -1954,9 +1976,11 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, GElf_Phdr *phdr) case DT_RELASZ: case DT_STRSZ: case DT_RELSZ: + case DT_RELRSZ: case DT_RELAENT: case DT_SYMENT: case DT_RELENT: + case DT_RELRENT: case DT_PLTPADSZ: case DT_MOVEENT: case DT_MOVESZ: @@ -2032,7 +2056,7 @@ print_dynamic (Ebl *ebl) /* Print relocations. */ static void -print_relocs (Ebl *ebl, GElf_Ehdr *ehdr) +print_relocs (Ebl *ebl, Dwfl_Module *mod, GElf_Ehdr *ehdr) { /* Find all relocation sections and handle them. */ Elf_Scn *scn = NULL; @@ -2049,6 +2073,8 @@ print_relocs (Ebl *ebl, GElf_Ehdr *ehdr) handle_relocs_rel (ebl, ehdr, scn, shdr); else if (shdr->sh_type == SHT_RELA) handle_relocs_rela (ebl, ehdr, scn, shdr); + else if (shdr->sh_type == SHT_RELR) + handle_relocs_relr (ebl, mod, scn, shdr); } } } @@ -2437,12 +2463,124 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) } } +/* Handle a relocation section. */ +static void +handle_relocs_relr (Ebl *ebl, Dwfl_Module *mod, Elf_Scn *scn, GElf_Shdr *shdr) +{ + int class = gelf_getclass (ebl->elf); + size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELR, 1, EV_CURRENT); + int nentries = shdr->sh_size / sh_entsize; + + /* Get the data of the section. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the section header string table index. */ + size_t shstrndx; + if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)) + error_exit (0, _("cannot get section header string table index")); + + /* A .relr.dyn section does not refer to a specific section. */ + printf (ngettext ("\ +\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", + nentries), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_offset, + nentries); + + if (class == ELFCLASS32) + { + uint32_t base = 0; + for (int cnt = 0; cnt < nentries; ++cnt) + { + Elf32_Word *words = data->d_buf; + Elf32_Word entry = words[cnt]; + + /* Just the raw entries? */ + if (print_unresolved_addresses) + printf (" %#010" PRIx32 "%s\n", entry, + (entry & 1) == 0 ? " *" : ""); + else + { + /* A real address, also sets base. */ + if ((entry & 1) == 0) + { + printf (" "); + print_dwarf_addr (mod, 4, entry, entry); + printf (" *\n"); + + base = entry + 4; + } + else + { + /* Untangle address from base and bits. */ + uint32_t addr; + for (addr = base; (entry >>= 1) != 0; addr += 4) + if ((entry & 1) != 0) + { + printf (" "); + print_dwarf_addr (mod, 4, addr, addr); + printf ("\n"); + } + base += 4 * (4 * 8 - 1); + } + } + } + } + else + { + uint64_t base = 0; + for (int cnt = 0; cnt < nentries; ++cnt) + { + Elf64_Xword *xwords = data->d_buf; + Elf64_Xword entry = xwords[cnt]; + + /* Just the raw entries? */ + if (print_unresolved_addresses) + printf (" %#018" PRIx64 "%s\n", entry, + (entry & 1) == 0 ? " *" : ""); + else + { + /* A real address, also sets base. */ + if ((entry & 1) == 0) + { + printf (" "); + print_dwarf_addr (mod, 8, entry, entry); + printf (" *\n"); + + base = entry + 8; + } + else + { + /* Untangle address from base and bits. */ + uint64_t addr; + for (addr = base; (entry >>= 1) != 0; addr += 8) + if ((entry & 1) != 0) + { + printf (" "); + print_dwarf_addr (mod, 8, addr, addr); + printf ("\n"); + } + base += 8 * (8 * 8 - 1); + } + } + } + } +} /* Print the program header. Return true if a symtab is printed, false otherwise. */ static bool print_symtab (Ebl *ebl, int type) { + /* Use the dynamic section info to display symbol tables. */ + if (use_dynamic_segment && type == SHT_DYNSYM) + return handle_dynamic_symtab(ebl); + /* Find the symbol table(s). For this we have to search through the section table. */ Elf_Scn *scn = NULL; @@ -2481,8 +2619,7 @@ print_symtab (Ebl *ebl, int type) _("cannot get section [%zd] header: %s"), elf_ndxscn (scn), elf_errmsg (-1)); } - handle_symtab (ebl, scn, shdr); - symtab_printed = true; + symtab_printed = handle_symtab (ebl, scn, shdr); } } @@ -2491,6 +2628,179 @@ print_symtab (Ebl *ebl, int type) static void +process_symtab (Ebl *ebl, unsigned int nsyms, Elf64_Word idx, + Elf32_Word verneed_stridx, Elf32_Word verdef_stridx, + Elf_Data *symdata, Elf_Data *versym_data, + Elf_Data *symstr_data, Elf_Data *verneed_data, + Elf_Data *verdef_data, Elf_Data *xndx_data) +{ + for (unsigned int cnt = 0; cnt < nsyms; ++cnt) + { + char typebuf[64]; + char bindbuf[64]; + char scnbuf[64]; + Elf32_Word xndx; + GElf_Sym sym_mem; + GElf_Sym *sym + = gelf_getsymshndx (symdata, xndx_data, cnt, &sym_mem, &xndx); + + if (unlikely (sym == NULL)) + continue; + + /* Determine the real section index. */ + if (likely (sym->st_shndx != SHN_XINDEX)) + xndx = sym->st_shndx; + + printf (_ ("\ +%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), + cnt, gelf_getclass (ebl->elf) == ELFCLASS32 ? 8 : 16, + sym->st_value, sym->st_size, + ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), typebuf, + sizeof (typebuf)), + ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), + bindbuf, sizeof (bindbuf)), + get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)), + ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf, + sizeof (scnbuf), NULL, shnum), + use_dynamic_segment == true + ? (char *)symstr_data->d_buf + sym->st_name + : elf_strptr (ebl->elf, idx, sym->st_name)); + + if (versym_data != NULL) + { + /* Get the version information. */ + GElf_Versym versym_mem; + GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem); + + if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) + { + bool is_nobits = false; + bool check_def = xndx != SHN_UNDEF; + + if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX) + { + GElf_Shdr symshdr_mem; + GElf_Shdr *symshdr = gelf_getshdr ( + elf_getscn (ebl->elf, xndx), &symshdr_mem); + + is_nobits + = (symshdr != NULL && symshdr->sh_type == SHT_NOBITS); + } + + if (is_nobits || !check_def) + { + /* We must test both. */ + GElf_Vernaux vernaux_mem; + GElf_Vernaux *vernaux = NULL; + size_t vn_offset = 0; + + GElf_Verneed verneed_mem; + GElf_Verneed *verneed + = gelf_getverneed (verneed_data, 0, &verneed_mem); + while (verneed != NULL) + { + size_t vna_offset = vn_offset; + + vernaux = gelf_getvernaux (verneed_data, + vna_offset += verneed->vn_aux, + &vernaux_mem); + while (vernaux != NULL && vernaux->vna_other != *versym + && vernaux->vna_next != 0 + && (verneed_data->d_size - vna_offset + >= vernaux->vna_next)) + { + /* Update the offset. */ + vna_offset += vernaux->vna_next; + + vernaux = (vernaux->vna_next == 0 + ? NULL + : gelf_getvernaux (verneed_data, + vna_offset, + &vernaux_mem)); + } + + /* Check whether we found the version. */ + if (vernaux != NULL && vernaux->vna_other == *versym) + /* Found it. */ + break; + + if (verneed_data->d_size - vn_offset < verneed->vn_next) + break; + + vn_offset += verneed->vn_next; + verneed + = (verneed->vn_next == 0 + ? NULL + : gelf_getverneed (verneed_data, vn_offset, + &verneed_mem)); + } + + if (vernaux != NULL && vernaux->vna_other == *versym) + { + printf ("@%s (%u)", + use_dynamic_segment == true + ? (char *)symstr_data->d_buf + + vernaux->vna_name + : elf_strptr (ebl->elf, verneed_stridx, + vernaux->vna_name), + (unsigned int)vernaux->vna_other); + check_def = 0; + } + else if (unlikely (!is_nobits)) + error (0, 0, _ ("bad dynamic symbol")); + else + check_def = 1; + } + + if (check_def && *versym != 0x8001) + { + /* We must test both. */ + size_t vd_offset = 0; + + GElf_Verdef verdef_mem; + GElf_Verdef *verdef + = gelf_getverdef (verdef_data, 0, &verdef_mem); + while (verdef != NULL) + { + if (verdef->vd_ndx == (*versym & 0x7fff)) + /* Found the definition. */ + break; + + if (verdef_data->d_size - vd_offset < verdef->vd_next) + break; + + vd_offset += verdef->vd_next; + verdef = (verdef->vd_next == 0 + ? NULL + : gelf_getverdef (verdef_data, vd_offset, + &verdef_mem)); + } + + if (verdef != NULL) + { + GElf_Verdaux verdaux_mem; + GElf_Verdaux *verdaux = gelf_getverdaux ( + verdef_data, vd_offset + verdef->vd_aux, + &verdaux_mem); + + if (verdaux != NULL) + printf ((*versym & 0x8000) ? "@%s" : "@@%s", + use_dynamic_segment == true + ? (char *)symstr_data->d_buf + + verdaux->vda_name + : elf_strptr (ebl->elf, verdef_stridx, + verdaux->vda_name)); + } + } + } + } + + putchar_unlocked ('\n'); + } +} + + +static bool handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) { Elf_Data *versym_data = NULL; @@ -2504,7 +2814,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) /* Get the data of the section. */ Elf_Data *data = elf_getdata (scn, NULL); if (data == NULL) - return; + return false; /* Find out whether we have other sections we might need. */ Elf_Scn *runscn = NULL; @@ -2574,163 +2884,184 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) Num: Value Size Type Bind Vis Ndx Name\n"), stdout); - for (unsigned int cnt = 0; cnt < nsyms; ++cnt) - { - char typebuf[64]; - char bindbuf[64]; - char scnbuf[64]; - Elf32_Word xndx; - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx); - - if (unlikely (sym == NULL)) - continue; - - /* Determine the real section index. */ - if (likely (sym->st_shndx != SHN_XINDEX)) - xndx = sym->st_shndx; - - printf (_("\ -%5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), - cnt, - class == ELFCLASS32 ? 8 : 16, - sym->st_value, - sym->st_size, - ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), - typebuf, sizeof (typebuf)), - ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), - bindbuf, sizeof (bindbuf)), - get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)), - ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf, - sizeof (scnbuf), NULL, shnum), - elf_strptr (ebl->elf, shdr->sh_link, sym->st_name)); - - if (versym_data != NULL) - { - /* Get the version information. */ - GElf_Versym versym_mem; - GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem); - - if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) - { - bool is_nobits = false; - bool check_def = xndx != SHN_UNDEF; - - if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX) - { - GElf_Shdr symshdr_mem; - GElf_Shdr *symshdr = - gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem); + process_symtab(ebl, nsyms, shdr->sh_link, verneed_stridx, verdef_stridx, + data, versym_data, NULL, verneed_data, verdef_data, xndx_data); + return true; +} - is_nobits = (symshdr != NULL - && symshdr->sh_type == SHT_NOBITS); - } - if (is_nobits || ! check_def) - { - /* We must test both. */ - GElf_Vernaux vernaux_mem; - GElf_Vernaux *vernaux = NULL; - size_t vn_offset = 0; - - GElf_Verneed verneed_mem; - GElf_Verneed *verneed = gelf_getverneed (verneed_data, 0, - &verneed_mem); - while (verneed != NULL) - { - size_t vna_offset = vn_offset; - - vernaux = gelf_getvernaux (verneed_data, - vna_offset += verneed->vn_aux, - &vernaux_mem); - while (vernaux != NULL - && vernaux->vna_other != *versym - && vernaux->vna_next != 0 - && (verneed_data->d_size - vna_offset - >= vernaux->vna_next)) - { - /* Update the offset. */ - vna_offset += vernaux->vna_next; - - vernaux = (vernaux->vna_next == 0 - ? NULL - : gelf_getvernaux (verneed_data, - vna_offset, - &vernaux_mem)); - } - - /* Check whether we found the version. */ - if (vernaux != NULL && vernaux->vna_other == *versym) - /* Found it. */ - break; +static bool +handle_dynamic_symtab (Ebl *ebl) +{ + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = NULL; + /* phnum is a static variable which was already fetched in function + process_elf_file. */ + for (size_t i = 0; i < phnum; ++i) + { + phdr = gelf_getphdr (ebl->elf, i, &phdr_mem); + if (phdr->p_type == PT_DYNAMIC) + break; + } + if (phdr == NULL) + return false; - if (verneed_data->d_size - vn_offset < verneed->vn_next) - break; + GElf_Addr addrs[i_max] = { + 0, + }; + GElf_Off offs[i_max] = { + 0, + }; + get_dynscn_addrs (ebl->elf, phdr, addrs); + find_offsets (ebl->elf, 0, i_max, addrs, offs); - vn_offset += verneed->vn_next; - verneed = (verneed->vn_next == 0 - ? NULL - : gelf_getverneed (verneed_data, vn_offset, - &verneed_mem)); - } + size_t syments = 0; - if (vernaux != NULL && vernaux->vna_other == *versym) - { - printf ("@%s (%u)", - elf_strptr (ebl->elf, verneed_stridx, - vernaux->vna_name), - (unsigned int) vernaux->vna_other); - check_def = 0; - } - else if (unlikely (! is_nobits)) - error (0, 0, _("bad dynamic symbol")); - else - check_def = 1; - } + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem); - if (check_def && *versym != 0x8001) - { - /* We must test both. */ - size_t vd_offset = 0; + if (offs[i_hash] != 0) + { + /* In the original format, .hash says the size of .dynsym. */ - GElf_Verdef verdef_mem; - GElf_Verdef *verdef = gelf_getverdef (verdef_data, 0, - &verdef_mem); - while (verdef != NULL) - { - if (verdef->vd_ndx == (*versym & 0x7fff)) - /* Found the definition. */ - break; + size_t entsz = SH_ENTSIZE_HASH (ehdr); + Elf_Data *data + = elf_getdata_rawchunk (ebl->elf, offs[i_hash] + entsz, entsz, + (entsz == 4 ? ELF_T_WORD : ELF_T_XWORD)); + if (data != NULL) + syments = (entsz == 4 ? *(const GElf_Word *)data->d_buf + : *(const GElf_Xword *)data->d_buf); + } + if (offs[i_gnu_hash] != 0 && syments == 0) + { + /* In the new format, we can derive it with some work. */ - if (verdef_data->d_size - vd_offset < verdef->vd_next) - break; + const struct + { + Elf32_Word nbuckets; + Elf32_Word symndx; + Elf32_Word maskwords; + Elf32_Word shift2; + } * header; + + Elf_Data *data = elf_getdata_rawchunk (ebl->elf, offs[i_gnu_hash], + sizeof *header, ELF_T_WORD); + if (data != NULL) + { + header = data->d_buf; + Elf32_Word nbuckets = header->nbuckets; + Elf32_Word symndx = header->symndx; + GElf_Off buckets_at + = (offs[i_gnu_hash] + sizeof *header + + (gelf_getclass (ebl->elf) * sizeof (Elf32_Word) + * header->maskwords)); + + // elf_getdata_rawchunk takes a size_t, make sure it + // doesn't overflow. +#if SIZE_MAX <= UINT32_MAX + if (nbuckets > SIZE_MAX / sizeof (Elf32_Word)) + data = NULL; + else +#endif + data = elf_getdata_rawchunk (ebl->elf, buckets_at, + nbuckets * sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL && symndx < nbuckets) + { + const Elf32_Word *const buckets = data->d_buf; + Elf32_Word maxndx = symndx; + for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) + if (buckets[bucket] > maxndx) + maxndx = buckets[bucket]; + + GElf_Off hasharr_at + = (buckets_at + nbuckets * sizeof (Elf32_Word)); + hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); + do + { + data = elf_getdata_rawchunk ( + ebl->elf, hasharr_at, sizeof (Elf32_Word), ELF_T_WORD); + if (data != NULL && (*(const Elf32_Word *)data->d_buf & 1u)) + { + syments = maxndx + 1; + break; + } + ++maxndx; + hasharr_at += sizeof (Elf32_Word); + } + while (data != NULL); + } + } + } + if (offs[i_strtab] > offs[i_symtab] && syments == 0) + syments = ((offs[i_strtab] - offs[i_symtab]) + / gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)); - vd_offset += verdef->vd_next; - verdef = (verdef->vd_next == 0 - ? NULL - : gelf_getverdef (verdef_data, vd_offset, - &verdef_mem)); - } + if (syments <= 0 || offs[i_strtab] == 0 || offs[i_symtab] == 0) + { + error_exit (0, _ ("Dynamic symbol information is not available for " + "displaying symbols.")); + } - if (verdef != NULL) - { - GElf_Verdaux verdaux_mem; - GElf_Verdaux *verdaux - = gelf_getverdaux (verdef_data, - vd_offset + verdef->vd_aux, - &verdaux_mem); - - if (verdaux != NULL) - printf ((*versym & 0x8000) ? "@%s" : "@@%s", - elf_strptr (ebl->elf, verdef_stridx, - verdaux->vda_name)); - } - } - } - } + /* All the data chunk initializaion. */ + Elf_Data *symdata = NULL; + Elf_Data *symstrdata = NULL; + Elf_Data *versym_data = NULL; + Elf_Data *verdef_data = NULL; + Elf_Data *verneed_data = NULL; - putchar_unlocked ('\n'); - } + symdata = elf_getdata_rawchunk ( + ebl->elf, offs[i_symtab], + gelf_fsize (ebl->elf, ELF_T_SYM, syments, EV_CURRENT), ELF_T_SYM); + symstrdata = elf_getdata_rawchunk (ebl->elf, offs[i_strtab], addrs[i_strsz], + ELF_T_BYTE); + versym_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_versym], syments * sizeof (Elf64_Half), ELF_T_HALF); + + /* Get the verneed_data without vernaux. */ + verneed_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verneed], addrs[i_verneednum] * sizeof (Elf64_Verneed), + ELF_T_VNEED); + size_t vernauxnum = 0; + size_t vn_next_offset = 0; + + for (size_t i = 0; i < addrs[i_verneednum]; i++) + { + GElf_Verneed *verneed + = (GElf_Verneed *)(verneed_data->d_buf + vn_next_offset); + vernauxnum += verneed->vn_cnt; + vn_next_offset += verneed->vn_next; + } + + /* Update the verneed_data to include the vernaux. */ + verneed_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verneed], + (addrs[i_verneednum] + vernauxnum) * sizeof (GElf_Verneed), ELF_T_VNEED); + + /* Get the verdef_data without verdaux. */ + verdef_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verdef], addrs[i_verdefnum] * sizeof (Elf64_Verdef), + ELF_T_VDEF); + size_t verdauxnum = 0; + size_t vd_next_offset = 0; + + for (size_t i = 0; i < addrs[i_verdefnum]; i++) + { + GElf_Verdef *verdef + = (GElf_Verdef *)(verdef_data->d_buf + vd_next_offset); + verdauxnum += verdef->vd_cnt; + vd_next_offset += verdef->vd_next; + } + + /* Update the verdef_data to include the verdaux. */ + verdef_data = elf_getdata_rawchunk ( + ebl->elf, offs[i_verdef], + (addrs[i_verdefnum] + verdauxnum) * sizeof (GElf_Verdef), ELF_T_VDEF); + + unsigned int nsyms = (unsigned int)syments; + process_symtab (ebl, nsyms, 0, 0, 0, symdata, versym_data, symstrdata, + verneed_data, verdef_data, NULL); + return true; } @@ -3893,7 +4224,7 @@ get_debug_elf_data (Dwarf *dbg, Ebl *ebl, int idx, Elf_Scn *scn) return elf_getdata (scn, NULL); } -void +static void print_dwarf_addr (Dwfl_Module *dwflmod, int address_size, Dwarf_Addr address, Dwarf_Addr raw) { @@ -4990,13 +5321,25 @@ get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr addrs[i_max]) addrs[i_verdef] = dyn->d_un.d_ptr; break; + case DT_VERDEFNUM: + addrs[i_verdefnum] = dyn->d_un.d_val; + break; + case DT_VERNEED: addrs[i_verneed] = dyn->d_un.d_ptr; break; + case DT_VERNEEDNUM: + addrs[i_verneednum] = dyn->d_un.d_val; + break; + case DT_STRSZ: addrs[i_strsz] = dyn->d_un.d_val; break; + + case DT_SYMTAB_SHNDX: + addrs[i_symtab_shndx] = dyn->d_un.d_ptr; + break; } } } @@ -11196,8 +11539,9 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, // hash used for generating the table. Version 6 contains symbols // for inlined functions, older versions didn't. Version 7 adds // symbol kinds. Version 8 just indicates that it correctly includes - // TUs for symbols. - if (vers < 4 || vers > 8) + // TUs for symbols. Version 9 adds shortcut table for information + // regarding the main function. + if (vers < 4 || vers > 9) { printf (_(" unknown version, cannot parse section\n")); return; @@ -11235,6 +11579,17 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, if (unlikely (readp + 4 > dataend)) goto invalid_data; + uint32_t shortcut_off = 0; + if (vers >= 9) + { + shortcut_off = read_4ubyte_unaligned (dbg, readp); + printf (_(" shortcut offset: %#" PRIx32 "\n"), shortcut_off); + + readp += 4; + if (unlikely (readp + 4 > dataend)) + goto invalid_data; + } + uint32_t const_off = read_4ubyte_unaligned (dbg, readp); printf (_(" constant offset: %#" PRIx32 "\n"), const_off); @@ -11332,8 +11687,19 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, if (const_off >= data->d_size) goto invalid_data; + const unsigned char *shortcut_start = NULL; + if (vers >= 9) + { + if (shortcut_off >= data->d_size) + goto invalid_data; + + shortcut_start = data->d_buf + shortcut_off; + nextp = shortcut_start; + } + else + nextp = const_start; + readp = data->d_buf + sym_off; - nextp = const_start; size_t sym_nr = (nextp - readp) / 8; printf (_("\n Symbol table at offset %#" PRIx32 @@ -11407,6 +11773,49 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, } n++; } + + if (vers < 9) + return; + + if (unlikely (shortcut_start == NULL)) + goto invalid_data; + + readp = shortcut_start; + nextp = const_start; + size_t shortcut_nr = (nextp - readp) / 4; + + if (unlikely (shortcut_nr != 2)) + goto invalid_data; + + printf (_("\nShortcut table at offset %#" PRIx32 " contains %zu slots:\n"), + shortcut_off, shortcut_nr); + + uint32_t lang = read_4ubyte_unaligned (dbg, readp); + readp += 4; + + /* Include the hex number of LANG in the output if the language + is unknown. */ + const char *lang_str = dwarf_lang_string (lang); + lang_str = string_or_unknown (lang_str, lang, DW_LANG_lo_user, + DW_LANG_hi_user, true); + + printf (_("Language of main: %s\n"), lang_str); + printf (_("Name of main: ")); + + if (lang != 0) + { + uint32_t name = read_4ubyte_unaligned (dbg, readp); + readp += 4; + const unsigned char *sym = const_start + name; + + if (unlikely ((size_t) (dataend - const_start) < name + || memchr (sym, '\0', dataend - sym) == NULL)) + goto invalid_data; + + printf ("%s\n", sym); + } + else + printf ("<unknown>\n"); } /* Returns true and sets split DWARF CU id if there is a split compile |