>From bdc19de94bff8f8812611b9ba8c0116a650d0fb5 Mon Sep 17 00:00:00 2001
From: Di Chen
Date: Fri, 13 Jan 2023 20:12:43 +0800
Subject: [PATCH] readelf: display dynamic symtab without section headers
This commit adds a new option "-D/--use-dynamic" to support printing the
dynamic symbol table from the PT_DYNAMIC segment. By using the
PT_DYNAMIC segment, eu-readelf can go through the contents of dynamic
section entries and the values of each tag. From that, we can get the
address and size of the dynamic symbol table, the address of the string
table, etc.
By using the new option "-D/--use-dynamic", eu-readelf can list the
symbols without section headers.
Example:
$ ./src/readelf -Ds a.out
0: 0 NOTYPE LOCAL DEFAULTUNDEF
1: 0 FUNCGLOBAL DEFAULTUNDEF
__libc_start_main@GLIBC_2.34 (2)
2: 0 NOTYPE WEAK DEFAULTUNDEF
__gmon_start__
https://sourceware.org/bugzilla/show_bug.cgi?id=28873
Signed-off-by: Di Chen
---
src/readelf.c | 289 --
1 file changed, 283 insertions(+), 6 deletions(-)
diff --git a/src/readelf.c b/src/readelf.c
index 451f8400..9e1e9b73 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -307,7 +307,8 @@ static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr
*ehdr, Elf_Scn *scn,
static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, 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 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);
@@ -327,7 +328,9 @@ enum dyn_idx
{
i_strsz,
i_verneed,
+ i_verneednum,
i_verdef,
+ i_verdefnum,
i_versym,
i_symtab,
i_strtab,
@@ -1042,7 +1045,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
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)
@@ -2442,6 +2445,12 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr)
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;
@@ -2480,16 +2489,275 @@ 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);
}
}
return symtab_printed;
}
+static bool
+handle_dynamic_symtab (Ebl *ebl)
+{
+ GElf_Phdr *phdr = NULL;
+ /* phnum is a static variable which already fetched in function
process_elf_file. */
+ for (size_t i = 0; i < phnum; ++i) {
+GElf_Phdr phdr_mem;
+phdr = gelf_getphdr(ebl->elf, i, &phdr_mem);
+if (phdr->p_type == PT_DYNAMIC) {
+ break;
+}
+ }
+ if (phdr == NULL)
+ return false;
-static void
+ 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);
+
+ size_t syments;
+
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr(ebl->elf, &ehdr_mem);
+
+ if (offs[i_hash] != 0) {
+/* In the original format, .hash says the size of .dynsym. */
+
+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. */
+
+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));
+
+ //