toybox/toys/pending/readelf.c
<<
>>
Prefs
   1/* readelf.c - display information about ELF files.
   2 *
   3 * Copyright 2019 The Android Open Source Project
   4 *
   5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/nm.html
   6
   7USE_READELF(NEWTOY(readelf, "<1(dyn-syms)adehlnp:SsWx:", TOYFLAG_USR|TOYFLAG_BIN))
   8
   9config READELF
  10  bool "readelf"
  11  default n
  12  help
  13    usage: readelf [-adehlnSs] [-p SECTION] [-x SECTION] [file...]
  14
  15    Displays information about ELF files.
  16
  17    -a  Equivalent to -dhlnSs
  18    -d  Show dynamic section
  19    -e  Headers (equivalent to -hlS)
  20    -h  Show ELF header
  21    -l  Show program headers
  22    -n  Show notes
  23    -p S        Dump strings found in named/numbered section
  24    -S  Show section headers
  25    -s  Show symbol tables (.dynsym and .symtab)
  26    -x S        Hex dump of named/numbered section
  27
  28    --dyn-syms  Show just .dynsym symbol table
  29*/
  30
  31#define FOR_readelf
  32#include "toys.h"
  33
  34GLOBALS(
  35  char *x, *p;
  36
  37  char *elf, *shstrtab, *f;
  38  unsigned long long shoff, phoff, size;
  39  int bits, endian, shnum, shentsize, phentsize;
  40)
  41
  42// Section header.
  43struct sh {
  44  unsigned type, link, info;
  45  unsigned long long flags, addr, offset, size, addralign, entsize;
  46  char *name;
  47};
  48
  49// Program header.
  50struct ph {
  51  unsigned type, flags;
  52  unsigned long long offset, vaddr, paddr, filesz, memsz, align;
  53};
  54
  55static long long elf_get(char **p, int len)
  56{
  57  long long result = ((TT.endian == 2) ? peek_be : peek_le)(*p, len);
  58
  59  *p += len;
  60  return result;
  61}
  62
  63static unsigned long long elf_long(char **p)
  64{
  65  return elf_get(p, 4*(TT.bits+1));
  66}
  67
  68static unsigned elf_int(char **p)
  69{
  70  return elf_get(p, 4);
  71}
  72
  73static unsigned short elf_short(char **p)
  74{
  75  return elf_get(p, 2);
  76}
  77
  78static void get_sh(int i, struct sh *s)
  79{
  80  char *shdr = TT.elf+TT.shoff+i*TT.shentsize;
  81  int name_offset;
  82
  83  if (i >= TT.shnum || shdr > TT.elf+TT.size-TT.shentsize) {
  84    error_exit("%s: no shdr %d",TT.f,i);
  85  }
  86
  87  name_offset = elf_int(&shdr);
  88  s->type = elf_int(&shdr);
  89  s->flags = elf_long(&shdr);
  90  s->addr = elf_long(&shdr);
  91  s->offset = elf_long(&shdr);
  92  s->size = elf_long(&shdr);
  93  s->link = elf_int(&shdr);
  94  s->info = elf_int(&shdr);
  95  s->addralign = elf_long(&shdr);
  96  s->entsize = elf_long(&shdr);
  97
  98  if (!TT.shstrtab) s->name = "?";
  99  else {
 100    s->name = TT.shstrtab + name_offset;
 101    if (s->name >= TT.elf+TT.size) error_exit("%s: shdr %d bad name", TT.f, i);
 102    if (s->offset >= TT.size-s->size && s->type != 8 /*SHT_NOBITS*/)
 103      error_exit("%s: shdr %d has bad offset/size %llu/%llu", TT.f, i,
 104        s->offset, s->size);
 105  }
 106}
 107
 108static int find_section(char *spec, struct sh *s)
 109{
 110  char *end;
 111  int i;
 112
 113  // Valid section number?
 114  errno = 0;
 115  i = strtoul(spec, &end, 0);
 116  if (!errno && !*end && i < TT.shnum) {
 117    get_sh(i, s);
 118    return 1;
 119  }
 120
 121  // Search the section names.
 122  for (i=0; i<TT.shnum; i++) {
 123    get_sh(i, s);
 124    if (!strcmp(s->name, spec)) return 1;
 125  }
 126
 127  error_msg("%s: no section '%s", TT.f, spec);
 128  return 0;
 129}
 130
 131static void get_ph(int i, struct ph *ph)
 132{
 133  char *phdr = TT.elf+TT.phoff+i*TT.phentsize;
 134
 135  if (phdr > TT.elf+TT.size-TT.phentsize) error_exit("%s: no phdr %d",TT.f,i);
 136
 137  // Elf64_Phdr reordered fields.
 138  ph->type = elf_int(&phdr);
 139  if (TT.bits) {
 140    ph->flags = elf_int(&phdr);
 141    ph->offset = elf_long(&phdr);
 142    ph->vaddr = elf_long(&phdr);
 143    ph->paddr = elf_long(&phdr);
 144    ph->filesz = elf_long(&phdr);
 145    ph->memsz = elf_long(&phdr);
 146    ph->align = elf_long(&phdr);
 147  } else {
 148    ph->offset = elf_int(&phdr);
 149    ph->vaddr = elf_int(&phdr);
 150    ph->paddr = elf_int(&phdr);
 151    ph->filesz = elf_int(&phdr);
 152    ph->memsz = elf_int(&phdr);
 153    ph->flags = elf_int(&phdr);
 154    ph->align = elf_int(&phdr);
 155  }
 156
 157  if (ph->offset >= TT.size-ph->filesz)
 158    error_exit("%s: phdr %d has bad offset/size %llu/%llu", TT.f, i,
 159      ph->offset, ph->filesz);
 160}
 161
 162#define MAP(...) __VA_ARGS__
 163#define DECODER(name, values) \
 164  static char *name(int type) { \
 165    static char unknown[20]; \
 166    struct {int v; char *s;} a[] = values; \
 167    int i; \
 168    \
 169    for (i=0; i<ARRAY_LEN(a); i++) if (type==a[i].v) return a[i].s; \
 170    sprintf(unknown, "0x%x", type); \
 171    return unknown; \
 172  }
 173
 174DECODER(dt_type, MAP({{0,"x(NULL)"},{1,"N(NEEDED)"},{2,"b(PLTRELSZ)"},
 175  {3,"x(PLTGOT)"},{4,"x(HASH)"},{5,"x(STRTAB)"},{6,"x(SYMTAB)"},{7,"x(RELA)"},
 176  {8,"b(RELASZ)"},{9,"b(RELAENT)"},{10,"b(STRSZ)"},{11,"b(SYMENT)"},
 177  {12,"x(INIT)"},{13,"x(FINI)"},{14,"S(SONAME)"},{15,"R(RPATH)"},
 178  {16,"x(SYMBOLIC)"},{17,"x(REL)"},{18,"b(RELSZ)"},{19,"b(RELENT)"},
 179  {20,"P(PLTREL)"},{21,"x(DEBUG)"},{22,"x(TEXTREL)"},{23,"x(JMPREL)"},
 180  {24,"d(BIND_NOW)"},{25,"x(INIT_ARRAY)"},{26,"x(FINI_ARRAY)"},
 181  {27,"b(INIT_ARRAYSZ)"},{28,"b(FINI_ARRAYSZ)"},{29,"R(RUNPATH)"},
 182  {30,"f(FLAGS)"},{32,"x(PREINIT_ARRAY)"},{33,"x(PREINIT_ARRAYSZ)"},
 183  {35,"b(RELRSZ)"},{36,"x(RELR)"},{37,"b(RELRENT)"},
 184  {0x6000000f,"x(ANDROID_REL)"},{0x60000010,"b(ANDROID_RELSZ)"},
 185  {0x60000011,"x(ANDROID_RELA)"},{0x60000012,"b(ANDROID_RELASZ)"},
 186  {0x6fffe000,"x(ANDROID_RELR)"},{0x6fffe001,"b(ANDROID_RELRSZ)"},
 187  {0x6fffe003,"x(ANDROID_RELRENT)"},{0x6ffffef5,"x(GNU_HASH)"},
 188  {0x6ffffef6,"x(TLSDESC_PLT)"},{0x6ffffef7,"x(TLSDESC_GOT)"},
 189  {0x6ffffff0,"x(VERSYM)"},{0x6ffffff9,"d(RELACOUNT)"},
 190  {0x6ffffffa,"d(RELCOUNT)"},{0x6ffffffb,"F(FLAGS_1)"},
 191  {0x6ffffffc," (VERDEF)"},{0x6ffffffd,"d(VERDEFNUM)"},
 192  {0x6ffffffe,"x(VERNEED)"},{0x6fffffff,"d(VERNEEDNUM)"}}))
 193
 194DECODER(et_type, MAP({{0,"NONE (None)"},{1,"REL (Relocatable file)"},
 195  {2,"EXEC (Executable file)"},{3,"DYN (Shared object file)"},
 196  {4,"CORE (Core file)"}}))
 197
 198DECODER(nt_type_core, MAP({{1,"NT_PRSTATUS"},{2,"NT_FPREGSET"},
 199  {3,"NT_PRPSINFO"},{5,"NT_PLATFORM"},{6,"NT_AUXV"},
 200  {0x46494c45,"NT_FILE"},{0x53494749,"NT_SIGINFO"}}))
 201
 202DECODER(nt_type_linux, MAP({{0x200,"NT_386_TLS"},{0x202, "NT_X86_XSTATE"},
 203  {0x400,"NT_ARM_VFP"},{0x401,"NT_ARM_TLS"},{0x405,"NT_ARM_SVE"}}))
 204
 205DECODER(os_abi, MAP({{0,"UNIX - System V"}}))
 206
 207DECODER(ph_type, MAP({{0,"NULL"},{1,"LOAD"},{2,"DYNAMIC"},{3,"INTERP"},
 208  {4,"NOTE"},{5,"SHLIB"},{6,"PHDR"},{7,"TLS"},{0x6474e550,"GNU_EH_FRAME"},
 209  {0x6474e551,"GNU_STACK"},{0x6474e552,"GNU_RELRO"},{0x70000001,"EXIDX"}}))
 210
 211DECODER(sh_type, MAP({{0,"NULL"},{1,"PROGBITS"},{2,"SYMTAB"},{3,"STRTAB"},
 212  {4,"RELA"},{5,"HASH"},{6,"DYNAMIC"},{7,"NOTE"},{8,"NOBITS"},{9,"REL"},
 213  {10,"SHLIB"},{11,"DYNSYM"},{14,"INIT_ARRAY"},{15,"FINI_ARRAY"},
 214  {16,"PREINIT_ARRAY"},{17,"GROUP"},{18,"SYMTAB_SHNDX"},{19,"RELR"},
 215  {0x60000001,"ANDROID_REL"},{0x60000002,"ANDROID_RELA"},
 216  {0x6fffff00,"ANDROID_RELR"},{0x6ffffff6,"GNU_HASH"},
 217  {0x6ffffffd,"VERDEF"},{0x6ffffffe,"VERNEED"},
 218  {0x6fffffff,"VERSYM"},{0x70000001,"ARM_EXIDX"},
 219  {0x70000003,"ARM_ATTRIBUTES"}}))
 220
 221DECODER(stb_type, MAP({{0,"LOCAL"},{1,"GLOBAL"},{2,"WEAK"}}))
 222
 223DECODER(stt_type, MAP({{0,"NOTYPE"},{1,"OBJECT"},{2,"FUNC"},{3,"SECTION"},
 224  {4,"FILE"},{5,"COMMON"},{6,"TLS"},{10,"GNU_IFUNC"}}))
 225
 226DECODER(stv_type, MAP({{0,"DEFAULT"},{1,"INTERNAL"},{2,"HIDDEN"},
 227  {3,"PROTECTED"}}))
 228
 229static void show_symbols(struct sh *table, struct sh *strtab)
 230{
 231  char *symtab = TT.elf+table->offset, *ndx;
 232  int numsym = table->size/(TT.bits ? 24 : 16), i;
 233
 234  if (numsym == 0) return;
 235
 236  xputc('\n');
 237  printf("Symbol table '%s' contains %d entries:\n"
 238         "   Num:    %*s  Size Type    Bind   Vis      Ndx Name\n",
 239         table->name, numsym, 5+8*TT.bits, "Value");
 240  for (i=0; i<numsym; i++) {
 241    int st_name = elf_int(&symtab), st_value, st_shndx;
 242    unsigned char st_info, st_other;
 243    long st_size;
 244    char *name;
 245
 246    // The various fields were moved around for 64-bit.
 247    if (TT.bits) {
 248      st_info = *symtab++;
 249      st_other = *symtab++;
 250      st_shndx = elf_short(&symtab);
 251      st_value = elf_long(&symtab);
 252      st_size = elf_long(&symtab);
 253    } else {
 254      st_value = elf_int(&symtab);
 255      st_size = elf_int(&symtab);
 256      st_info = *symtab++;
 257      st_other = *symtab++;
 258      st_shndx = elf_short(&symtab);
 259    }
 260
 261    name = TT.elf + strtab->offset + st_name;
 262    if (name >= TT.elf+TT.size) error_exit("%s: bad symbol name", TT.f);
 263
 264    if (!st_shndx) ndx = "UND";
 265    else if (st_shndx==0xfff1) ndx = "ABS";
 266    else sprintf(ndx = toybuf, "%d", st_shndx);
 267
 268    // TODO: look up and show any symbol versions with @ or @@.
 269
 270    printf("%6d: %0*x %5ld %-7s %-6s %-9s%3s %s\n", i, 8*(TT.bits+1),
 271      st_value, st_size, stt_type(st_info & 0xf), stb_type(st_info >> 4),
 272      stv_type(st_other & 3), ndx, name);
 273  }
 274}
 275
 276static int notematch(int namesz, char **p, char *expected, int len)
 277{
 278  if (namesz != len || memcmp(*p, expected, namesz)) return 0;
 279  *p += namesz;
 280  return 1;
 281}
 282
 283static void show_notes(long offset, long size)
 284{
 285  char *note = TT.elf + offset;
 286
 287  printf("  %-20s %10s\tDescription\n", "Owner", "Data size");
 288  while (note < TT.elf+offset+size) {
 289    char *p = note, *desc;
 290    int namesz = elf_int(&p), descsz = elf_int(&p), type = elf_int(&p), j = 0;
 291
 292    printf("  %-20.*s 0x%08x\t", namesz, p, descsz);
 293    if (notematch(namesz, &p, "GNU", 4)) {
 294      if (type == 1) {
 295        printf("NT_GNU_ABI_TAG\tOS: %s, ABI: %u.%u.%u",
 296          !elf_int(&p)?"Linux":"?", elf_int(&p), elf_int(&p), elf_int(&p)), j=1;
 297      } else if (type == 3) {
 298        printf("NT_GNU_BUILD_ID\t");
 299        for (;j<descsz;j++) printf("%02x", *p++);
 300      } else if (type == 4) {
 301        printf("NT_GNU_GOLD_VERSION\t%.*s", descsz, p), j=1;
 302      } else p -= 4;
 303    } else if (notematch(namesz, &p, "Android", 8)) {
 304      if (type == 1) {
 305        printf("NT_VERSION\tAPI level %u", elf_int(&p)), j=1;
 306        if (descsz>=132) printf(", NDK %.64s (%.64s)", p, p+64);
 307      } else p -= 8;
 308    } else if (notematch(namesz, &p, "CORE", 5)) {
 309      if (*(desc = nt_type_core(type)) != '0') printf("%s", desc), j=1;
 310    } else if (notematch(namesz, &p, "LINUX", 6)) {
 311      if (*(desc = nt_type_linux(type)) != '0') printf("%s", desc), j=1;
 312    }
 313
 314    // If we didn't do custom output above, show a hex dump.
 315    if (!j) {
 316      printf("0x%x\t", type);
 317      for (;j<descsz;j++) printf("%c%02x",!j?'\t':' ', *p++/*note[16+j]*/);
 318    }
 319    xputc('\n');
 320    note += 3*4 + ((namesz+3)&~3) + ((descsz+3)&~3);
 321  }
 322}
 323
 324static void scan_elf()
 325{
 326  struct sh dynamic = {}, dynstr = {}, dynsym = {}, shstr = {}, strtab = {},
 327    symtab = {}, s;
 328  struct ph ph;
 329  char *hdr = TT.elf;
 330  int type, machine, version, flags, entry, ehsize, phnum, shstrndx, i, j, w;
 331
 332  if (TT.size < 45 || memcmp(hdr, "\177ELF", 4)) {
 333    error_msg("%s: not ELF", TT.f);
 334    return;
 335  }
 336
 337  TT.bits = hdr[4] - 1;
 338  TT.endian = hdr[5];
 339  if (TT.bits<0 || TT.bits>1 || TT.endian<1 || TT.endian>2 || hdr[6]!=1) {
 340    error_msg("%s: bad ELF", TT.f);
 341    return;
 342  }
 343
 344  hdr += 16; // EI_NIDENT
 345  type = elf_short(&hdr);
 346  machine = elf_short(&hdr);
 347  version = elf_int(&hdr);
 348  entry = elf_long(&hdr);
 349  TT.phoff = elf_long(&hdr);
 350  TT.shoff = elf_long(&hdr);
 351  flags = elf_int(&hdr);
 352  ehsize = elf_short(&hdr);
 353  TT.phentsize = elf_short(&hdr);
 354  phnum = elf_short(&hdr);
 355  TT.shentsize = elf_short(&hdr);
 356  TT.shnum = elf_short(&hdr);
 357  shstrndx = elf_short(&hdr);
 358
 359  // Set up the section header string table so we can use section header names.
 360  // Core files have shstrndx == 0.
 361  TT.shstrtab = 0;
 362  if (shstrndx != 0) {
 363    get_sh(shstrndx, &shstr);
 364    if (shstr.type != 3 /*SHT_STRTAB*/) {
 365      error_msg("%s: bad shstrndx", TT.f);
 366      return;
 367    }
 368    TT.shstrtab = TT.elf+shstr.offset;
 369  }
 370
 371  if (toys.optc > 1) printf("\nFile: %s\n", TT.f);
 372
 373  if (FLAG(h)) {
 374    printf("ELF Header:\n");
 375    printf("  Magic:   ");
 376    for (i=0; i<16; i++) printf("%02x%c", TT.elf[i], i==15?'\n':' ');
 377    printf("  Class:                             ELF%d\n", TT.bits?64:32);
 378    printf("  Data:                              2's complement, %s endian\n",
 379           (TT.endian==2)?"big":"little");
 380    printf("  Version:                           1 (current)\n");
 381    printf("  OS/ABI:                            %s\n", os_abi(TT.elf[7]));
 382    printf("  ABI Version:                       %d\n", TT.elf[8]);
 383    printf("  Type:                              %s\n", et_type(type));
 384    printf("  Machine:                           %s\n", elf_arch_name(machine));
 385    printf("  Version:                           0x%x\n", version);
 386    printf("  Entry point address:               0x%x\n", entry);
 387    printf("  Start of program headers:          %lld (bytes into file)\n",
 388           TT.phoff);
 389    printf("  Start of section headers:          %lld (bytes into file)\n",
 390           TT.shoff);
 391    printf("  Flags:                             0x%x\n", flags);
 392    printf("  Size of this header:               %d (bytes)\n", ehsize);
 393    printf("  Size of program headers:           %d (bytes)\n", TT.phentsize);
 394    printf("  Number of program headers:         %d\n", phnum);
 395    printf("  Size of section headers:           %d (bytes)\n", TT.shentsize);
 396    printf("  Number of section headers:         %d\n", TT.shnum);
 397    printf("  Section header string table index: %d\n", shstrndx);
 398  }
 399
 400  w = 8*(TT.bits+1);
 401  if (FLAG(S)) {
 402    if (!TT.shnum) printf("\nThere are no sections in this file.\n");
 403    else {
 404      if (!FLAG(h)) {
 405        printf("There are %d section headers, starting at offset %#llx:\n",
 406               TT.shnum, TT.shoff);
 407      }
 408      printf("\n"
 409             "Section Headers:\n"
 410             "  [Nr] %-20s %-14s %-*s %-6s %-6s ES Flg Lk Inf Al\n",
 411             "Name", "Type", w, "Address", "Off", "Size");
 412    }
 413  }
 414  // We need to iterate through the section headers even if we're not
 415  // dumping them, to find specific sections.
 416  for (i=0; i<TT.shnum; i++) {
 417    get_sh(i, &s);
 418    if (s.type == 2 /*SHT_SYMTAB*/) symtab = s;
 419    else if (s.type == 6 /*SHT_DYNAMIC*/) dynamic = s;
 420    else if (s.type == 11 /*SHT_DYNSYM*/) dynsym = s;
 421    else if (s.type == 3 /*SHT_STRTAB*/) {
 422      if (!strcmp(s.name, ".strtab")) strtab = s;
 423      else if (!strcmp(s.name, ".dynstr")) dynstr = s;
 424    }
 425
 426    if (FLAG(S)) {
 427      char sh_flags[12] = {}, *p = sh_flags;
 428
 429      for (j=0; j<12; j++) if (s.flags&(1<<j)) *p++="WAXxMSILOTC"[j];
 430      printf("  [%2d] %-20s %-14s %0*llx %06llx %06llx %02llx %3s %2d %2d %2lld\n",
 431             i, s.name, sh_type(s.type), w, s.addr, s.offset, s.size,
 432             s.entsize, sh_flags, s.link, s.info, s.addralign);
 433    }
 434  }
 435  if (FLAG(S) && TT.shnum) {
 436    printf("Key:\n"
 437           "  (W)rite, (A)lloc, e(X)ecute, (M)erge, (S)trings, (I)nfo\n"
 438           "  (L)ink order, (O)S, (G)roup, (T)LS, (C)ompressed, x=unknown\n");
 439  }
 440
 441  if (FLAG(l)) {
 442    xputc('\n');
 443    if (!phnum) printf("There are no program headers in this file.\n");
 444    else {
 445      if (!FLAG(h)) {
 446        printf("Elf file type is %s\n"
 447        "Entry point %#x\n"
 448        "There are %d program headers, starting at offset %lld\n"
 449        "\n",
 450        et_type(type), entry, phnum, TT.phoff);
 451      }
 452      printf("Program Headers:\n"
 453             "  %-14s %-8s %-*s   %-*s   %-7s %-7s Flg Align\n", "Type",
 454             "Offset", w, "VirtAddr", w, "PhysAddr", "FileSiz", "MemSiz");
 455      for (i=0; i<phnum; i++) {
 456        get_ph(i, &ph);
 457        printf("  %-14s 0x%06llx 0x%0*llx 0x%0*llx 0x%05llx 0x%05llx %c%c%c %#llx\n",
 458               ph_type(ph.type), ph.offset, w, ph.vaddr, w, ph.paddr,
 459               ph.filesz, ph.memsz, ph.flags&4?'R':' ', ph.flags&2?'W':' ',
 460               ph.flags&1?'E':' ', ph.align);
 461        if (ph.type == 3 /*PH_INTERP*/ && ph.filesz - 1 < TT.size - ph.offset) {
 462          printf("      [Requesting program interpreter: %*s]\n",
 463                 (int) ph.filesz-1, TT.elf+ph.offset);
 464        }
 465      }
 466
 467      printf("\n"
 468             " Section to Segment mapping:\n"
 469             "  Segment Sections...\n");
 470      for (i=0; i<phnum; i++) {
 471        get_ph(i, &ph);
 472        printf("   %02d     ", i);
 473        for (j=0; j<TT.shnum; j++) {
 474          get_sh(j, &s);
 475          if (!*s.name) continue;
 476          if (s.offset >= ph.offset && s.offset+s.size <= ph.offset+ph.filesz)
 477            printf("%s ", s.name);
 478        }
 479        xputc('\n');
 480      }
 481    }
 482  }
 483
 484  // binutils ld emits a bunch of extra DT_NULL entries, so binutils readelf
 485  // uses two passes here! We just tell the truth, which matches -h.
 486  if (FLAG(d)) {
 487    char *dyn = TT.elf+dynamic.offset, *end = dyn+dynamic.size;
 488
 489    xputc('\n');
 490    if (!dynamic.size) printf("There is no dynamic section in this file.\n");
 491    else printf("Dynamic section at offset 0x%llx contains %lld entries:\n"
 492                "  %-*s %-20s %s\n",
 493                dynamic.offset, dynamic.size/dynamic.entsize,
 494                w+2, "Tag", "Type", "Name/Value");
 495    while (dyn < end) {
 496      unsigned long long tag = elf_long(&dyn), val = elf_long(&dyn);
 497      char *type = dt_type(tag);
 498
 499      printf(" 0x%0*llx %-20s ", w, tag, *type=='0' ? type : type+1);
 500      if (*type == 'd') printf("%lld\n", val);
 501      else if (*type == 'b') printf("%lld (bytes)\n", val);
 502      else if (*type == 's') printf("%s\n", TT.elf+dynstr.offset+val);
 503      else if (*type == 'f' || *type == 'F') {
 504        struct bitname { int bit; char *s; }
 505          df_names[] = {{0, "ORIGIN"},{1,"SYMBOLIC"},{2,"TEXTREL"},
 506            {3,"BIND_NOW"},{4,"STATIC_TLS"},{}},
 507          df_1_names[]={{0,"NOW"},{1,"GLOBAL"},{2,"GROUP"},{3,"NODELETE"},
 508            {5,"INITFIRST"},{27,"PIE"},{}},
 509          *names = *type == 'f' ? df_names : df_1_names;
 510        int mask;
 511
 512        if (*type == 'F') printf("Flags: ");
 513        for (j=0; names[j].s; j++) {
 514          if (val & (mask=(1<<names[j].bit))) {
 515            printf("%s%s", names[j].s, (val &= ~mask) ? " " : "");
 516          }
 517        }
 518        if (val) printf("0x%llx", val);
 519        xputc('\n');
 520      } else if (*type == 'N' || *type == 'R' || *type == 'S') {
 521        printf("%s: [%s]\n", *type=='N' ? "Shared library" :
 522          (*type=='R' ? "Library runpath" : "Library soname"),
 523          TT.elf+dynstr.offset+val);
 524      } else if (*type == 'P') {
 525        type = dt_type(val);
 526        j = strlen(type);
 527        if (*type != '0') type += 2, j -= 3;
 528        printf("%*.*s\n", j, j, type);
 529      } else printf("0x%llx\n", val);
 530    }
 531  }
 532
 533  if (FLAG(dyn_syms)) show_symbols(&dynsym, &dynstr);
 534  if (FLAG(s)) show_symbols(&symtab, &strtab);
 535
 536  if (FLAG(n)) {
 537    int found = 0;
 538
 539    for (i=0; i<TT.shnum; i++) {
 540      get_sh(i, &s);
 541      if (s.type == 7 /*SHT_NOTE*/) {
 542        printf("\nDisplaying notes found in: %s\n", s.name);
 543        show_notes(s.offset, s.size);
 544        found = 1;
 545      }
 546    }
 547    for (i=0; !found && i<phnum; i++) {
 548      get_ph(i, &ph);
 549      if (ph.type == 4 /*PT_NOTE*/) {
 550        printf("\n"
 551          "Displaying notes found at file offset 0x%llx with length 0x%llx:\n",
 552          ph.offset, ph.filesz);
 553        show_notes(ph.offset, ph.filesz);
 554      }
 555    }
 556  }
 557
 558  if (FLAG(x)) {
 559    if (find_section(TT.x, &s)) {
 560      char *p = TT.elf+s.offset;
 561      long offset = 0;
 562
 563      printf("\nHex dump of section '%s':\n", s.name);
 564      while (offset < s.size) {
 565        int space = 2*16 + 16/4;
 566
 567        printf("  0x%08lx ", offset);
 568        for (i=0; i<16 && offset < s.size; offset++) {
 569          space -= printf("%02x%s", *p++, ++i%4 ? "" : " ");
 570        }
 571        printf("%*s", space, "");
 572        for (p-=i; i; i--, p++) putchar(*p>=' ' && *p<='~' ? *p : '.');
 573        xputc('\n');
 574      }
 575      printf("\n");
 576    }
 577  }
 578
 579  if (FLAG(p)) {
 580    if (find_section(TT.p, &s)) {
 581      char *begin = TT.elf+s.offset, *end = begin + s.size, *p = begin;
 582      int any = 0;
 583
 584      printf("\nString dump of section '%s':\n", s.name);
 585      for (; p < end; p++) {
 586        if (isprint(*p)) {
 587          printf("  [%6tx]  ", p-begin);
 588          while (p < end && isprint(*p)) putchar(*p++);
 589          xputc('\n');
 590          any=1;
 591        }
 592      }
 593      if (!any) printf("  No strings found in this section.\n");
 594      printf("\n");
 595    }
 596  }
 597}
 598
 599void readelf_main(void)
 600{
 601  char **arg;
 602  int all = FLAG_d|FLAG_h|FLAG_l|FLAG_n|FLAG_S|FLAG_s|FLAG_dyn_syms;
 603
 604  if (FLAG(a)) toys.optflags |= all;
 605  if (FLAG(e)) toys.optflags |= FLAG_h|FLAG_l|FLAG_S;
 606  if (FLAG(s)) toys.optflags |= FLAG_dyn_syms;
 607  if (!(toys.optflags & (all|FLAG_p|FLAG_x))) help_exit("needs a flag");
 608
 609  for (arg = toys.optargs; *arg; arg++) {
 610    int fd = open(TT.f = *arg, O_RDONLY);
 611    struct stat sb;
 612
 613    if (fd == -1) perror_msg("%s", TT.f);
 614    else {
 615      if (fstat(fd, &sb)) perror_msg("%s", TT.f);
 616      else if (!sb.st_size) error_msg("%s: empty", TT.f);
 617      else if (!S_ISREG(sb.st_mode)) error_msg("%s: not a regular file",TT.f);
 618      else {
 619        TT.elf = xmmap(NULL, TT.size=sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
 620        scan_elf();
 621        munmap(TT.elf, TT.size);
 622      }
 623      close(fd);
 624    }
 625  }
 626}
 627