Home | History | Annotate | Download | only in qtools
      1 /*************************************************************************
      2     Copyright (C) 2002,2003,2004,2005 Wei Qin
      3     See file COPYING for more information.
      4 
      5     This program is free software; you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation; either version 2 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 *************************************************************************/
     15 
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <errno.h>
     19 #include <assert.h>
     20 #include "read_elf.h"
     21 
     22 #define SwapHalf(a) (((a & 0x00ff) << 8) | ((a & 0xff00) >> 8))
     23 #define SwapWord(a) (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24))
     24 #define SwapAddr(a) SwapWord(a)
     25 #define SwapOff(a) SwapWord(a)
     26 #define SwapSection(a) SwapHalf(a)
     27 
     28 int LittleEndian()
     29 {
     30   Elf32_Word a = 0x01020304;
     31   return *(char *) &a == 0x04;
     32 }
     33 
     34 void SwapElfHeader(Elf32_Ehdr *hdr)
     35 {
     36   hdr->e_type = SwapHalf(hdr->e_type);
     37   hdr->e_machine = SwapHalf(hdr->e_machine);
     38   hdr->e_version = SwapWord(hdr->e_version);
     39   hdr->e_entry = SwapAddr(hdr->e_entry);
     40   hdr->e_phoff = SwapOff(hdr->e_phoff);
     41   hdr->e_shoff = SwapOff(hdr->e_shoff);
     42   hdr->e_flags = SwapWord(hdr->e_flags);
     43   hdr->e_ehsize = SwapHalf(hdr->e_ehsize);
     44   hdr->e_phentsize = SwapHalf(hdr->e_phentsize);
     45   hdr->e_phnum = SwapHalf(hdr->e_phnum);
     46   hdr->e_shentsize = SwapHalf(hdr->e_shentsize);
     47   hdr->e_shnum = SwapHalf(hdr->e_shnum);
     48   hdr->e_shstrndx = SwapHalf(hdr->e_shstrndx);
     49 }
     50 
     51 void SwapSectionHeader(Elf32_Shdr *shdr)
     52 {
     53   shdr->sh_name = SwapWord(shdr->sh_name);
     54   shdr->sh_type = SwapWord(shdr->sh_type);
     55   shdr->sh_flags = SwapWord(shdr->sh_flags);
     56   shdr->sh_addr = SwapAddr(shdr->sh_addr);
     57   shdr->sh_offset = SwapOff(shdr->sh_offset);
     58   shdr->sh_size = SwapWord(shdr->sh_size);
     59   shdr->sh_link = SwapWord(shdr->sh_link);
     60   shdr->sh_info = SwapWord(shdr->sh_info);
     61   shdr->sh_addralign = SwapWord(shdr->sh_addralign);
     62   shdr->sh_entsize = SwapWord(shdr->sh_entsize);
     63 }
     64 
     65 void SwapElfSymbol(Elf32_Sym *sym)
     66 {
     67     sym->st_name = SwapWord(sym->st_name);
     68     sym->st_value = SwapAddr(sym->st_value);
     69     sym->st_size = SwapWord(sym->st_size);
     70     sym->st_shndx = SwapSection(sym->st_shndx);
     71 }
     72 
     73 void AdjustElfHeader(Elf32_Ehdr *hdr)
     74 {
     75   switch(hdr->e_ident[EI_DATA])
     76   {
     77     case ELFDATA2LSB:
     78       if (!LittleEndian())
     79         SwapElfHeader(hdr);
     80       break;
     81     case ELFDATA2MSB:
     82       if (LittleEndian())
     83         SwapElfHeader(hdr);
     84       break;
     85   }
     86 }
     87 
     88 void AdjustSectionHeader(Elf32_Ehdr *hdr, Elf32_Shdr *shdr)
     89 {
     90   switch(hdr->e_ident[EI_DATA])
     91   {
     92     case ELFDATA2LSB:
     93       if (!LittleEndian())
     94         SwapSectionHeader(shdr);
     95       break;
     96     case ELFDATA2MSB:
     97       if (LittleEndian())
     98         SwapSectionHeader(shdr);
     99       break;
    100   }
    101 }
    102 
    103 void AdjustElfSymbols(Elf32_Ehdr *hdr, Elf32_Sym *elf_symbols, int num_entries)
    104 {
    105     if (hdr->e_ident[EI_DATA] == ELFDATA2LSB && LittleEndian())
    106         return;
    107     if (hdr->e_ident[EI_DATA] == ELFDATA2MSB && !LittleEndian())
    108         return;
    109     for (int ii = 0; ii < num_entries; ++ii) {
    110         SwapElfSymbol(&elf_symbols[ii]);
    111     }
    112 }
    113 
    114 Elf32_Ehdr *ReadElfHeader(FILE *fobj)
    115 {
    116   Elf32_Ehdr *hdr = new Elf32_Ehdr;
    117   int rval = fread(hdr, sizeof(Elf32_Ehdr), 1, fobj);
    118   if (rval != 1) {
    119     delete hdr;
    120     return NULL;
    121   }
    122   if (hdr->e_ident[EI_MAG0] != 0x7f || hdr->e_ident[EI_MAG1] != 'E' ||
    123       hdr->e_ident[EI_MAG2] != 'L' || hdr->e_ident[EI_MAG3] != 'F') {
    124     delete hdr;
    125     return NULL;
    126   }
    127   AdjustElfHeader(hdr);
    128   return hdr;
    129 }
    130 
    131 Elf32_Shdr *ReadSectionHeaders(Elf32_Ehdr *hdr, FILE *f)
    132 {
    133   int i;
    134   unsigned long sz = hdr->e_shnum * hdr->e_shentsize;
    135   assert(sizeof(Elf32_Shdr) == hdr->e_shentsize);
    136   Elf32_Shdr *shdr = new Elf32_Shdr[hdr->e_shnum];
    137 
    138   if (fseek(f, hdr->e_shoff, SEEK_SET) != 0)
    139   {
    140     delete[] shdr;
    141     return NULL;
    142   }
    143   if (fread(shdr, sz, 1, f) != 1)
    144   {
    145     delete[] shdr;
    146     return NULL;
    147   }
    148 
    149   for(i = 0; i < hdr->e_shnum; i++)
    150     AdjustSectionHeader(hdr, shdr + i);
    151 
    152   return shdr;
    153 }
    154 
    155 
    156 char *ReadStringTable(Elf32_Ehdr *hdr, Elf32_Shdr *shdr_table, FILE *f)
    157 {
    158   Elf32_Shdr *shdr = shdr_table + hdr->e_shstrndx;
    159   char *string_table;
    160 
    161   string_table = new char[shdr->sh_size];
    162   fseek(f, shdr->sh_offset, SEEK_SET);
    163   fread(string_table, shdr->sh_size, 1, f);
    164 
    165   return string_table;
    166 }
    167 
    168 int ReadSection(Elf32_Shdr *shdr, void *buffer, FILE *f)
    169 {
    170   if (fseek(f, shdr->sh_offset, SEEK_SET) != 0)
    171     return -1;
    172   if (fread(buffer, shdr->sh_size, 1, f) != 1)
    173     return -1;
    174   return 0;
    175 }
    176 
    177 char *GetSymbolName(Elf32_Half index, char *string_table)
    178 {
    179   return string_table + index;
    180 }
    181 
    182 Elf32_Shdr *FindSymbolTableSection(Elf32_Ehdr *hdr,
    183                                    Elf32_Shdr *shdr,
    184                                    char *string_table)
    185 {
    186   for(int ii = 0; ii < hdr->e_shnum; ii++) {
    187     if (shdr[ii].sh_type == SHT_SYMTAB &&
    188        strcmp(GetSymbolName(shdr[ii].sh_name, string_table),
    189               ".symtab") == 0)
    190     {
    191       return &shdr[ii];
    192     }
    193   }
    194   return NULL;
    195 }
    196 
    197 Elf32_Shdr *FindSymbolStringTableSection(Elf32_Ehdr *hdr,
    198                                          Elf32_Shdr *shdr,
    199                                          char *string_table)
    200 {
    201   for(int ii = 0; ii < hdr->e_shnum; ii++) {
    202     if (shdr[ii].sh_type == SHT_STRTAB &&
    203        strcmp(GetSymbolName(shdr[ii].sh_name, string_table),
    204               ".strtab") == 0)
    205     {
    206       return &shdr[ii];
    207     }
    208   }
    209   return NULL;
    210 }
    211