| /************************************************************************* |
| Copyright (C) 2002,2003,2004,2005 Wei Qin |
| See file COPYING for more information. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| *************************************************************************/ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <assert.h> |
| #include "read_elf.h" |
| |
| #define SwapHalf(a) (((a & 0x00ff) << 8) | ((a & 0xff00) >> 8)) |
| #define SwapWord(a) (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24)) |
| #define SwapAddr(a) SwapWord(a) |
| #define SwapOff(a) SwapWord(a) |
| #define SwapSection(a) SwapHalf(a) |
| |
| int LittleEndian() |
| { |
| Elf32_Word a = 0x01020304; |
| return *(char *) &a == 0x04; |
| } |
| |
| void SwapElfHeader(Elf32_Ehdr *hdr) |
| { |
| hdr->e_type = SwapHalf(hdr->e_type); |
| hdr->e_machine = SwapHalf(hdr->e_machine); |
| hdr->e_version = SwapWord(hdr->e_version); |
| hdr->e_entry = SwapAddr(hdr->e_entry); |
| hdr->e_phoff = SwapOff(hdr->e_phoff); |
| hdr->e_shoff = SwapOff(hdr->e_shoff); |
| hdr->e_flags = SwapWord(hdr->e_flags); |
| hdr->e_ehsize = SwapHalf(hdr->e_ehsize); |
| hdr->e_phentsize = SwapHalf(hdr->e_phentsize); |
| hdr->e_phnum = SwapHalf(hdr->e_phnum); |
| hdr->e_shentsize = SwapHalf(hdr->e_shentsize); |
| hdr->e_shnum = SwapHalf(hdr->e_shnum); |
| hdr->e_shstrndx = SwapHalf(hdr->e_shstrndx); |
| } |
| |
| void SwapSectionHeader(Elf32_Shdr *shdr) |
| { |
| shdr->sh_name = SwapWord(shdr->sh_name); |
| shdr->sh_type = SwapWord(shdr->sh_type); |
| shdr->sh_flags = SwapWord(shdr->sh_flags); |
| shdr->sh_addr = SwapAddr(shdr->sh_addr); |
| shdr->sh_offset = SwapOff(shdr->sh_offset); |
| shdr->sh_size = SwapWord(shdr->sh_size); |
| shdr->sh_link = SwapWord(shdr->sh_link); |
| shdr->sh_info = SwapWord(shdr->sh_info); |
| shdr->sh_addralign = SwapWord(shdr->sh_addralign); |
| shdr->sh_entsize = SwapWord(shdr->sh_entsize); |
| } |
| |
| void SwapElfSymbol(Elf32_Sym *sym) |
| { |
| sym->st_name = SwapWord(sym->st_name); |
| sym->st_value = SwapAddr(sym->st_value); |
| sym->st_size = SwapWord(sym->st_size); |
| sym->st_shndx = SwapSection(sym->st_shndx); |
| } |
| |
| void AdjustElfHeader(Elf32_Ehdr *hdr) |
| { |
| switch(hdr->e_ident[EI_DATA]) |
| { |
| case ELFDATA2LSB: |
| if (!LittleEndian()) |
| SwapElfHeader(hdr); |
| break; |
| case ELFDATA2MSB: |
| if (LittleEndian()) |
| SwapElfHeader(hdr); |
| break; |
| } |
| } |
| |
| void AdjustSectionHeader(Elf32_Ehdr *hdr, Elf32_Shdr *shdr) |
| { |
| switch(hdr->e_ident[EI_DATA]) |
| { |
| case ELFDATA2LSB: |
| if (!LittleEndian()) |
| SwapSectionHeader(shdr); |
| break; |
| case ELFDATA2MSB: |
| if (LittleEndian()) |
| SwapSectionHeader(shdr); |
| break; |
| } |
| } |
| |
| void AdjustElfSymbols(Elf32_Ehdr *hdr, Elf32_Sym *elf_symbols, int num_entries) |
| { |
| if (hdr->e_ident[EI_DATA] == ELFDATA2LSB && LittleEndian()) |
| return; |
| if (hdr->e_ident[EI_DATA] == ELFDATA2MSB && !LittleEndian()) |
| return; |
| for (int ii = 0; ii < num_entries; ++ii) { |
| SwapElfSymbol(&elf_symbols[ii]); |
| } |
| } |
| |
| Elf32_Ehdr *ReadElfHeader(FILE *fobj) |
| { |
| Elf32_Ehdr *hdr = new Elf32_Ehdr; |
| int rval = fread(hdr, sizeof(Elf32_Ehdr), 1, fobj); |
| if (rval != 1) { |
| delete hdr; |
| return NULL; |
| } |
| if (hdr->e_ident[EI_MAG0] != 0x7f || hdr->e_ident[EI_MAG1] != 'E' || |
| hdr->e_ident[EI_MAG2] != 'L' || hdr->e_ident[EI_MAG3] != 'F') { |
| delete hdr; |
| return NULL; |
| } |
| AdjustElfHeader(hdr); |
| return hdr; |
| } |
| |
| Elf32_Shdr *ReadSectionHeaders(Elf32_Ehdr *hdr, FILE *f) |
| { |
| int i; |
| unsigned long sz = hdr->e_shnum * hdr->e_shentsize; |
| assert(sizeof(Elf32_Shdr) == hdr->e_shentsize); |
| Elf32_Shdr *shdr = new Elf32_Shdr[hdr->e_shnum]; |
| |
| if (fseek(f, hdr->e_shoff, SEEK_SET) != 0) |
| { |
| delete[] shdr; |
| return NULL; |
| } |
| if (fread(shdr, sz, 1, f) != 1) |
| { |
| delete[] shdr; |
| return NULL; |
| } |
| |
| for(i = 0; i < hdr->e_shnum; i++) |
| AdjustSectionHeader(hdr, shdr + i); |
| |
| return shdr; |
| } |
| |
| |
| char *ReadStringTable(Elf32_Ehdr *hdr, Elf32_Shdr *shdr_table, FILE *f) |
| { |
| Elf32_Shdr *shdr = shdr_table + hdr->e_shstrndx; |
| char *string_table; |
| |
| string_table = new char[shdr->sh_size]; |
| fseek(f, shdr->sh_offset, SEEK_SET); |
| fread(string_table, shdr->sh_size, 1, f); |
| |
| return string_table; |
| } |
| |
| int ReadSection(Elf32_Shdr *shdr, void *buffer, FILE *f) |
| { |
| if (fseek(f, shdr->sh_offset, SEEK_SET) != 0) |
| return -1; |
| if (fread(buffer, shdr->sh_size, 1, f) != 1) |
| return -1; |
| return 0; |
| } |
| |
| char *GetSymbolName(Elf32_Half index, char *string_table) |
| { |
| return string_table + index; |
| } |
| |
| Elf32_Shdr *FindSymbolTableSection(Elf32_Ehdr *hdr, |
| Elf32_Shdr *shdr, |
| char *string_table) |
| { |
| for(int ii = 0; ii < hdr->e_shnum; ii++) { |
| if (shdr[ii].sh_type == SHT_SYMTAB && |
| strcmp(GetSymbolName(shdr[ii].sh_name, string_table), |
| ".symtab") == 0) |
| { |
| return &shdr[ii]; |
| } |
| } |
| return NULL; |
| } |
| |
| Elf32_Shdr *FindSymbolStringTableSection(Elf32_Ehdr *hdr, |
| Elf32_Shdr *shdr, |
| char *string_table) |
| { |
| for(int ii = 0; ii < hdr->e_shnum; ii++) { |
| if (shdr[ii].sh_type == SHT_STRTAB && |
| strcmp(GetSymbolName(shdr[ii].sh_name, string_table), |
| ".strtab") == 0) |
| { |
| return &shdr[ii]; |
| } |
| } |
| return NULL; |
| } |