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 status_t 38 Image::GetSymbol(const char* name, int32 symbolType, void** _symbolLocation, 39 size_t* _symbolSize, int32* _symbolType) const 40 { 41 // TODO: At least for ImageFile we could do hash lookups! 42 int32 iterator = 0; 43 const char* foundName; 44 size_t foundNameLen; 45 addr_t foundAddress; 46 size_t foundSize; 47 int32 foundType; 48 while (NextSymbol(iterator, &foundName, &foundNameLen, &foundAddress, 49 &foundSize, &foundType) == B_OK) { 50 if ((symbolType == B_SYMBOL_TYPE_ANY || symbolType == foundType) 51 && strcmp(name, foundName) == 0) { 52 if (_symbolLocation != NULL) 53 *_symbolLocation = (void*)foundAddress; 54 if (_symbolSize != NULL) 55 *_symbolSize = foundSize; 56 if (_symbolType != NULL) 57 *_symbolType = foundType; 58 return B_OK; 59 } 60 } 61 62 return B_ENTRY_NOT_FOUND; 63 } 64 65 66 // #pragma mark - SymbolTableBasedImage 67 68 69 SymbolTableBasedImage::SymbolTableBasedImage() 70 : 71 fLoadDelta(0), 72 fSymbolTable(NULL), 73 fStringTable(NULL), 74 fSymbolCount(0), 75 fStringTableSize(0) 76 { 77 } 78 79 80 SymbolTableBasedImage::~SymbolTableBasedImage() 81 { 82 } 83 84 85 const elf_sym* 86 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress, 87 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const 88 { 89 const elf_sym* symbolFound = NULL; 90 const char* symbolName = NULL; 91 bool exactMatch = false; 92 addr_t deltaFound = ~(addr_t)0; 93 94 for (int32 i = 0; i < fSymbolCount; i++) { 95 const elf_sym* symbol = &fSymbolTable[i]; 96 97 if (symbol->st_value == 0 98 || symbol->st_size >= (size_t)fInfo.text_size + fInfo.data_size) { 99 continue; 100 } 101 102 addr_t symbolAddress = symbol->st_value + fLoadDelta; 103 if (symbolAddress > address) 104 continue; 105 106 addr_t symbolDelta = address - symbolAddress; 107 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) 108 exactMatch = true; 109 110 if (exactMatch || symbolDelta < deltaFound) { 111 deltaFound = symbolDelta; 112 symbolFound = symbol; 113 symbolName = fStringTable + symbol->st_name; 114 115 if (exactMatch) 116 break; 117 } 118 } 119 120 if (symbolFound != NULL) { 121 if (_baseAddress != NULL) 122 *_baseAddress = symbolFound->st_value + fLoadDelta; 123 if (_symbolName != NULL) 124 *_symbolName = symbolName; 125 if (_exactMatch != NULL) 126 *_exactMatch = exactMatch; 127 if (_symbolNameLen != NULL) 128 *_symbolNameLen = _SymbolNameLen(symbolName); 129 } 130 131 return symbolFound; 132 } 133 134 135 status_t 136 SymbolTableBasedImage::NextSymbol(int32& iterator, const char** _symbolName, 137 size_t* _symbolNameLen, addr_t* _symbolAddress, size_t* _symbolSize, 138 int32* _symbolType) const 139 { 140 while (true) { 141 if (++iterator >= fSymbolCount) 142 return B_ENTRY_NOT_FOUND; 143 144 const elf_sym* symbol = &fSymbolTable[iterator]; 145 146 if ((symbol->Type() != STT_FUNC && symbol->Type() != STT_OBJECT) 147 || symbol->st_value == 0) { 148 continue; 149 } 150 151 *_symbolName = fStringTable + symbol->st_name; 152 *_symbolNameLen = _SymbolNameLen(*_symbolName); 153 *_symbolAddress = symbol->st_value + fLoadDelta; 154 *_symbolSize = symbol->st_size; 155 *_symbolType = symbol->Type() == STT_FUNC ? B_SYMBOL_TYPE_TEXT 156 : B_SYMBOL_TYPE_DATA; 157 158 return B_OK; 159 } 160 } 161 162 163 size_t 164 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const 165 { 166 if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable 167 || (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) { 168 return 0; 169 } 170 171 return strnlen(symbolName, 172 (addr_t)fStringTable + fStringTableSize - (addr_t)symbolName); 173 } 174 175 176 // #pragma mark - ImageFile 177 178 179 ImageFile::ImageFile() 180 : 181 fFD(-1), 182 fFileSize(0), 183 fMappedFile((uint8*)MAP_FAILED) 184 { 185 } 186 187 188 ImageFile::~ImageFile() 189 { 190 if (fMappedFile != MAP_FAILED) 191 munmap(fMappedFile, fFileSize); 192 193 if (fFD >= 0) 194 close(fFD); 195 } 196 197 198 status_t 199 ImageFile::Init(const image_info& info) 200 { 201 // just copy the image info 202 fInfo = info; 203 204 // load the file 205 addr_t textAddress; 206 size_t textSize; 207 addr_t dataAddress; 208 size_t dataSize; 209 status_t error = _LoadFile(info.name, &textAddress, &textSize, &dataAddress, 210 &dataSize); 211 if (error != B_OK) 212 return error; 213 214 // compute the load delta 215 fLoadDelta = (addr_t)fInfo.text - textAddress; 216 217 return B_OK; 218 } 219 220 221 status_t 222 ImageFile::Init(const char* path) 223 { 224 // load the file 225 addr_t textAddress; 226 size_t textSize; 227 addr_t dataAddress; 228 size_t dataSize; 229 status_t error = _LoadFile(path, &textAddress, &textSize, &dataAddress, 230 &dataSize); 231 if (error != B_OK) 232 return error; 233 234 // init the image info 235 fInfo.id = -1; 236 fInfo.type = B_LIBRARY_IMAGE; 237 fInfo.sequence = 0; 238 fInfo.init_order = 0; 239 fInfo.init_routine = 0; 240 fInfo.term_routine = 0; 241 fInfo.device = -1; 242 fInfo.node = -1; 243 strlcpy(fInfo.name, path, sizeof(fInfo.name)); 244 fInfo.text = (void*)textAddress; 245 fInfo.data = (void*)dataAddress; 246 fInfo.text_size = textSize; 247 fInfo.data_size = dataSize; 248 249 // the image isn't loaded, so no delta 250 fLoadDelta = 0; 251 252 return B_OK; 253 } 254 255 256 status_t 257 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize, 258 addr_t* _dataAddress, size_t* _dataSize) 259 { 260 // open and stat() the file 261 fFD = open(path, O_RDONLY); 262 if (fFD < 0) 263 return errno; 264 265 struct stat st; 266 if (fstat(fFD, &st) < 0) 267 return errno; 268 269 fFileSize = st.st_size; 270 if (fFileSize < (off_t)sizeof(elf_ehdr)) 271 return B_NOT_AN_EXECUTABLE; 272 273 // map it 274 fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0); 275 if (fMappedFile == MAP_FAILED) 276 return errno; 277 278 // examine the elf header 279 elf_ehdr* elfHeader = (elf_ehdr*)fMappedFile; 280 if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0) 281 return B_NOT_AN_EXECUTABLE; 282 283 if (elfHeader->e_ident[4] != ELF_CLASS) 284 return B_NOT_AN_EXECUTABLE; 285 286 // verify the location of the program headers 287 int32 programHeaderCount = elfHeader->e_phnum; 288 if (elfHeader->e_phoff < sizeof(elf_ehdr) 289 || elfHeader->e_phentsize < sizeof(elf_phdr) 290 || (off_t)(elfHeader->e_phoff + programHeaderCount 291 * elfHeader->e_phentsize) 292 > fFileSize) { 293 return B_NOT_AN_EXECUTABLE; 294 } 295 296 elf_phdr* programHeaders 297 = (elf_phdr*)(fMappedFile + elfHeader->e_phoff); 298 299 // verify the location of the section headers 300 int32 sectionCount = elfHeader->e_shnum; 301 if (elfHeader->e_shoff < sizeof(elf_ehdr) 302 || elfHeader->e_shentsize < sizeof(elf_shdr) 303 || (off_t)(elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize) 304 > fFileSize) { 305 return B_NOT_AN_EXECUTABLE; 306 } 307 308 // find the text and data segment -- we need load address and size 309 *_textAddress = 0; 310 *_textSize = 0; 311 *_dataAddress = 0; 312 *_dataSize = 0; 313 for (int32 i = 0; i < programHeaderCount; i++) { 314 elf_phdr* header = (elf_phdr*) 315 ((uint8*)programHeaders + i * elfHeader->e_phentsize); 316 if (header->p_type == PT_LOAD) { 317 if ((header->p_flags & PF_WRITE) == 0) { 318 *_textAddress = header->p_vaddr; 319 *_textSize = header->p_memsz; 320 } else { 321 *_dataAddress = header->p_vaddr; 322 *_dataSize = header->p_memsz; 323 break; 324 } 325 } 326 } 327 328 status_t error = _FindTableInSection(elfHeader, SHT_SYMTAB); 329 if (error != B_OK) 330 error = _FindTableInSection(elfHeader, SHT_DYNSYM); 331 332 return error; 333 } 334 335 336 status_t 337 ImageFile::_FindTableInSection(elf_ehdr* elfHeader, uint16 sectionType) 338 { 339 elf_shdr* sectionHeaders 340 = (elf_shdr*)(fMappedFile + elfHeader->e_shoff); 341 342 // find the symbol table 343 for (int32 i = 0; i < elfHeader->e_shnum; i++) { 344 elf_shdr* sectionHeader = (elf_shdr*) 345 ((uint8*)sectionHeaders + i * elfHeader->e_shentsize); 346 347 if (sectionHeader->sh_type == sectionType) { 348 elf_shdr& stringHeader = *(elf_shdr*) 349 ((uint8*)sectionHeaders 350 + sectionHeader->sh_link * elfHeader->e_shentsize); 351 352 if (stringHeader.sh_type != SHT_STRTAB) 353 return B_BAD_DATA; 354 355 if ((off_t)(sectionHeader->sh_offset + sectionHeader->sh_size) 356 > fFileSize 357 || (off_t)(stringHeader.sh_offset + stringHeader.sh_size) 358 > fFileSize) { 359 return B_BAD_DATA; 360 } 361 362 fSymbolTable = (elf_sym*)(fMappedFile + sectionHeader->sh_offset); 363 fStringTable = (char*)(fMappedFile + stringHeader.sh_offset); 364 fSymbolCount = sectionHeader->sh_size / sizeof(elf_sym); 365 fStringTableSize = stringHeader.sh_size; 366 367 return B_OK; 368 } 369 } 370 371 return B_BAD_DATA; 372 } 373 374 375 // #pragma mark - KernelImage 376 377 378 KernelImage::KernelImage() 379 { 380 } 381 382 383 KernelImage::~KernelImage() 384 { 385 delete[] fSymbolTable; 386 delete[] fStringTable; 387 } 388 389 390 status_t 391 KernelImage::Init(const image_info& info) 392 { 393 fInfo = info; 394 395 // get the table sizes 396 fSymbolCount = 0; 397 fStringTableSize = 0; 398 status_t error = _kern_read_kernel_image_symbols(fInfo.id, 399 NULL, &fSymbolCount, NULL, &fStringTableSize, NULL); 400 if (error != B_OK) 401 return error; 402 403 // allocate the tables 404 fSymbolTable = new(std::nothrow) elf_sym[fSymbolCount]; 405 fStringTable = new(std::nothrow) char[fStringTableSize]; 406 if (fSymbolTable == NULL || fStringTable == NULL) 407 return B_NO_MEMORY; 408 409 // get the info 410 return _kern_read_kernel_image_symbols(fInfo.id, 411 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize, 412 &fLoadDelta); 413 } 414 415 416 CommPageImage::CommPageImage() 417 { 418 } 419 420 421 CommPageImage::~CommPageImage() 422 { 423 delete[] fSymbolTable; 424 delete[] fStringTable; 425 } 426 427 428 status_t 429 CommPageImage::Init(const image_info& info) 430 { 431 // find kernel image for commpage 432 image_id commPageID = -1; 433 image_info commPageInfo; 434 435 int32 cookie = 0; 436 while (_kern_get_next_image_info(B_SYSTEM_TEAM, &cookie, &commPageInfo, 437 sizeof(image_info)) == B_OK) { 438 if (!strcmp("commpage", commPageInfo.name)) { 439 commPageID = commPageInfo.id; 440 break; 441 } 442 } 443 if (commPageID < 0) 444 return B_ENTRY_NOT_FOUND; 445 446 fInfo = commPageInfo; 447 fInfo.text = info.text; 448 449 // get the table sizes 450 fSymbolCount = 0; 451 fStringTableSize = 0; 452 status_t error = _kern_read_kernel_image_symbols(commPageID, NULL, 453 &fSymbolCount, NULL, &fStringTableSize, NULL); 454 if (error != B_OK) 455 return error; 456 457 // allocate the tables 458 fSymbolTable = new(std::nothrow) elf_sym[fSymbolCount]; 459 fStringTable = new(std::nothrow) char[fStringTableSize]; 460 if (fSymbolTable == NULL || fStringTable == NULL) 461 return B_NO_MEMORY; 462 463 // get the info 464 error = _kern_read_kernel_image_symbols(commPageID, 465 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize, NULL); 466 if (error != B_OK) { 467 delete[] fSymbolTable; 468 delete[] fStringTable; 469 return error; 470 } 471 472 fLoadDelta = (addr_t)info.text; 473 474 return B_OK; 475 } 476