/************************************************************************* 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; }