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 Elf32_Sym* 86 SymbolTableBasedImage::LookupSymbol(addr_t address, addr_t* _baseAddress, 87 const char** _symbolName, size_t *_symbolNameLen, bool *_exactMatch) const 88 { 89 const Elf32_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 Elf32_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 Elf32_Sym* symbol = &fSymbolTable[iterator]; 145 146 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 147 && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT) 148 || symbol->st_value == 0) { 149 continue; 150 } 151 152 *_symbolName = fStringTable + symbol->st_name; 153 *_symbolNameLen = _SymbolNameLen(*_symbolName); 154 *_symbolAddress = symbol->st_value + fLoadDelta; 155 *_symbolSize = symbol->st_size; 156 *_symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC 157 ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; 158 159 return B_OK; 160 } 161 } 162 163 164 size_t 165 SymbolTableBasedImage::_SymbolNameLen(const char* symbolName) const 166 { 167 if (symbolName == NULL || (addr_t)symbolName < (addr_t)fStringTable 168 || (addr_t)symbolName >= (addr_t)fStringTable + fStringTableSize) { 169 return 0; 170 } 171 172 return strnlen(symbolName, 173 (addr_t)fStringTable + fStringTableSize - (addr_t)symbolName); 174 } 175 176 177 // #pragma mark - ImageFile 178 179 180 ImageFile::ImageFile() 181 : 182 fFD(-1), 183 fFileSize(0), 184 fMappedFile((uint8*)MAP_FAILED) 185 { 186 } 187 188 189 ImageFile::~ImageFile() 190 { 191 if (fMappedFile != MAP_FAILED) 192 munmap(fMappedFile, fFileSize); 193 194 if (fFD >= 0) 195 close(fFD); 196 } 197 198 199 status_t 200 ImageFile::Init(const image_info& info) 201 { 202 // just copy the image info 203 fInfo = info; 204 205 // load the file 206 addr_t textAddress; 207 size_t textSize; 208 addr_t dataAddress; 209 size_t dataSize; 210 status_t error = _LoadFile(info.name, &textAddress, &textSize, &dataAddress, 211 &dataSize); 212 if (error != B_OK) 213 return error; 214 215 // compute the load delta 216 fLoadDelta = (addr_t)fInfo.text - textAddress; 217 218 return B_OK; 219 } 220 221 222 status_t 223 ImageFile::Init(const char* path) 224 { 225 // load the file 226 addr_t textAddress; 227 size_t textSize; 228 addr_t dataAddress; 229 size_t dataSize; 230 status_t error = _LoadFile(path, &textAddress, &textSize, &dataAddress, 231 &dataSize); 232 if (error != B_OK) 233 return error; 234 235 // init the image info 236 fInfo.id = -1; 237 fInfo.type = B_LIBRARY_IMAGE; 238 fInfo.sequence = 0; 239 fInfo.init_order = 0; 240 fInfo.init_routine = 0; 241 fInfo.term_routine = 0; 242 fInfo.device = -1; 243 fInfo.node = -1; 244 strlcpy(fInfo.name, path, sizeof(fInfo.name)); 245 fInfo.text = (void*)textAddress; 246 fInfo.data = (void*)dataAddress; 247 fInfo.text_size = textSize; 248 fInfo.data_size = dataSize; 249 250 // the image isn't loaded, so no delta 251 fLoadDelta = 0; 252 253 return B_OK; 254 } 255 256 257 status_t 258 ImageFile::_LoadFile(const char* path, addr_t* _textAddress, size_t* _textSize, 259 addr_t* _dataAddress, size_t* _dataSize) 260 { 261 // open and stat() the file 262 fFD = open(path, O_RDONLY); 263 if (fFD < 0) 264 return errno; 265 266 struct stat st; 267 if (fstat(fFD, &st) < 0) 268 return errno; 269 270 fFileSize = st.st_size; 271 if (fFileSize < sizeof(Elf32_Ehdr)) 272 return B_NOT_AN_EXECUTABLE; 273 274 // map it 275 fMappedFile = (uint8*)mmap(NULL, fFileSize, PROT_READ, MAP_PRIVATE, fFD, 0); 276 if (fMappedFile == MAP_FAILED) 277 return errno; 278 279 // examine the elf header 280 Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)fMappedFile; 281 if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0) 282 return B_NOT_AN_EXECUTABLE; 283 284 if (elfHeader->e_ident[4] != ELFCLASS32) 285 return B_NOT_AN_EXECUTABLE; 286 287 // verify the location of the program headers 288 int32 programHeaderCount = elfHeader->e_phnum; 289 if (elfHeader->e_phoff < sizeof(Elf32_Ehdr) 290 || elfHeader->e_phentsize < sizeof(Elf32_Phdr) 291 || elfHeader->e_phoff + programHeaderCount * elfHeader->e_phentsize 292 > fFileSize) { 293 return B_NOT_AN_EXECUTABLE; 294 } 295 296 Elf32_Phdr* programHeaders 297 = (Elf32_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(Elf32_Ehdr) 302 || elfHeader->e_shentsize < sizeof(Elf32_Shdr) 303 || elfHeader->e_shoff + sectionCount * elfHeader->e_shentsize 304 > fFileSize) { 305 return B_NOT_AN_EXECUTABLE; 306 } 307 308 Elf32_Shdr* sectionHeaders 309 = (Elf32_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 Elf32_Phdr* header = (Elf32_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 Elf32_Shdr* sectionHeader = (Elf32_Shdr*) 334 ((uint8*)sectionHeaders + i * elfHeader->e_shentsize); 335 336 if (sectionHeader->sh_type == SHT_SYMTAB) { 337 Elf32_Shdr& stringHeader = *(Elf32_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 (sectionHeader->sh_offset + sectionHeader->sh_size > fFileSize 345 || stringHeader.sh_offset + stringHeader.sh_size > fFileSize) { 346 return B_BAD_DATA; 347 } 348 349 fSymbolTable = (Elf32_Sym*)(fMappedFile + sectionHeader->sh_offset); 350 fStringTable = (char*)(fMappedFile + stringHeader.sh_offset); 351 fSymbolCount = sectionHeader->sh_size / sizeof(Elf32_Sym); 352 fStringTableSize = stringHeader.sh_size; 353 354 return B_OK; 355 } 356 } 357 358 return B_BAD_DATA; 359 } 360 361 362 // #pragma mark - KernelImage 363 364 365 KernelImage::KernelImage() 366 { 367 } 368 369 370 KernelImage::~KernelImage() 371 { 372 delete[] fSymbolTable; 373 delete[] fStringTable; 374 } 375 376 377 status_t 378 KernelImage::Init(const image_info& info) 379 { 380 fInfo = info; 381 382 // get the table sizes 383 fSymbolCount = 0; 384 fStringTableSize = 0; 385 status_t error = _kern_read_kernel_image_symbols(fInfo.id, 386 NULL, &fSymbolCount, NULL, &fStringTableSize, NULL); 387 if (error != B_OK) 388 return error; 389 390 // allocate the tables 391 fSymbolTable = new(std::nothrow) Elf32_Sym[fSymbolCount]; 392 fStringTable = new(std::nothrow) char[fStringTableSize]; 393 if (fSymbolTable == NULL || fStringTable == NULL) 394 return B_NO_MEMORY; 395 396 // get the info 397 return _kern_read_kernel_image_symbols(fInfo.id, 398 fSymbolTable, &fSymbolCount, fStringTable, &fStringTableSize, 399 &fLoadDelta); 400 } 401