1 /* 2 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "ElfFile.h" 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <sys/stat.h> 14 #include <unistd.h> 15 16 #include <algorithm> 17 #include <new> 18 19 #include <AutoDeleter.h> 20 21 #include "ElfSymbolLookup.h" 22 #include "Tracing.h" 23 24 25 // #pragma mark - ElfSection 26 27 28 ElfSection::ElfSection(const char* name, uint32 type, int fd, uint64 offset, 29 uint64 size, target_addr_t loadAddress, uint32 flags, uint32 linkIndex) 30 : 31 fName(name), 32 fType(type), 33 fFD(fd), 34 fOffset(offset), 35 fSize(size), 36 fData(NULL), 37 fLoadAddress(loadAddress), 38 fFlags(flags), 39 fLoadCount(0), 40 fLinkIndex(linkIndex) 41 { 42 } 43 44 45 ElfSection::~ElfSection() 46 { 47 free(fData); 48 } 49 50 51 status_t 52 ElfSection::Load() 53 { 54 if (fLoadCount > 0) { 55 fLoadCount++; 56 return B_OK; 57 } 58 59 fData = malloc(fSize); 60 if (fData == NULL) 61 return B_NO_MEMORY; 62 63 ssize_t bytesRead = pread(fFD, fData, fSize, fOffset); 64 if (bytesRead < 0 || (uint64)bytesRead != fSize) { 65 free(fData); 66 fData = NULL; 67 return bytesRead < 0 ? errno : B_ERROR; 68 } 69 70 fLoadCount++; 71 return B_OK; 72 } 73 74 75 void 76 ElfSection::Unload() 77 { 78 if (fLoadCount == 0) 79 return; 80 81 if (--fLoadCount == 0) { 82 free(fData); 83 fData = NULL; 84 } 85 } 86 87 88 // #pragma mark - ElfSegment 89 90 91 ElfSegment::ElfSegment(uint32 type, uint64 fileOffset, uint64 fileSize, 92 target_addr_t loadAddress, target_size_t loadSize, uint32 flags) 93 : 94 fFileOffset(fileOffset), 95 fFileSize(fileSize), 96 fLoadAddress(loadAddress), 97 fLoadSize(loadSize), 98 fType(type), 99 fFlags(flags) 100 { 101 } 102 103 104 ElfSegment::~ElfSegment() 105 { 106 } 107 108 109 // #pragma mark - SymbolLookupSource 110 111 112 struct ElfFile::SymbolLookupSource : public ElfSymbolLookupSource { 113 SymbolLookupSource(int fd) 114 : 115 fFd(fd), 116 fSegments(8, true) 117 { 118 } 119 120 bool AddSegment(uint64 fileOffset, uint64 fileLength, uint64 memoryAddress) 121 { 122 Segment* segment = new(std::nothrow) Segment(fileOffset, fileLength, 123 memoryAddress); 124 if (segment == NULL || !fSegments.AddItem(segment)) { 125 delete segment; 126 return false; 127 } 128 return true; 129 } 130 131 virtual ssize_t Read(uint64 address, void* buffer, size_t size) 132 { 133 for (int32 i = 0; Segment* segment = fSegments.ItemAt(i); i++) { 134 if (address < segment->fMemoryAddress 135 || address - segment->fMemoryAddress 136 > segment->fFileLength) { 137 continue; 138 } 139 140 uint64 offset = address - segment->fMemoryAddress; 141 size_t toRead = (size_t)std::min((uint64)size, 142 segment->fFileLength - offset); 143 if (toRead == 0) 144 return 0; 145 146 ssize_t bytesRead = pread(fFd, buffer, toRead, 147 (off_t)(segment->fFileOffset + offset)); 148 if (bytesRead < 0) 149 return errno; 150 return bytesRead; 151 } 152 153 return B_BAD_VALUE; 154 } 155 156 private: 157 struct Segment { 158 uint64 fFileOffset; 159 uint64 fFileLength; 160 uint64 fMemoryAddress; 161 162 Segment(uint64 fileOffset, uint64 fileLength, uint64 memoryAddress) 163 : 164 fFileOffset(fileOffset), 165 fFileLength(fileLength), 166 fMemoryAddress(memoryAddress) 167 { 168 } 169 }; 170 171 private: 172 int fFd; 173 BObjectList<Segment> fSegments; 174 }; 175 176 177 // #pragma mark - ElfFile 178 179 180 ElfFile::ElfFile() 181 : 182 fFileSize(0), 183 fFD(-1), 184 fType(ET_NONE), 185 fMachine(EM_NONE), 186 f64Bit(false), 187 fSwappedByteOrder(false), 188 fSections(16, true), 189 fSegments(16, true) 190 { 191 } 192 193 194 ElfFile::~ElfFile() 195 { 196 if (fFD >= 0) 197 close(fFD); 198 } 199 200 201 status_t 202 ElfFile::Init(const char* fileName) 203 { 204 // open file 205 fFD = open(fileName, O_RDONLY); 206 if (fFD < 0) { 207 WARNING("Failed to open \"%s\": %s\n", fileName, strerror(errno)); 208 return errno; 209 } 210 211 // stat() file to get its size 212 struct stat st; 213 if (fstat(fFD, &st) < 0) { 214 WARNING("Failed to stat \"%s\": %s\n", fileName, strerror(errno)); 215 return errno; 216 } 217 fFileSize = st.st_size; 218 219 // Read the identification information to determine whether this is an 220 // ELF file at all and some relevant properties for reading it. 221 uint8 elfIdent[EI_NIDENT]; 222 ssize_t bytesRead = pread(fFD, elfIdent, sizeof(elfIdent), 0); 223 if (bytesRead != (ssize_t)sizeof(elfIdent)) 224 return bytesRead < 0 ? errno : B_ERROR; 225 226 // magic 227 if (!memcmp(elfIdent, ELFMAG, 4) == 0) 228 return B_ERROR; 229 230 // endianess 231 if (elfIdent[EI_DATA] == ELFDATA2LSB) { 232 fSwappedByteOrder = B_HOST_IS_BENDIAN != 0; 233 } else if (elfIdent[EI_DATA] == ELFDATA2MSB) { 234 fSwappedByteOrder = B_HOST_IS_LENDIAN != 0; 235 } else { 236 WARNING("%s: Invalid ELF data byte order: %d\n", fileName, 237 elfIdent[EI_DATA]); 238 return B_BAD_DATA; 239 } 240 241 // determine class and load 242 if(elfIdent[EI_CLASS] == ELFCLASS64) { 243 f64Bit = true; 244 return _LoadFile<ElfClass64>(fileName); 245 } 246 if(elfIdent[EI_CLASS] == ELFCLASS32) { 247 f64Bit = false; 248 return _LoadFile<ElfClass32>(fileName); 249 } 250 251 WARNING("%s: Invalid ELF class: %d\n", fileName, elfIdent[EI_CLASS]); 252 return B_BAD_DATA; 253 } 254 255 256 ElfSection* 257 ElfFile::GetSection(const char* name) 258 { 259 ElfSection* section = FindSection(name); 260 if (section != NULL && section->Load() == B_OK) 261 return section; 262 263 return NULL; 264 } 265 266 267 void 268 ElfFile::PutSection(ElfSection* section) 269 { 270 if (section != NULL) 271 section->Unload(); 272 } 273 274 275 ElfSection* 276 ElfFile::FindSection(const char* name) const 277 { 278 int32 count = fSections.CountItems(); 279 for (int32 i = 0; i < count; i++) { 280 ElfSection* section = fSections.ItemAt(i); 281 if (strcmp(section->Name(), name) == 0) 282 return section; 283 } 284 285 return NULL; 286 } 287 288 289 ElfSection* 290 ElfFile::FindSection(uint32 type) const 291 { 292 int32 count = fSections.CountItems(); 293 for (int32 i = 0; i < count; i++) { 294 ElfSection* section = fSections.ItemAt(i); 295 if (section->Type() == type) 296 return section; 297 } 298 299 return NULL; 300 } 301 302 303 ElfSegment* 304 ElfFile::TextSegment() const 305 { 306 int32 count = fSegments.CountItems(); 307 for (int32 i = 0; i < count; i++) { 308 ElfSegment* segment = fSegments.ItemAt(i); 309 if (segment->Type() == PT_LOAD && !segment->IsWritable()) 310 return segment; 311 } 312 313 return NULL; 314 } 315 316 317 ElfSegment* 318 ElfFile::DataSegment() const 319 { 320 int32 count = fSegments.CountItems(); 321 for (int32 i = 0; i < count; i++) { 322 ElfSegment* segment = fSegments.ItemAt(i); 323 if (segment->Type() == PT_LOAD && segment->IsWritable()) 324 return segment; 325 } 326 327 return NULL; 328 } 329 330 331 ElfSymbolLookupSource* 332 ElfFile::CreateSymbolLookupSource(uint64 fileOffset, uint64 fileLength, 333 uint64 memoryAddress) const 334 { 335 SymbolLookupSource* source = new(std::nothrow) SymbolLookupSource(fFD); 336 if (source == NULL 337 || !source->AddSegment(fileOffset, fileLength, memoryAddress)) { 338 delete source; 339 return NULL; 340 } 341 342 return source; 343 } 344 345 346 status_t 347 ElfFile::CreateSymbolLookup(uint64 textDelta, ElfSymbolLookup*& _lookup) const 348 { 349 // Get the symbol table + corresponding string section. There may be two 350 // symbol tables: the dynamic and the non-dynamic one. The former contains 351 // only the symbols needed at run-time. The latter, if existing, is likely 352 // more complete. So try to find and use the latter one, falling back to the 353 // former. 354 ElfSection* symbolSection; 355 ElfSection* stringSection; 356 if (!_FindSymbolSections(symbolSection, stringSection, SHT_SYMTAB) 357 && !_FindSymbolSections(symbolSection, stringSection, SHT_DYNSYM)) { 358 return B_ENTRY_NOT_FOUND; 359 } 360 361 // create a source with a segment for each section 362 SymbolLookupSource* source = new(std::nothrow) SymbolLookupSource(fFD); 363 if (source == NULL) 364 return B_NO_MEMORY; 365 BReference<SymbolLookupSource> sourceReference(source, true); 366 367 if (!source->AddSegment(symbolSection->Offset(), symbolSection->Size(), 368 symbolSection->Offset()) 369 || !source->AddSegment(stringSection->Offset(), stringSection->Size(), 370 stringSection->Offset())) { 371 return B_NO_MEMORY; 372 } 373 374 // create the lookup 375 size_t symbolTableEntrySize = Is64Bit() 376 ? sizeof(ElfClass64::Sym) : sizeof(ElfClass32::Sym); 377 uint32 symbolCount = uint32(symbolSection->Size() / symbolTableEntrySize); 378 379 return ElfSymbolLookup::Create(source, symbolSection->Offset(), 0, 380 stringSection->Offset(), symbolCount, symbolTableEntrySize, textDelta, 381 f64Bit, fSwappedByteOrder, true, _lookup); 382 } 383 384 385 template<typename ElfClass> 386 status_t 387 ElfFile::_LoadFile(const char* fileName) 388 { 389 typedef typename ElfClass::Ehdr Ehdr; 390 typedef typename ElfClass::Phdr Phdr; 391 typedef typename ElfClass::Shdr Shdr; 392 393 // read the elf header 394 Ehdr elfHeader; 395 ssize_t bytesRead = pread(fFD, &elfHeader, sizeof(elfHeader), 0); 396 if (bytesRead != (ssize_t)sizeof(elfHeader)) 397 return bytesRead < 0 ? errno : B_ERROR; 398 399 // check the ELF header 400 if (!_CheckRange(0, sizeof(elfHeader)) 401 || !_CheckElfHeader<ElfClass>(elfHeader)) { 402 WARNING("\"%s\": Not a valid ELF file\n", fileName); 403 return B_BAD_DATA; 404 } 405 406 fType = Get(elfHeader.e_type); 407 fMachine = Get(elfHeader.e_machine); 408 409 if (Get(elfHeader.e_shnum) > 0) { 410 // check section header table values 411 uint64 sectionHeadersOffset = Get(elfHeader.e_shoff); 412 size_t sectionHeaderSize = Get(elfHeader.e_shentsize); 413 int sectionCount = Get(elfHeader.e_shnum); 414 size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; 415 if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { 416 WARNING("\"%s\": Invalid ELF header\n", fileName); 417 return B_BAD_DATA; 418 } 419 420 // read the section header table 421 uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); 422 if (sectionHeaderTable == NULL) 423 return B_NO_MEMORY; 424 MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); 425 426 bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, 427 sectionHeadersOffset); 428 if (bytesRead != (ssize_t)sectionHeaderTableSize) 429 return bytesRead < 0 ? errno : B_ERROR; 430 431 // check and get the section header string section 432 Shdr* stringSectionHeader = (Shdr*)(sectionHeaderTable 433 + Get(elfHeader.e_shstrndx) * sectionHeaderSize); 434 if (!_CheckRange(Get(stringSectionHeader->sh_offset), 435 Get(stringSectionHeader->sh_size))) { 436 WARNING("\"%s\": Invalid string section header\n", fileName); 437 return B_BAD_DATA; 438 } 439 size_t sectionStringSize = Get(stringSectionHeader->sh_size); 440 441 ElfSection* sectionStringSection = new(std::nothrow) ElfSection( 442 ".shstrtab", Get(stringSectionHeader->sh_type),fFD, 443 Get(stringSectionHeader->sh_offset), sectionStringSize, 444 Get(stringSectionHeader->sh_addr), 445 Get(stringSectionHeader->sh_flags), 446 Get(stringSectionHeader->sh_link)); 447 if (sectionStringSection == NULL) 448 return B_NO_MEMORY; 449 if (!fSections.AddItem(sectionStringSection)) { 450 delete sectionStringSection; 451 return B_NO_MEMORY; 452 } 453 454 status_t error = sectionStringSection->Load(); 455 if (error != B_OK) 456 return error; 457 458 const char* sectionStrings = (const char*)sectionStringSection->Data(); 459 460 // read the other sections 461 for (int i = 0; i < sectionCount; i++) { 462 Shdr* sectionHeader = (Shdr*)(sectionHeaderTable + i 463 * sectionHeaderSize); 464 // skip invalid sections and the section header string section 465 const char* name = sectionStrings + Get(sectionHeader->sh_name); 466 if (Get(sectionHeader->sh_name) >= sectionStringSize 467 || !_CheckRange(Get(sectionHeader->sh_offset), 468 Get(sectionHeader->sh_size)) 469 || i == Get(elfHeader.e_shstrndx)) { 470 continue; 471 } 472 473 // create an ElfSection 474 ElfSection* section = new(std::nothrow) ElfSection(name, 475 Get(sectionHeader->sh_type), fFD, Get(sectionHeader->sh_offset), 476 Get(sectionHeader->sh_size), Get(sectionHeader->sh_addr), 477 Get(sectionHeader->sh_flags), Get(sectionHeader->sh_link)); 478 if (section == NULL) 479 return B_NO_MEMORY; 480 if (!fSections.AddItem(section)) { 481 delete section; 482 return B_NO_MEMORY; 483 } 484 } 485 } 486 487 if (Get(elfHeader.e_phnum) > 0) { 488 // check program header table values 489 uint64 programHeadersOffset = Get(elfHeader.e_phoff); 490 size_t programHeaderSize = Get(elfHeader.e_phentsize); 491 int segmentCount = Get(elfHeader.e_phnum); 492 size_t programHeaderTableSize = programHeaderSize * segmentCount; 493 if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { 494 WARNING("\"%s\": Invalid ELF header\n", fileName); 495 return B_BAD_DATA; 496 } 497 498 // read the program header table 499 uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); 500 if (programHeaderTable == NULL) 501 return B_NO_MEMORY; 502 MemoryDeleter programHeaderTableDeleter(programHeaderTable); 503 504 bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, 505 programHeadersOffset); 506 if (bytesRead != (ssize_t)programHeaderTableSize) 507 return bytesRead < 0 ? errno : B_ERROR; 508 509 // read the program headers and create ElfSegment objects 510 for (int i = 0; i < segmentCount; i++) { 511 Phdr* programHeader = (Phdr*)(programHeaderTable + i 512 * programHeaderSize); 513 // skip invalid program headers 514 if (Get(programHeader->p_filesz) > 0 515 && !_CheckRange(Get(programHeader->p_offset), 516 Get(programHeader->p_filesz))) { 517 continue; 518 } 519 520 // create an ElfSegment 521 ElfSegment* segment = new(std::nothrow) ElfSegment( 522 Get(programHeader->p_type), Get(programHeader->p_offset), 523 Get(programHeader->p_filesz), Get(programHeader->p_vaddr), 524 Get(programHeader->p_memsz), Get(programHeader->p_flags)); 525 if (segment == NULL) 526 return B_NO_MEMORY; 527 if (!fSegments.AddItem(segment)) { 528 delete segment; 529 return B_NO_MEMORY; 530 } 531 } 532 } 533 534 return B_OK; 535 } 536 537 538 bool 539 ElfFile::_FindSymbolSections(ElfSection*& _symbolSection, 540 ElfSection*& _stringSection, uint32 type) const 541 { 542 // get the symbol table section 543 ElfSection* symbolSection = FindSection(type); 544 if (symbolSection == NULL) 545 return false; 546 547 // The symbol table section is linked to the corresponding string section. 548 ElfSection* stringSection = SectionAt(symbolSection->LinkIndex()); 549 if (stringSection == NULL || stringSection->Type() != SHT_STRTAB) 550 return false; 551 552 _symbolSection = symbolSection; 553 _stringSection = stringSection; 554 return true; 555 } 556 557 558 bool 559 ElfFile::_CheckRange(uint64 offset, uint64 size) const 560 { 561 return offset < fFileSize && offset + size <= fFileSize; 562 } 563 564 565 template<typename ElfClass> 566 bool 567 ElfFile::_CheckElfHeader(typename ElfClass::Ehdr& elfHeader) 568 { 569 if (Get(elfHeader.e_shnum) > 0) { 570 if (Get(elfHeader.e_shoff) == 0 571 || Get(elfHeader.e_shentsize) < sizeof(typename ElfClass::Shdr) 572 || Get(elfHeader.e_shstrndx) == SHN_UNDEF 573 || Get(elfHeader.e_shstrndx) >= Get(elfHeader.e_shnum)) { 574 return false; 575 } 576 } 577 578 if (Get(elfHeader.e_phnum) > 0) { 579 if (Get(elfHeader.e_phoff) == 0 580 || Get(elfHeader.e_phentsize) < sizeof(typename ElfClass::Phdr)) { 581 return false; 582 } 583 } 584 585 return true; 586 } 587