diff options
Diffstat (limited to 'toys')
-rw-r--r-- | toys/pending/readelf.c | 203 |
1 files changed, 119 insertions, 84 deletions
diff --git a/toys/pending/readelf.c b/toys/pending/readelf.c index 5cd148c1..a8564a4d 100644 --- a/toys/pending/readelf.c +++ b/toys/pending/readelf.c @@ -35,7 +35,7 @@ GLOBALS( char *x, *p; char *elf, *shstrtab, *f; - unsigned long long shoff, phoff, size; + unsigned long long shoff, phoff, size, shstrtabsz; int bits, endian, shnum, shentsize, phentsize; ) @@ -75,13 +75,14 @@ static unsigned short elf_short(char **p) return elf_get(p, 2); } -static void get_sh(int i, struct sh *s) +static int get_sh(unsigned i, struct sh *s) { char *shdr = TT.elf+TT.shoff+i*TT.shentsize; - int name_offset; + unsigned name_offset; if (i >= TT.shnum || shdr > TT.elf+TT.size-TT.shentsize) { - error_exit("%s: no shdr %d",TT.f,i); + printf("No shdr %d\n", i); + return 0; } name_offset = elf_int(&shdr); @@ -95,14 +96,21 @@ static void get_sh(int i, struct sh *s) s->addralign = elf_long(&shdr); s->entsize = elf_long(&shdr); + if (s->offset>TT.size || s->size>TT.size || s->offset>TT.size-s->size) { + printf("Bad offset/size %llu/%llu for sh %d\n", s->offset, s->size, i); + return 0; + } + if (!TT.shstrtab) s->name = "?"; else { s->name = TT.shstrtab + name_offset; - if (s->name >= TT.elf+TT.size) error_exit("%s: shdr %d bad name", TT.f, i); - if (s->offset >= TT.size-s->size && s->type != 8 /*SHT_NOBITS*/) - error_exit("%s: shdr %d has bad offset/size %llu/%llu", TT.f, i, - s->offset, s->size); + if (name_offset > TT.shstrtabsz || s->name >= TT.elf+TT.size) { + printf("Bad name for sh %d\n", i); + return 0; + } } + + return 1; } static int find_section(char *spec, struct sh *s) @@ -113,26 +121,25 @@ static int find_section(char *spec, struct sh *s) // Valid section number? errno = 0; i = strtoul(spec, &end, 0); - if (!errno && !*end && i < TT.shnum) { - get_sh(i, s); - return 1; - } + if (!errno && !*end && i < TT.shnum) return get_sh(i, s); // Search the section names. for (i=0; i<TT.shnum; i++) { - get_sh(i, s); - if (!strcmp(s->name, spec)) return 1; + if (get_sh(i, s) && !strcmp(s->name, spec)) return 1; } error_msg("%s: no section '%s", TT.f, spec); return 0; } -static void get_ph(int i, struct ph *ph) +static int get_ph(int i, struct ph *ph) { char *phdr = TT.elf+TT.phoff+i*TT.phentsize; - if (phdr > TT.elf+TT.size-TT.phentsize) error_exit("%s: no phdr %d",TT.f,i); + if (phdr > TT.elf+TT.size-TT.phentsize) { + printf("Bad phdr %d\n", i); + return 0; + } // Elf64_Phdr reordered fields. ph->type = elf_int(&phdr); @@ -154,9 +161,12 @@ static void get_ph(int i, struct ph *ph) ph->align = elf_int(&phdr); } - if (ph->offset >= TT.size-ph->filesz) - error_exit("%s: phdr %d has bad offset/size %llu/%llu", TT.f, i, - ph->offset, ph->filesz); + if (ph->offset >= TT.size-ph->filesz) { + printf("phdr %d has bad offset/size %llu/%llu", i, ph->offset, ph->filesz); + return 0; + } + + return 1; } #define MAP(...) __VA_ARGS__ @@ -238,9 +248,9 @@ static void show_symbols(struct sh *table, struct sh *strtab) " Num: %*s Size Type Bind Vis Ndx Name\n", table->name, numsym, 5+8*TT.bits, "Value"); for (i=0; i<numsym; i++) { - int st_name = elf_int(&symtab), st_value, st_shndx; + unsigned st_name = elf_int(&symtab), st_value, st_shndx; unsigned char st_info, st_other; - long st_size; + unsigned long st_size; char *name; // The various fields were moved around for 64-bit. @@ -259,7 +269,7 @@ static void show_symbols(struct sh *table, struct sh *strtab) } name = TT.elf + strtab->offset + st_name; - if (name >= TT.elf+TT.size) error_exit("%s: bad symbol name", TT.f); + if (name >= TT.elf+TT.size) name = "???"; if (!st_shndx) ndx = "UND"; else if (st_shndx==0xfff1) ndx = "ABS"; @@ -267,7 +277,7 @@ static void show_symbols(struct sh *table, struct sh *strtab) // TODO: look up and show any symbol versions with @ or @@. - printf("%6d: %0*x %5ld %-7s %-6s %-9s%3s %s\n", i, 8*(TT.bits+1), + printf("%6d: %0*x %5lu %-7s %-6s %-9s%3s %s\n", i, 8*(TT.bits+1), st_value, st_size, stt_type(st_info & 0xf), stb_type(st_info >> 4), stv_type(st_other & 3), ndx, name); } @@ -280,15 +290,24 @@ static int notematch(int namesz, char **p, char *expected, int len) return 1; } -static void show_notes(long offset, long size) +static void show_notes(unsigned long offset, unsigned long size) { char *note = TT.elf + offset; + if (size > TT.size || offset > TT.size-size) { + printf("Bad note bounds %lu/%lu\n", offset, size); + return; + } + printf(" %-20s %10s\tDescription\n", "Owner", "Data size"); while (note < TT.elf+offset+size) { char *p = note, *desc; - int namesz = elf_int(&p), descsz = elf_int(&p), type = elf_int(&p), j = 0; + unsigned namesz=elf_int(&p), descsz=elf_int(&p), type=elf_int(&p), j=0; + if (namesz > size || descsz > size) { + error_msg("%s: bad note @%lu", TT.f, offset); + return; + } printf(" %-20.*s 0x%08x\t", namesz, p, descsz); if (notematch(namesz, &p, "GNU", 4)) { if (type == 1) { @@ -356,18 +375,6 @@ static void scan_elf() TT.shnum = elf_short(&hdr); shstrndx = elf_short(&hdr); - // Set up the section header string table so we can use section header names. - // Core files have shstrndx == 0. - TT.shstrtab = 0; - if (shstrndx != 0) { - get_sh(shstrndx, &shstr); - if (shstr.type != 3 /*SHT_STRTAB*/) { - error_msg("%s: bad shstrndx", TT.f); - return; - } - TT.shstrtab = TT.elf+shstr.offset; - } - if (toys.optc > 1) printf("\nFile: %s\n", TT.f); if (FLAG(h)) { @@ -384,9 +391,9 @@ static void scan_elf() printf(" Machine: %s\n", elf_arch_name(machine)); printf(" Version: 0x%x\n", version); printf(" Entry point address: 0x%x\n", entry); - printf(" Start of program headers: %lld (bytes into file)\n", + printf(" Start of program headers: %llu (bytes into file)\n", TT.phoff); - printf(" Start of section headers: %lld (bytes into file)\n", + printf(" Start of section headers: %llu (bytes into file)\n", TT.shoff); printf(" Flags: 0x%x\n", flags); printf(" Size of this header: %d (bytes)\n", ehsize); @@ -396,6 +403,27 @@ static void scan_elf() printf(" Number of section headers: %d\n", TT.shnum); printf(" Section header string table index: %d\n", shstrndx); } + if (TT.phoff > TT.size) { + error_msg("%s: bad phoff", TT.f); + return; + } + if (TT.shoff > TT.size) { + error_msg("%s: bad shoff", TT.f); + return; + } + + // Set up the section header string table so we can use section header names. + // Core files have shstrndx == 0. + TT.shstrtab = 0; + TT.shstrtabsz = 0; + if (shstrndx != 0) { + if (!get_sh(shstrndx, &shstr) || shstr.type != 3 /*SHT_STRTAB*/) { + error_msg("%s: bad shstrndx", TT.f); + return; + } + TT.shstrtab = TT.elf+shstr.offset; + TT.shstrtabsz = shstr.size; + } w = 8*(TT.bits+1); if (FLAG(S)) { @@ -414,7 +442,7 @@ static void scan_elf() // We need to iterate through the section headers even if we're not // dumping them, to find specific sections. for (i=0; i<TT.shnum; i++) { - get_sh(i, &s); + if (!get_sh(i, &s)) continue; if (s.type == 2 /*SHT_SYMTAB*/) symtab = s; else if (s.type == 6 /*SHT_DYNAMIC*/) dynamic = s; else if (s.type == 11 /*SHT_DYNSYM*/) dynsym = s; @@ -453,12 +481,13 @@ static void scan_elf() " %-14s %-8s %-*s %-*s %-7s %-7s Flg Align\n", "Type", "Offset", w, "VirtAddr", w, "PhysAddr", "FileSiz", "MemSiz"); for (i=0; i<phnum; i++) { - get_ph(i, &ph); + if (!get_ph(i, &ph)) continue; printf(" %-14s 0x%06llx 0x%0*llx 0x%0*llx 0x%05llx 0x%05llx %c%c%c %#llx\n", ph_type(ph.type), ph.offset, w, ph.vaddr, w, ph.paddr, ph.filesz, ph.memsz, ph.flags&4?'R':' ', ph.flags&2?'W':' ', ph.flags&1?'E':' ', ph.align); - if (ph.type == 3 /*PH_INTERP*/ && ph.filesz - 1 < TT.size - ph.offset) { + if (ph.type == 3 /*PH_INTERP*/ && ph.filesz<TT.size && + ph.offset<TT.size && ph.filesz - 1 < TT.size - ph.offset) { printf(" [Requesting program interpreter: %*s]\n", (int) ph.filesz-1, TT.elf+ph.offset); } @@ -468,10 +497,10 @@ static void scan_elf() " Section to Segment mapping:\n" " Segment Sections...\n"); for (i=0; i<phnum; i++) { - get_ph(i, &ph); + if (!get_ph(i, &ph)) continue; printf(" %02d ", i); for (j=0; j<TT.shnum; j++) { - get_sh(j, &s); + if (!get_sh(j, &s)) continue; if (!*s.name) continue; if (s.offset >= ph.offset && s.offset+s.size <= ph.offset+ph.filesz) printf("%s ", s.name); @@ -488,45 +517,51 @@ static void scan_elf() xputc('\n'); if (!dynamic.size) printf("There is no dynamic section in this file.\n"); - else printf("Dynamic section at offset 0x%llx contains %lld entries:\n" - " %-*s %-20s %s\n", - dynamic.offset, dynamic.size/dynamic.entsize, - w+2, "Tag", "Type", "Name/Value"); - while (dyn < end) { - unsigned long long tag = elf_long(&dyn), val = elf_long(&dyn); - char *type = dt_type(tag); - - printf(" 0x%0*llx %-20s ", w, tag, *type=='0' ? type : type+1); - if (*type == 'd') printf("%lld\n", val); - else if (*type == 'b') printf("%lld (bytes)\n", val); - else if (*type == 's') printf("%s\n", TT.elf+dynstr.offset+val); - else if (*type == 'f' || *type == 'F') { - struct bitname { int bit; char *s; } - df_names[] = {{0, "ORIGIN"},{1,"SYMBOLIC"},{2,"TEXTREL"}, - {3,"BIND_NOW"},{4,"STATIC_TLS"},{}}, - df_1_names[]={{0,"NOW"},{1,"GLOBAL"},{2,"GROUP"},{3,"NODELETE"}, - {5,"INITFIRST"},{27,"PIE"},{}}, - *names = *type == 'f' ? df_names : df_1_names; - int mask; - - if (*type == 'F') printf("Flags: "); - for (j=0; names[j].s; j++) { - if (val & (mask=(1<<names[j].bit))) { - printf("%s%s", names[j].s, (val &= ~mask) ? " " : ""); + else if (!dynamic.entsize) printf("Bad dynamic entry size 0!\n"); + else { + printf("Dynamic section at offset 0x%llx contains %lld entries:\n" + " %-*s %-20s %s\n", + dynamic.offset, dynamic.size/dynamic.entsize, + w+2, "Tag", "Type", "Name/Value"); + while (dyn < end) { + unsigned long long tag = elf_long(&dyn), val = elf_long(&dyn); + char *type = dt_type(tag); + + printf(" 0x%0*llx %-20s ", w, tag, *type=='0' ? type : type+1); + if (*type == 'd') printf("%lld\n", val); + else if (*type == 'b') printf("%lld (bytes)\n", val); + else if (*type == 's') printf("%s\n", TT.elf+dynstr.offset+val); + else if (*type == 'f' || *type == 'F') { + struct bitname { int bit; char *s; } + df_names[] = {{0, "ORIGIN"},{1,"SYMBOLIC"},{2,"TEXTREL"}, + {3,"BIND_NOW"},{4,"STATIC_TLS"},{}}, + df_1_names[]={{0,"NOW"},{1,"GLOBAL"},{2,"GROUP"},{3,"NODELETE"}, + {5,"INITFIRST"},{27,"PIE"},{}}, + *names = *type == 'f' ? df_names : df_1_names; + int mask; + + if (*type == 'F') printf("Flags: "); + for (j=0; names[j].s; j++) { + if (val & (mask=(1<<names[j].bit))) { + printf("%s%s", names[j].s, (val &= ~mask) ? " " : ""); + } } - } - if (val) printf("0x%llx", val); - xputc('\n'); - } else if (*type == 'N' || *type == 'R' || *type == 'S') { - printf("%s: [%s]\n", *type=='N' ? "Shared library" : - (*type=='R' ? "Library runpath" : "Library soname"), - TT.elf+dynstr.offset+val); - } else if (*type == 'P') { - type = dt_type(val); - j = strlen(type); - if (*type != '0') type += 2, j -= 3; - printf("%*.*s\n", j, j, type); - } else printf("0x%llx\n", val); + if (val) printf("0x%llx", val); + xputc('\n'); + } else if (*type == 'N' || *type == 'R' || *type == 'S') { + char *s = TT.elf+dynstr.offset+val; + + if (dynstr.offset>TT.size || val>TT.size || dynstr.offset>TT.size-val) + s = "???"; + printf("%s: [%s]\n", *type=='N' ? "Shared library" : + (*type=='R' ? "Library runpath" : "Library soname"), s); + } else if (*type == 'P') { + type = dt_type(val); + j = strlen(type); + if (*type != '0') type += 2, j -= 3; + printf("%*.*s\n", j, j, type); + } else printf("0x%llx\n", val); + } } } @@ -537,7 +572,7 @@ static void scan_elf() int found = 0; for (i=0; i<TT.shnum; i++) { - get_sh(i, &s); + if (!get_sh(i, &s)) continue; if (s.type == 7 /*SHT_NOTE*/) { printf("\nDisplaying notes found in: %s\n", s.name); show_notes(s.offset, s.size); @@ -545,7 +580,7 @@ static void scan_elf() } } for (i=0; !found && i<phnum; i++) { - get_ph(i, &ph); + if (!get_ph(i, &ph)) continue; if (ph.type == 4 /*PT_NOTE*/) { printf("\n" "Displaying notes found at file offset 0x%llx with length 0x%llx:\n", |