一个简单的elf文件头查看工具

/*
 * Copyright (c) 2013 Kiba Amor <[email protected]>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list ofconditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materialsprovided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
 * COPYRIGHT HOLDER 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>

#ifndef _countof
#define _countof(X) (sizeof(X)/sizeof(X[0]))
#endif

#define safe_free(X) \
  if (X != NULL) \
  { \
    free(X); \
    X = NULL; \
  }

#if defined(__x86_64__)
#define ARCH "x86_64"
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Phdr Elf_Phdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Sym  Elf_Sym;
#define ELF_ST_TYPE(X) ELF64_ST_TYPE(X)
#define ELF_ST_BIND(X) ELF64_ST_BIND(X)
#define ELF_ST_VISIBILITY(X) ELF64_ST_VISIBILITY(X)
typedef Elf64_Rel  Elf_Rel;
typedef Elf64_Rela Elf_Rela;
#define ELF_R_SYM(X)  ELF64_R_SYM(X)
#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
#else
#define ARCH "x86"
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Phdr Elf_Phdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Sym  Elf_Sym;
#define ELF_ST_TYPE(X) ELF32_ST_TYPE(X)
#define ELF_ST_BIND(X) ELF32_ST_BIND(X)
#define ELF_ST_VISIBILITY(X) ELF32_ST_VISIBILITY(X)
typedef Elf32_Rel  Elf_Rel;
typedef Elf32_Rela Elf_Rela;
#define ELF_R_SYM(X)  ELF32_R_SYM(X)
#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
#endif // __x86_64__

typedef struct
{
  int         key;
  const char* value;
} pair_t;

const char* g_selfname = NULL;
const char* g_filename = NULL;
int         g_file = -1;
Elf_Ehdr*   g_ehdr = NULL;
Elf_Phdr*   g_phdrs = NULL;
int         g_phdr_num = -1;
Elf_Shdr*   g_shdrs = NULL;
int         g_shdr_num = -1;
char*       g_shdr_str_tab = NULL;

void clean_up(void)
{
  if (g_file >= 0)
  {
    close(g_file);
    g_file = -1;
  }
  safe_free(g_ehdr);
  safe_free(g_phdrs);
  safe_free(g_shdrs);
  safe_free(g_shdr_str_tab);
}

int get_file(void)
{
  if (g_file < 0)
  {
    g_file = open(g_filename, O_RDONLY);
    if (g_file < 0)
    {
      perror("open input file failed");
      exit(EXIT_FAILURE);
    }
  }

  return g_file;
}

int read_at(int file, int pos, void* buf, int cnt)
{
  if (pos == lseek(file, pos, SEEK_SET))
    return read(file, buf, cnt) == cnt ? cnt : -1;
  return -1;
}

int is_elf_file(unsigned char* ident)
{
  if (!ident
      || ident[EI_MAG0] != ELFMAG0
      || ident[EI_MAG1] != ELFMAG1
      || ident[EI_MAG2] != ELFMAG2
      || ident[EI_MAG3] != ELFMAG3)
  {
    return 0;
  }
  return 1;
}

const Elf_Ehdr* get_ehdr(void)
{
  if (g_ehdr == NULL)
  {
    g_ehdr = (Elf_Ehdr *)malloc(sizeof(Elf_Ehdr));
    if (read_at(get_file(), 0, g_ehdr, sizeof(Elf_Ehdr)) < 0)
    {
      perror("read elf header failed\n");
      exit(EXIT_FAILURE);
    }
    else if (!is_elf_file(g_ehdr->e_ident))
    {
      fprintf(stderr, "'%s' is not a elf file\n", g_filename);
      exit(EXIT_FAILURE);
    }
    if (sizeof(Elf_Ehdr) != g_ehdr->e_ehsize)
    {
      fprintf(stderr, "elf header size mismatch\n");
      exit(EXIT_FAILURE);
    }
  }

  return g_ehdr;
}

const Elf_Phdr* get_phdrs(void)
{
  const Elf_Ehdr* ehdr = NULL;
  if (g_phdrs == NULL)
  {
    ehdr = get_ehdr();
    if (sizeof(Elf_Phdr) != ehdr->e_phentsize)
    {
      fprintf(stderr, "program header size mismatch\n");
      exit(EXIT_FAILURE);
    }
    g_phdr_num = ehdr->e_phnum;
    g_phdrs = (Elf_Phdr *)malloc(sizeof(Elf_Phdr) * g_phdr_num);
    if (read_at(get_file(), ehdr->e_phoff, g_phdrs, 
        sizeof(Elf_Phdr) * g_phdr_num) < 0)
    {
      perror("read program header failed\n");
      exit(EXIT_FAILURE);
    }
  }
  return g_phdrs;
}

const Elf_Shdr* get_shdrs(void)
{
  const Elf_Ehdr* ehdr = NULL;
  if (g_shdrs == NULL)
  {
    ehdr = get_ehdr();
    if (sizeof(Elf_Shdr) != ehdr->e_shentsize)
    {
      fprintf(stderr, "section header size mismatch\n");
      exit(EXIT_FAILURE);
    }
    g_shdr_num = ehdr->e_shnum;
    g_shdrs = (Elf_Shdr *)malloc(sizeof(Elf_Shdr) * g_shdr_num);
    if (read_at(get_file(), ehdr->e_shoff, g_shdrs,
          sizeof(Elf_Shdr) * g_shdr_num) < 0)
    {
      perror("read section header failed");
      exit(EXIT_FAILURE);
    }
  }
  return g_shdrs;
}

void* get_sect_cont_by_idx(int sect_idx)
{
  const Elf_Shdr* shdrs = NULL;
  void* sect_cont = NULL;

  if (sect_idx < 0 || sect_idx >= g_shdr_num)
    return NULL;

  shdrs = get_shdrs();
  sect_cont = (void *)malloc(shdrs[sect_idx].sh_size);

  if (read_at(get_file(), shdrs[sect_idx].sh_offset, 
    sect_cont, shdrs[sect_idx].sh_size) < 0)
  {
    safe_free(sect_cont);
    return NULL;
  }

  return sect_cont;
}

const char* get_shdr_str_tab(void)
{
  if (g_shdr_str_tab == NULL)
    g_shdr_str_tab = get_sect_cont_by_idx(get_ehdr()->e_shstrndx);
  return g_shdr_str_tab;
}

int get_sect_idx_by_name(const char* sect_name)
{
  const Elf_Shdr* shdrs = get_shdrs();
  const char* shdr_str_tab = get_shdr_str_tab();
  int i = 0;

  for (i = 0; i < g_shdr_num; ++i)
  {
    if (strcmp(sect_name, shdrs[i].sh_name + shdr_str_tab) == 0)
      return i;
  }

  return -1;
}

void print_pair(int key, const pair_t* pairs, int cnt, int linefeed)
{
  while (--cnt >= 0)
  {
    if (key == pairs[cnt].key)
    {
      printf("%s", pairs[cnt].value);
      break;
    }
  }
  if (linefeed)
    printf("\n");
}

void print_ehdr_ident(void)
{
  const pair_t classpairs[] = 
  {
    {ELFCLASSNONE,  "None"},
    {ELFCLASS32,    "ELF32"},
    {ELFCLASS64,    "ELF64"},
  };
  const pair_t datapairs[] =
  {
    {ELFDATANONE, "None"},
    {ELFDATA2LSB, "2's complement, little endian"},
    {ELFDATA2MSB, "2's complement, big endian"},
  };
  const pair_t osabipairs[] =
  {
    //{ELFOSABI_NONE,     "UNIX System VB ABI"},
    {ELFOSABI_SYSV,       "UNIX System VB ABI"},
    {ELFOSABI_HPUX,       "HP-UX"},
    {ELFOSABI_NETBSD,     "NetBSD"},
    //{ELFOSABI_GNU,      "Object uses GNU ELF extensions"},
    {ELFOSABI_LINUX,      "Object uses GNU ELF extensions"},
    {ELFOSABI_SOLARIS,    "Sun Solaris"},
    {ELFOSABI_AIX,        "AIX"},
    {ELFOSABI_IRIX,       "IBM Irix"},
    {ELFOSABI_FREEBSD,    "FreeBSD"},
    {ELFOSABI_TRU64,      "Compaq TRU64 UNIX"},
    {ELFOSABI_MODESTO,    "Novell Modesto"},
    {ELFOSABI_OPENBSD,    "OpenBSD"},
    {ELFOSABI_ARM_AEABI,  "ARM EABI"},
    {ELFOSABI_ARM,        "ARM"},
    {ELFOSABI_STANDALONE, "Standlone (embedded) application"},
  };
  const Elf_Ehdr* ehdr = get_ehdr();
  const unsigned char* ident = ehdr->e_ident;
  int i = 0;

  printf("ELF Header:\n  Magic:  ");
  for (i = 0; i < EI_NIDENT; ++i)  
    printf("%02X ", ident[i]);

  printf("\n  Class:                              ");
  print_pair(ident[EI_CLASS], classpairs, _countof(classpairs), 1);

  printf("  Data:                               ");
  print_pair(ident[EI_DATA], datapairs, _countof(datapairs), 1);

  printf("  Version:                            %d%s\n", ident[EI_VERSION],
      ident[EI_VERSION] == EV_CURRENT ? "(current)" : "");

  printf("  OS/ABI:                             ");
  print_pair(ident[EI_OSABI], osabipairs, _countof(osabipairs), 1);
}

void print_ehdr(void)
{
  const pair_t objtypepairs[] = 
  {
    {ET_NONE, "None"},
    {ET_REL,  "Relocatable file"},
    {ET_EXEC, "Executable file"},
    {ET_DYN,  "Shared object file"},
    {ET_CORE, "Core file"},
  };
  const pair_t machinepairs[] = 
  {
    {EM_NONE,       "None"},
    {EM_M32,        "AT&T WE 32100"},
    {EM_SPARC,      "SUN SPARC"},
    {EM_386,        "Intel 80386"},
    {EM_68K,        "Motorola m68k family"},
    {EM_88K,        "Motorola m88k family"},
    {EM_860,        "Intel 80860"},
    {EM_MIPS,       "MIPS R3000 big-endian"},
    {EM_S370,       "IBM System/370"},
    {EM_MIPS_RS3_LE,"MIPS R3000 little-endian"},
    {EM_PARISC,     "HPPA"},
    {EM_VPP500,     "Fujitsu VPP500"},
    {EM_SPARC32PLUS,"Sun's \"v8plus\""},
    {EM_960,        "Intel 80960"},
    {EM_PPC,        "PowerPC"},
    {EM_PPC64,      "PowerPC 64-bit"},
    {EM_S390,       "IBM S390"},
    {EM_V800,       "NEC V800 series"},
    {EM_FR20,       "Fujitsu FR20"},
    {EM_RH32,       "TRW RH-32"},
    {EM_RCE,        "Motorola RCE"},
    {EM_ARM,        "ARM"},
    {EM_FAKE_ALPHA, "Digital Alpha"},
    {EM_SH,         "Hitachi SH"},
    {EM_SPARCV9,    "SPARC v9 64-bit"},
    {EM_TRICORE,    "Siemens Tricore"},
    {EM_ARC,        "Argonaut RISC Core"},
    {EM_H8_300,     "Hitachi H8/300"},
    {EM_H8_300H,    "Hitachi H8/300H"},
    {EM_H8S,        "Hitachi H8S"},
    {EM_H8_500,     "Hitachi H8/500"},
    {EM_IA_64,      "Intel Merced"},
    {EM_MIPS_X,     "Stanford MIPS-X"},
    {EM_COLDFIRE,   "Motorola Coldfire"},
    {EM_68HC12,     "Motorola M68HC12"},
    {EM_MMA,        "Fujitsu MMA Multimedia Accelerator"},
    {EM_PCP,        "Siemens PCP"},
    {EM_NCPU,       "Sony nCPU embeeded RISC"},
    {EM_NDR1,       "Denso NDR1 microprocessor"},
    {EM_STARCORE,   "Motorola Start*Core processor"},
    {EM_ME16,       "Toyota ME16 processor"},
    {EM_ST100,      "STMicroelectronic ST100 processor"},
    {EM_TINYJ,      "Advanced Logic Corp. Tinyj emb.fam"},
    {EM_X86_64,     "AMD x86-64 architecture"},
    {EM_PDSP,       "Sony DSP Processor"},
    {EM_FX66,       "Siemens FX66 microcontroller"},
    {EM_ST9PLUS,    "STMicroelectronics ST9+ 8/16 mc"},
    {EM_ST7,        "STmicroelectronics ST7 8 bit mc"},
    {EM_68HC16,     "Motorola MC68HC16 microcontroller"},
    {EM_68HC11,     "Motorola MC68HC11 microcontroller"},
    {EM_68HC08,     "Motorola MC68HC08 microcontroller"},
    {EM_68HC05,     "Motorola MC68HC05 microcontroller"},
    {EM_SVX,        "Silicon Graphics SVx"},
    {EM_ST19,       "STMicroelectronics ST19 8 bit mc"},
    {EM_VAX,        "Digital VAX"},
    {EM_CRIS,       "Axis Communications 32-bit embedded processor"},
    {EM_JAVELIN,    "Infineon Technologies 32-bit embedded processor"},
    {EM_FIREPATH,   "Element 14 64-bit DSP Processor"},
    {EM_ZSP,        "LSI Logic 16-bit DSP Processor"},
    {EM_MMIX,       "Donald Knuth's educational 64-bit processor"},
    {EM_HUANY,      "Harvard University machine-independent object files"},
    {EM_PRISM,      "SiTera Prism"},
    {EM_AVR,        "Atmel AVR 8-bit microcontroller"},
    {EM_FR30,       "Fujitsu FR30"},
    {EM_D10V,       "Mitsubishi D10V"},
    {EM_D30V,       "Mitsubishi D30V"},
    {EM_V850,       "NEC v850"},
    {EM_M32R,       "Mitsubishi M32R"},
    {EM_MN10300,    "Matsushita MN10300"},
    {EM_MN10200,    "Matsushita MN10200"},
    {EM_PJ,         "picoJava"},
    {EM_OPENRISC,   "OpenRISC 32-bit embedded processor"},
    {EM_ARC_A5,     "ARC Cores Tangent-A5"},
    {EM_XTENSA,     "Tensilica Xtensa Architecture"},
  };
  const pair_t versionpairs[] =
  {
    {EV_NONE,     "None"},
    {EV_CURRENT,  "Current version"},
  };
  const Elf_Ehdr* ehdr = get_ehdr();

  print_ehdr_ident();

  printf("  Object file type:                   ");
  print_pair(ehdr->e_type, objtypepairs, _countof(objtypepairs), 1);

  printf("  Machine:                            ");
  print_pair(ehdr->e_machine, machinepairs, _countof(machinepairs), 1);

  printf("  Version:                            ");
  print_pair(ehdr->e_version, versionpairs, _countof(versionpairs), 1);

  printf("  Entry point address:                0x%08x\n", ehdr->e_entry);
  printf("  Start of program headers:           0x%08x (bytes into file)\n", ehdr->e_phoff);
  printf("  Start of section headers:           0x%08x (bytes into file)\n", ehdr->e_shoff);
  printf("  Flags:                              0x%08x\n", ehdr->e_flags);
  printf("  Size of this header:                %d (bytes)\n", ehdr->e_ehsize);
  printf("  Size of program headers:            %d (bytes)\n", ehdr->e_phentsize);
  printf("  Number of program headers:          %d\n", ehdr->e_phnum);
  printf("  Size of section headers:            %d (bytes)\n", ehdr->e_shentsize);
  printf("  Number of section headers:          %d\n", ehdr->e_shnum);
  printf("  Section header string table index:  %d\n\n", ehdr->e_shstrndx);
}

void print_phdrs(void)
{
  const pair_t typepairs[] = 
  {
    {PT_NULL,         "NULL        "},
    {PT_LOAD,         "LOAD        "},
    {PT_DYNAMIC,      "DYNAMIC     "},
    {PT_INTERP,       "INTERP      "},
    {PT_NOTE,         "NOTE        "},
    {PT_SHLIB,        "SHLIB       "},
    {PT_PHDR,         "PHDR        "},
    {PT_TLS,          "TLS         "},
    {PT_GNU_EH_FRAME, "GNU_EH_FRAME"},
    {PT_GNU_STACK,    "GUN_STACK   "},
    {PT_GNU_RELRO,    "GNU_RELRO   "},
  };
  const Elf_Phdr* phdrs = get_phdrs();
  int i;
  char tmp_buf[16];

  printf("Program Headers:\n");
  printf("  Type         Offset     VirtAddr   PhysAddr   FileSize   MemSize    Flag Align\n");
  for (i = 0; i < g_phdr_num; ++i)
  {
    printf("  ");
    print_pair(phdrs[i].p_type, typepairs, _countof(typepairs), 0);

    printf(" 0x%08x", phdrs[i].p_offset);

    printf(" 0x%08x", phdrs[i].p_vaddr);
    printf(" 0x%08x", phdrs[i].p_paddr);

    printf(" 0x%08x", phdrs[i].p_filesz);
    printf(" 0x%08x", phdrs[i].p_memsz);
    snprintf(tmp_buf, 16, "%s%s%s",
        phdrs[i].p_flags & PF_X ? "X" : "",
        phdrs[i].p_flags & PF_W ? "W" : "",
        phdrs[i].p_flags & PF_R ? "R" : "");
    printf(" %-4s", tmp_buf);
    printf(" 0x%04x\n", phdrs[i].p_align);
  }
  printf("\n");
}

void print_shdrs(void)
{
  const pair_t typepairs[] =
  {
    {SHT_NULL,            "NULL          "},
    {SHT_PROGBITS,        "PROGBITS      "},
    {SHT_SYMTAB,          "SYMTAB        "},
    {SHT_STRTAB,          "STRTAB        "},
    {SHT_RELA,            "RELA          "},
    {SHT_HASH,            "HASH          "},
    {SHT_DYNAMIC,         "DYNAMIC       "},
    {SHT_NOTE,            "NOTE          "},
    {SHT_NOBITS,          "NOBITS        "},
    {SHT_REL,             "REL           "},
    {SHT_SHLIB,           "SHLIB         "},
    {SHT_DYNSYM,          "DYNSYM        "},
    {SHT_INIT_ARRAY,      "INIT_ARRAY    "},
    {SHT_FINI_ARRAY,      "FINI_ARRAY    "},
    {SHT_PREINIT_ARRAY,   "PREINIT_ARRAY "},
    {SHT_GROUP,           "GROUP         "},
    {SHT_SYMTAB_SHNDX,    "SYMTAB_SHNDX  "},
    {SHT_GNU_ATTRIBUTES,  "GNU_ATTRIBUTES"},
    {SHT_GNU_HASH,        "GNU_HASH      "},
    {SHT_GNU_LIBLIST,     "GNU_LIBLIST   "},
    {SHT_GNU_verdef,      "GNU_verdef    "},
    {SHT_GNU_verneed,     "GNU_verneed   "},
    {SHT_GNU_versym,      "GNU_versym    "},
  };
  const Elf_Shdr* shdrs = get_shdrs();
  const char* shdr_str_tab = get_shdr_str_tab();
  int i;
  char tmp_buf[16];

  printf("Section Headers:\n");
  printf("  Idx Name               Type           Flags VirtAddr   Offset     Size       Link Info Align  EntrySize\n");
  for (i = 0; i < g_shdr_num; ++i)
  {
    printf(" %- 3d ", i);
    printf(" %-18s ", shdr_str_tab + shdrs[i].sh_name);
    print_pair(shdrs[i].sh_type, typepairs, _countof(typepairs), 0);
    snprintf(tmp_buf, 16, " %s%s%s%s%s%s%s%s%s%s",
        shdrs[i].sh_flags & SHF_WRITE             ? "W" : "",
        shdrs[i].sh_flags & SHF_ALLOC             ? "A" : "",
        shdrs[i].sh_flags & SHF_EXECINSTR         ? "E" : "",
        shdrs[i].sh_flags & SHF_MERGE             ? "M" : "",
        shdrs[i].sh_flags & SHF_STRINGS           ? "S" : "",
        shdrs[i].sh_flags & SHF_INFO_LINK         ? "I" : "",
        shdrs[i].sh_flags & SHF_LINK_ORDER        ? "L" : "",
        shdrs[i].sh_flags & SHF_OS_NONCONFORMING  ? "O" : "",
        shdrs[i].sh_flags & SHF_GROUP             ? "G" : "",
        shdrs[i].sh_flags & SHF_TLS               ? "T" : "");
    printf("%-5s ", tmp_buf);
    printf(" 0x%08x", shdrs[i].sh_addr);
    printf(" 0x%08x", shdrs[i].sh_offset);
    printf(" 0x%08x", shdrs[i].sh_size);
    printf("%- 4d ", shdrs[i].sh_link);
    printf("%- 4d ", shdrs[i].sh_info);
    printf(" 0x%04x", shdrs[i].sh_addralign);
    printf(" 0x%08x\n", shdrs[i].sh_entsize);
  }
  printf("Key to Flags:\n");
  printf("  W (Writable), A (Alloc), E(Executable), M (Merge), S (Strings),\n");
  printf("  I (Info), L (Link Order), O (Os Nonconforming), G (Group), T (TLS)\n\n");
}

void print_symbol_info_by_sect_idx(int sect_idx)
{
  const pair_t typepairs[] = 
  {
    {STT_NOTYPE,    "NOTYPE   "},
    {STT_OBJECT,    "OBJECT   "},
    {STT_FUNC,      "FUNC     "},
    {STT_SECTION,   "SECTION  "},
    {STT_FILE,      "FILE     "},
    {STT_COMMON,    "COMMON   "},
    {STT_TLS,       "TLS      "},
    {STT_GNU_IFUNC, "GUN_IFUNC"},
  };
  const pair_t bindpairs[] = 
  {
    {STB_LOCAL,       "LOCAL     "},
    {STB_GLOBAL,      "GLOBAL    "},
    {STB_WEAK,        "WEAK      "},
    {STB_GNU_UNIQUE,  "GUN_UNIQUE"},
  };
  const pair_t visiblepairs[] =
  {
    {STV_DEFAULT,   "DEFAULT   "},
    {STV_INTERNAL,  "INTERNAL  "},
    {STV_HIDDEN,    "HIDDEN    "},
    {STV_PROTECTED, "PROTECTED "},
  };
  const Elf_Shdr* shdrs = get_shdrs();
  const char* shdr_str_tab = get_shdr_str_tab();
  Elf_Sym* symbol = (Elf_Sym *)get_sect_cont_by_idx(sect_idx);
  int symbol_num = shdrs[sect_idx].sh_size / sizeof(Elf_Sym);
  char* symbol_str_tab = (char *)get_sect_cont_by_idx(shdrs[sect_idx].sh_link);
  int i = 0;

  if (symbol == NULL
    || symbol_str_tab == NULL)
  {
    safe_free(symbol);
    safe_free(symbol_str_tab);
    return;
  }

  printf("Symbol Info For '%s':\n", shdrs[sect_idx].sh_name + shdr_str_tab);
  printf("  Idx Value      Size   Type      Bind       Visibility Shndx  Name\n");
  for (i = 0; i < symbol_num; ++i)
  {
    printf("  %3d", i);
    printf(" 0x%08x", symbol[i].st_value);
    printf(" 0x%04x ", symbol[i].st_size);
    print_pair(ELF_ST_TYPE(symbol[i].st_info), typepairs, _countof(typepairs), 0);
    printf(" ");
    print_pair(ELF_ST_BIND(symbol[i].st_info), bindpairs, _countof(bindpairs), 0);
    printf(" ");
    print_pair(ELF_ST_VISIBILITY(symbol[i].st_other), visiblepairs, _countof(visiblepairs), 0);
    printf(" ");
    switch (symbol[i].st_shndx)
    {
      case SHN_UNDEF:
        printf("UNDEF ");
        break;
      case SHN_ABS:
        printf("ABS   ");
        break;
      case SHN_COMMON:
        printf("COMMON");
        break;
      default:
        printf("%-6d", symbol[i].st_shndx);
        break;
    }
    printf(" %s\n", symbol[i].st_name + symbol_str_tab);
  }

  safe_free(symbol);
  safe_free(symbol_str_tab);
}

void print_symbol_info(void)
{
  const Elf_Shdr* shdrs = get_shdrs();
  int i = 0;

  printf("Symbol Info:\n");
  for (i = 0; i < g_shdr_num; ++i)
  {
    if (shdrs[i].sh_type == SHT_SYMTAB 
      || shdrs[i].sh_type == SHT_DYNSYM)
    {
      print_symbol_info_by_sect_idx(i);
    }
  }
}

void print_relocation_info(void)
{ 
  const Elf_Shdr* shdrs = get_shdrs();
  const char* shdr_str_tab = get_shdr_str_tab();
  Elf_Rel* rel = NULL;
  int rel_num = 0;
  Elf_Sym* sym = NULL;
  char* sym_str_tab = NULL;
  int i = 0;
  int j = 0;

  printf("Relocation Info:\n");
  for (i = 0; i < g_shdr_num; ++i)
  {
    if (shdrs[i].sh_type == SHT_REL)
    {
      printf("Relocation Info Without Addends For '%s':\n", 
          shdrs[shdrs[i].sh_info].sh_name + shdr_str_tab);

      rel_num = shdrs[i].sh_size / sizeof(Elf_Rel);
      rel = (Elf_Rel *)get_sect_cont_by_idx(i);
      sym = (Elf_Sym *)get_sect_cont_by_idx(shdrs[i].sh_link);
      sym_str_tab = (char *)get_sect_cont_by_idx(shdrs[shdrs[i].sh_link].sh_link);

      printf("  OFFSET     TYPE       VALUE\n");
      for (j = 0; j < rel_num; ++j)
      {
        printf("  0x%08x", rel[j].r_offset);
        printf(" 0x%08x", ELF_R_TYPE(rel[j].r_info));
        printf(" %s\n", sym[ELF_R_SYM(rel[j].r_info)].st_name + sym_str_tab);
      }

      safe_free(rel);
      safe_free(sym);
      safe_free(sym_str_tab);
    }
  }
}

void print_all_str_tab(void)
{
  const Elf_Shdr* shdrs = get_shdrs();
  const char* shdr_str_tab = get_shdr_str_tab();
  char* str_tab = NULL;
  int str_tab_pos = 0;
  int i = 0;
  int j = 0;

  printf("All String Table:\n");
  for (i = 0; i < g_shdr_num; ++i)
  {
    if (shdrs[i].sh_type == SHT_STRTAB) 
    {
      printf("String Table '%s':\n", shdrs[i].sh_name + shdr_str_tab);
      printf("  Idx Value\n");

      str_tab = (char *)get_sect_cont_by_idx(i);
      for (j = 0, str_tab_pos = 0; str_tab_pos < shdrs[i].sh_size; ++j)
      {
        printf("  %3d %s\n", j, str_tab + str_tab_pos);
        str_tab_pos += strlen(str_tab + str_tab_pos) + 1;
      }
      safe_free(str_tab);
    }
  }
}

void print_usage(void)
{
  fprintf(stderr, "Usage: %s file\n", g_selfname);
  fprintf(stderr, " -a  same as -h -p -s -S -r -d\n");
  fprintf(stderr, " -h  dump ELF file header\n");
  fprintf(stderr, " -p  dump ELF file program header\n");
  fprintf(stderr, " -s  dump ELF file section header\n");
  fprintf(stderr, " -S  dump Symbol Info\n");
  fprintf(stderr, " -r  dump relocation info\n");
  fprintf(stderr, " -d  dump all string table\n");
  fprintf(stderr, " -v  print version info and exit\n");
}

void print_version(void)
{
  printf("Elf(Executable Linkable Format) file dump tool("ARCH")\n");
  printf("Copyright (c) 2013 Kiba Amor <[email protected]>\n");
  printf("All rights reserved.\n");
  printf("Version 1.0\n");
}

int main(int argc, char** argv)
{
  int i = 0;
  int j = 0;
  int show_ehdr = 0;
  int show_phdrs = 0;
  int show_shdrs = 0;
  int show_symbol_info = 0;
  int show_relocation_info = 0;
  int show_all_str_tab = 0;

  g_selfname = argv[0];

  for (i = 1; i < argc; ++i)
  {
    if (argv[i][0] != '-')
    {
      if (g_filename != NULL)
      {
        fprintf(stderr, "multi input file detected\n");
        return EXIT_FAILURE;
      }
      else
      {
        g_filename = argv[i];
        continue;
      }
    }

    for (j = (int)strlen(argv[i]) - 1; j > 0 ; --j)
    {
      switch (argv[i][j])
      {
        case 'a':
          show_ehdr = 1;
          show_phdrs = 1;
          show_shdrs = 1;
          show_symbol_info = 1;
          show_relocation_info = 1;
          show_all_str_tab = 1;
          break;
        case 'h':
          show_ehdr = 1;
          break;
        case 'p':
          show_phdrs = 1;
          break;
        case 's':
          show_shdrs = 1;
          break;
        case 'S':
          show_symbol_info = 1;
          break;
        case 'r':
          show_relocation_info = 1;
          break;
        case 'd':
          show_all_str_tab = 1;
          break;
        case 'v':
          print_version();
          return EXIT_FAILURE;
        default:
          fprintf(stderr, "unkown option: '%c'\n", argv[i][j]);
          return EXIT_FAILURE;
      }
    }
  }

  if (g_filename == NULL
      || (show_ehdr == 0
      && show_phdrs == 0
      && show_shdrs == 0 
      && show_symbol_info == 0
      && show_relocation_info == 0
      && show_all_str_tab == 0))
  {
    print_usage();
    return EXIT_FAILURE;
  }

  atexit(clean_up);

  if (show_ehdr)
    print_ehdr();
  if (show_phdrs)
    print_phdrs();
  if (show_shdrs)
    print_shdrs();
  if (show_symbol_info)
    print_symbol_info();
  if (show_relocation_info)
    print_relocation_info();
  if (show_all_str_tab)
    print_all_str_tab();

  return EXIT_SUCCESS;
}

你可能感兴趣的:(一个简单的elf文件头查看工具)