1 /* 2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "Image.h" 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <sys/mman.h> 13 #include <unistd.h> 14 15 #include <new> 16 17 #include <runtime_loader.h> 18 #include <syscalls.h> 19 20 21 using namespace BPrivate::Debug; 22 23 24 // #pragma mark - Image 25 26 27 Image::Image() 28 { 29 } 30 31 32 Image::~Image() 33 { 34 } 35 36 37 // #pragma mark - SymbolTableBasedImage 38 39 40 SymbolTableBasedImage::SymbolTableBasedImage() 41 : 42 fLoadDelta(0), 43 fSymbolTable(NULL), 44 fStringTable(NULL), 45 fSymbolCount(0), 46 fStringTableSize(0) 47 { 48 } 49 50 51 SymbolTableBasedImage::~SymbolTableBasedImage() 52 { 53 } 54 55 56 const Elf32_Sym* 57 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress, 58 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const 59 { 60 const Elf32_Sym* symbolFound = NULL; 61 const char* symbolName = NULL; 62 bool exactMatch = false; 63 addr_t deltaFound = ~(addr_t)0; 64 65 for (int32 i = 0; i < fSymbolCount; i++) { 66 const Elf32_Sym* symbol = &fSymbolTable[i]; 67 68 if (symbol->st_value == 0 69 || symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) { 70 continue; 71 } 72 73 addr_t symbolAddress = symbol->st_value + fLoadDelta; 74 if (symbolAddress > address) 75 continue; 76 77 addr_t symbolDelta = address - symbolAddress; 78 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) 79 exactMatch = true; 80 81 if (exactMatch || symbolDelta < deltaFound) { 82 deltaFound = symbolDelta; 83 symbolFound = symbol; 84 symbolName = fStringTable + symbol->st_name; 85 86 if (exactMatch) 87 break; 88 } 89 } 90 91 if (symbolFound != NULL) { 92 if (_baseAddress != NULL) 93 *_baseAddress = symbolFound->st_value + fLoadDelta; 94 if (_symbolName != NULL) 95 *_symbolName = symbolName; 96 if (_exactMatch != NULL) 97 *_exactMatch = exactMatch; 98 if (_symbolNameLen != NULL) 99 *_symbolNameLen = _SymbolNameLen(symbolName); 100 } 101 102 return symbolFound; 103 } 104 105 106 status_t 107 SymbolTableBasedImage::NextSymbol(int32& iterator, const char** _symbolName, 108 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 109 int32* _symbolType) const 110 { 111 while (true) { 112 if (++iterator >= fSymbolCount) 113 return B_ENTRY_NOT_FOUND; 114 115 const Elf32_Sym* symbol = &fSymbolTable[iterator]; 116 117 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 118 && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT) 119 || symbol->st_value == 0) { 120 continue; 121 } 122 123 *_symbolName = fStringTable + symbol->st_name; 124 *_symbolNameLen = _SymbolNameLen(*_symbolName); 125 *_symbolAddress = symbol->st_value + fLoadDelta; 126 *_symbolSize = symbol->st_size; 127 *_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 128 ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 129 130 return B_OK; 131 } 132 } 133 134 135 size_t 136 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const 137 { 138 if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable 139 || (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) { 140 return 0; 141 } 142 143 return strnlen(symbolName, 144 (addr_t)fStringTable + fStringTableSize - (addr_t)symbolName); 145 } 146 147 148 // #pragma mark - ImageFile 149 150 151 ImageFile::ImageFile() 152 : 153 fFD(-1), 154 fFileSize(0), 155 fMappedFile((uint8*)MAP_FAILED) 156 { 157 } 158 159 160 ImageFile::~ImageFile() 161 { 162 if (fMappedFile != MAP_FAILED) 163 munmap(fMappedFile, fFileSize); 164 165 if (fFD >= 0) 166 close(fFD); 167 } 168 169 170 status_t 171 ImageFile::Init(const image_info& info) 172 { 173 // just copy the image info 174 fInfo = info; 175 176 // load the file 177 addr_t textAddress; 178 size_t textSize; 179 addr_t dataAddress; 180 size_t dataSize; 181 status_t error = _LoadFile(info.name, &textAddress, &textSize, &dataAddress, 182 &dataSize); 183 if (error != B_OK) 184 return error; 185 186 // compute the load delta 187 fLoadDelta = (addr_t)fInfo.text - textAddress; 188 189 return B_OK; 190 } 191 192 193 status_t 194 ImageFile::Init(const char* path) 195 { 196 // load the file 197 addr_t textAddress; 198 size_t textSize; 199 addr_t dataAddress; 200 size_t dataSize; 201 status_t error = _LoadFile(path, &textAddress, &textSize, &dataAddress, 202 &dataSize); 203 if (error != B_OK) 204 return error; 205 206 // init the image info 207 fInfo.id = -1; 208 fInfo.type = B_LIBRARY_IMAGE; 209 fInfo.sequence = 0; 210 fInfo.init_order = 0; 211 fInfo.init_routine = 0; 212 fInfo.term_routine = 0; 213 fInfo.device = -1; 214 fInfo.node = -1; 215 strlcpy(fInfo.name, path, sizeof(fInfo.name)); 216 fInfo.text = (void*)textAddress; 217 fInfo.data = (void*)dataAddress; 218 fInfo.text_size = textSize; 219 fInfo.data_size = dataSize; 220 221 // the image isn't loaded, so no delta 222 fLoadDelta = 0; 223 224 return B_OK; 225 } 226 227 228 status_t 229 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize, 230 addr_t* _dataAddress, size_t* _dataSize) 231 { 232 // open and stat() the file 233 fFD = open(path, O_RDONLY); 234 if (fFD < 0) 235 return errno; 236 237 struct stat st; 238 if (fstat(fFD, &st) < 0) 239 return errno; 240 241 fFileSize = st.st_size; 242 if (fFileSize < sizeof(Elf32_Ehdr)) 243 return B_NOT_AN_EXECUTABLE; 244 245 // map it 246 fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0); 247 if (fMappedFile == MAP_FAILED) 248 return errno; 249 250 // examine the elf header 251 Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile; 252 if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0) 253 return B_NOT_AN_EXECUTABLE; 254 255 if (elfHeader->e_ident[4] != ELFCLASS32) 256 return B_NOT_AN_EXECUTABLE; 257 258 // verify the location of the program headers 259 int32 programHeaderCount = elfHeader->e_phnum; 260 if (elfHeader->e_phoff < sizeof(Elf32_Ehdr) 261 || elfHeader->e_phentsize < sizeof(Elf32_Phdr) 262 || elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize 263 > fFileSize) { 264 return B_NOT_AN_EXECUTABLE; 265 } 266 267 Elf32_Phdr* programHeaders 268 = (Elf32_Phdr*)(fMappedFile + elfHeader->e_phoff); 269 270 // verify the location of the section headers 271 int32 sectionCount = elfHeader->e_shnum; 272 if (elfHeader->e_shoff < sizeof(Elf32_Ehdr) 273 || elfHeader->e_shentsize < sizeof(Elf32_Shdr) 274 || elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize 275 > fFileSize) { 276 return B_NOT_AN_EXECUTABLE; 277 } 278 279 Elf32_Shdr* sectionHeaders 280 = (Elf32_Shdr*)(fMappedFile + elfHeader->e_shoff); 281 282 // find the text and data segment -- we need load address and size 283 *_textAddress = 0; 284 *_textSize = 0; 285 *_dataAddress = 0; 286 *_dataSize = 0; 287 for (int32 i = 0; i < programHeaderCount; i++) { 288 Elf32_Phdr* header = (Elf32_Phdr*) 289 ((uint8*)programHeaders + i * elfHeader->e_phentsize); 290 if (header->p_type == PT_LOAD) { 291 if ((header->p_flags & PF_WRITE) == 0) { 292 *_textAddress = header->p_vaddr; 293 *_textSize = header->p_memsz; 294 } else { 295 *_dataAddress = header->p_vaddr; 296 *_dataSize = header->p_memsz; 297 break; 298 } 299 } 300 } 301 302 // find the symbol table 303 for (int32 i = 0; i < elfHeader->e_shnum; i++) { 304 Elf32_Shdr* sectionHeader = (Elf32_Shdr*) 305 ((uint8*)sectionHeaders + i * elfHeader->e_shentsize); 306 307 if (sectionHeader->sh_type == SHT_SYMTAB) { 308 Elf32_Shdr& stringHeader = *(Elf32_Shdr*) 309 ((uint8*)sectionHeaders 310 + sectionHeader->sh_link * elfHeader->e_shentsize); 311 312 if (stringHeader.sh_type != SHT_STRTAB) 313 return B_BAD_DATA; 314 315 if (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize 316 || stringHeader.sh_offset + stringHeader.sh_size > fFileSize) { 317 return B_BAD_DATA; 318 } 319 320 fSymbolTable = (Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset); 321 fStringTable = (char*)(fMappedFile + stringHeader.sh_offset); 322 fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym); 323 fStringTableSize = stringHeader.sh_size; 324 325 return B_OK; 326 } 327 } 328 329 return B_BAD_DATA; 330 } 331 332 333 // #pragma mark - KernelImage 334 335 336 KernelImage::KernelImage() 337 { 338 } 339 340 341 KernelImage::~KernelImage() 342 { 343 delete[] fSymbolTable; 344 delete[] fStringTable; 345 } 346 347 348 status_t 349 KernelImage::Init(const image_info& info) 350 { 351 fInfo = info; 352 353 // get the table sizes 354 fSymbolCount = 0; 355 fStringTableSize = 0; 356 status_t error = _kern_read_kernel_image_symbols(fInfo.id, 357 NULL, &fSymbolCount, NULL, &fStringTableSize, NULL); 358 if (error != B_OK) 359 return error; 360 361 // allocate the tables 362 fSymbolTable = new(std::nothrow) Elf32_Sym[fSymbolCount]; 363 fStringTable = new(std::nothrow) char[fStringTableSize]; 364 if (fSymbolTable == NULL || fStringTable == NULL) 365 return B_NO_MEMORY; 366 367 // get the info 368 return _kern_read_kernel_image_symbols(fInfo.id, 369 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize, 370 &fLoadDelta); 371 } 372