The Android Open Source Project | 52d4c30 | 2009-03-03 19:29:09 -0800 | [diff] [blame^] | 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 | } |