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 elf_shdr* sectionHeaders 309 = (elf_shdr*)(fMappedFile + elfHeader->e_shoff); 310 311 // find the text and data segment -- we need load address and size 312 *_textAddress = 0; 313 *_textSize = 0; 314 *_dataAddress = 0; 315 *_dataSize = 0; 316 for (int32 i = 0; i < programHeaderCount; i++) { 317 elf_phdr* header = (elf_phdr*) 318 ((uint8*)programHeaders + i * elfHeader->e_phentsize); 319 if (header->p_type == PT_LOAD) { 320 if ((header->p_flags & PF_WRITE) == 0) { 321 *_textAddress = header->p_vaddr; 322 *_textSize = header->p_memsz; 323 } else { 324 *_dataAddress = header->p_vaddr; 325 *_dataSize = header->p_memsz; 326 break; 327 } 328 } 329 } 330 331 // find the symbol table 332 for (int32 i = 0; i < elfHeader->e_shnum; i++) { 333 elf_shdr* sectionHeader = (elf_shdr*) 334 ((uint8*)sectionHeaders + i * elfHeader->e_shentsize); 335 336 if (sectionHeader->sh_type == SHT_SYMTAB) { 337 elf_shdr& stringHeader = *(elf_shdr*) 338 ((uint8*)sectionHeaders 339 + sectionHeader->sh_link * elfHeader->e_shentsize); 340 341 if (stringHeader.sh_type != SHT_STRTAB) 342 return B_BAD_DATA; 343 344 if ((off_t)(sectionHeader->sh_offset + sectionHeader->sh_size) 345 > fFileSize 346 || (off_t)(stringHeader.sh_offset + stringHeader.sh_size) 347 > fFileSize) { 348 return B_BAD_DATA; 349 } 350 351 fSymbolTable = (elf_sym*)(fMappedFile + sectionHeader->sh_offset); 352 fStringTable = (char*)(fMappedFile + stringHeader.sh_offset); 353 fSymbolCount = sectionHeader->sh_size / sizeof(elf_sym); 354 fStringTableSize = stringHeader.sh_size; 355 356 return B_OK; 357 } 358 } 359 360 return B_BAD_DATA; 361 } 362 363 364 // #pragma mark - KernelImage 365 366 367 KernelImage::KernelImage() 368 { 369 } 370 371 372 KernelImage::~KernelImage() 373 { 374 delete[] fSymbolTable; 375 delete[] fStringTable; 376 } 377 378 379 status_t 380 KernelImage::Init(const image_info& info) 381 { 382 fInfo = info; 383 384 // get the table sizes 385 fSymbolCount = 0; 386 fStringTableSize = 0; 387 status_t error = _kern_read_kernel_image_symbols(fInfo.id, 388 NULL, &fSymbolCount, NULL, &fStringTableSize, NULL); 389 if (error != B_OK) 390 return error; 391 392 // allocate the tables 393 fSymbolTable = new(std::nothrow) elf_sym[fSymbolCount]; 394 fStringTable = new(std::nothrow) char[fStringTableSize]; 395 if (fSymbolTable == NULL || fStringTable == NULL) 396 return B_NO_MEMORY; 397 398 // get the info 399 return _kern_read_kernel_image_symbols(fInfo.id, 400 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize, 401 &fLoadDelta); 402 } 403