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 return NULL; 339 } 340 341 return source; 342 } 343 344 345 status_t 346 ElfFile::CreateSymbolLookup(uint64 textDelta, ElfSymbolLookup*& _lookup) const 347 { 348 // Get the symbol table + corresponding string section. There may be two 349 // symbol tables: the dynamic and the non-dynamic one. The former contains 350 // only the symbols needed at run-time. The latter, if existing, is likely 351 // more complete. So try to find and use the latter one, falling back to the 352 // former. 353 ElfSection* symbolSection; 354 ElfSection* stringSection; 355 if (!_FindSymbolSections(symbolSection, stringSection, SHT_SYMTAB) 356 && !_FindSymbolSections(symbolSection, stringSection, SHT_DYNSYM)) { 357 return B_ENTRY_NOT_FOUND; 358 } 359 360 // create a source with a segment for each section 361 SymbolLookupSource* source = new(std::nothrow) SymbolLookupSource(fFD); 362 if (source == NULL) 363 return B_NO_MEMORY; 364 BReference<SymbolLookupSource> sourceReference(source, true); 365 366 if (!source->AddSegment(symbolSection->Offset(), symbolSection->Size(), 367 symbolSection->Offset()) 368 || !source->AddSegment(stringSection->Offset(), stringSection->Size(), 369 stringSection->Offset())) { 370 return B_NO_MEMORY; 371 } 372 373 // create the lookup 374 size_t symbolTableEntrySize = Is64Bit() 375 ? sizeof(ElfClass64::Sym) : sizeof(ElfClass32::Sym); 376 uint32 symbolCount = uint32(symbolSection->Size() / symbolTableEntrySize); 377 378 return ElfSymbolLookup::Create(source, symbolSection->Offset(), 0, 379 stringSection->Offset(), symbolCount, symbolTableEntrySize, textDelta, 380 f64Bit, fSwappedByteOrder, true, _lookup); 381 } 382 383 384 template<typename ElfClass> 385 status_t 386 ElfFile::_LoadFile(const char* fileName) 387 { 388 typedef typename ElfClass::Ehdr Ehdr; 389 typedef typename ElfClass::Phdr Phdr; 390 typedef typename ElfClass::Shdr Shdr; 391 392 // read the elf header 393 Ehdr elfHeader; 394 ssize_t bytesRead = pread(fFD, &elfHeader, sizeof(elfHeader), 0); 395 if (bytesRead != (ssize_t)sizeof(elfHeader)) 396 return bytesRead < 0 ? errno : B_ERROR; 397 398 // check the ELF header 399 if (!_CheckRange(0, sizeof(elfHeader)) 400 || !_CheckElfHeader<ElfClass>(elfHeader)) { 401 WARNING("\"%s\": Not a valid ELF file\n", fileName); 402 return B_BAD_DATA; 403 } 404 405 fType = Get(elfHeader.e_type); 406 fMachine = Get(elfHeader.e_machine); 407 408 if (Get(elfHeader.e_shnum) > 0) { 409 // check section header table values 410 uint64 sectionHeadersOffset = Get(elfHeader.e_shoff); 411 size_t sectionHeaderSize = Get(elfHeader.e_shentsize); 412 int sectionCount = Get(elfHeader.e_shnum); 413 size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; 414 if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { 415 WARNING("\"%s\": Invalid ELF header\n", fileName); 416 return B_BAD_DATA; 417 } 418 419 // read the section header table 420 uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); 421 if (sectionHeaderTable == NULL) 422 return B_NO_MEMORY; 423 MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); 424 425 bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, 426 sectionHeadersOffset); 427 if (bytesRead != (ssize_t)sectionHeaderTableSize) 428 return bytesRead < 0 ? errno : B_ERROR; 429 430 // check and get the section header string section 431 Shdr* stringSectionHeader = (Shdr*)(sectionHeaderTable 432 + Get(elfHeader.e_shstrndx) * sectionHeaderSize); 433 if (!_CheckRange(Get(stringSectionHeader->sh_offset), 434 Get(stringSectionHeader->sh_size))) { 435 WARNING("\"%s\": Invalid string section header\n", fileName); 436 return B_BAD_DATA; 437 } 438 size_t sectionStringSize = Get(stringSectionHeader->sh_size); 439 440 ElfSection* sectionStringSection = new(std::nothrow) ElfSection( 441 ".shstrtab", Get(stringSectionHeader->sh_type),fFD, 442 Get(stringSectionHeader->sh_offset), sectionStringSize, 443 Get(stringSectionHeader->sh_addr), 444 Get(stringSectionHeader->sh_flags), 445 Get(stringSectionHeader->sh_link)); 446 if (sectionStringSection == NULL) 447 return B_NO_MEMORY; 448 if (!fSections.AddItem(sectionStringSection)) { 449 delete sectionStringSection; 450 return B_NO_MEMORY; 451 } 452 453 status_t error = sectionStringSection->Load(); 454 if (error != B_OK) 455 return error; 456 457 const char* sectionStrings = (const char*)sectionStringSection->Data(); 458 459 // read the other sections 460 for (int i = 0; i < sectionCount; i++) { 461 Shdr* sectionHeader = (Shdr*)(sectionHeaderTable + i 462 * sectionHeaderSize); 463 // skip invalid sections and the section header string section 464 const char* name = sectionStrings + Get(sectionHeader->sh_name); 465 if (Get(sectionHeader->sh_name) >= sectionStringSize 466 || !_CheckRange(Get(sectionHeader->sh_offset), 467 Get(sectionHeader->sh_size)) 468 || i == Get(elfHeader.e_shstrndx)) { 469 continue; 470 } 471 472 // create an ElfSection 473 ElfSection* section = new(std::nothrow) ElfSection(name, 474 Get(sectionHeader->sh_type), fFD, Get(sectionHeader->sh_offset), 475 Get(sectionHeader->sh_size), Get(sectionHeader->sh_addr), 476 Get(sectionHeader->sh_flags), Get(sectionHeader->sh_link)); 477 if (section == NULL) 478 return B_NO_MEMORY; 479 if (!fSections.AddItem(section)) { 480 delete section; 481 return B_NO_MEMORY; 482 } 483 } 484 } 485 486 if (Get(elfHeader.e_phnum) > 0) { 487 // check program header table values 488 uint64 programHeadersOffset = Get(elfHeader.e_phoff); 489 size_t programHeaderSize = Get(elfHeader.e_phentsize); 490 int segmentCount = Get(elfHeader.e_phnum); 491 size_t programHeaderTableSize = programHeaderSize * segmentCount; 492 if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { 493 WARNING("\"%s\": Invalid ELF header\n", fileName); 494 return B_BAD_DATA; 495 } 496 497 // read the program header table 498 uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); 499 if (programHeaderTable == NULL) 500 return B_NO_MEMORY; 501 MemoryDeleter programHeaderTableDeleter(programHeaderTable); 502 503 bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, 504 programHeadersOffset); 505 if (bytesRead != (ssize_t)programHeaderTableSize) 506 return bytesRead < 0 ? errno : B_ERROR; 507 508 // read the program headers and create ElfSegment objects 509 for (int i = 0; i < segmentCount; i++) { 510 Phdr* programHeader = (Phdr*)(programHeaderTable + i 511 * programHeaderSize); 512 // skip invalid program headers 513 if (Get(programHeader->p_filesz) > 0 514 && !_CheckRange(Get(programHeader->p_offset), 515 Get(programHeader->p_filesz))) { 516 continue; 517 } 518 519 // create an ElfSegment 520 ElfSegment* segment = new(std::nothrow) ElfSegment( 521 Get(programHeader->p_type), Get(programHeader->p_offset), 522 Get(programHeader->p_filesz), Get(programHeader->p_vaddr), 523 Get(programHeader->p_memsz), Get(programHeader->p_flags)); 524 if (segment == NULL) 525 return B_NO_MEMORY; 526 if (!fSegments.AddItem(segment)) { 527 delete segment; 528 return B_NO_MEMORY; 529 } 530 } 531 } 532 533 return B_OK; 534 } 535 536 537 bool 538 ElfFile::_FindSymbolSections(ElfSection*& _symbolSection, 539 ElfSection*& _stringSection, uint32 type) const 540 { 541 // get the symbol table section 542 ElfSection* symbolSection = FindSection(type); 543 if (symbolSection == NULL) 544 return false; 545 546 // The symbol table section is linked to the corresponding string section. 547 ElfSection* stringSection = SectionAt(symbolSection->LinkIndex()); 548 if (stringSection == NULL || stringSection->Type() != SHT_STRTAB) 549 return false; 550 551 _symbolSection = symbolSection; 552 _stringSection = stringSection; 553 return true; 554 } 555 556 557 bool 558 ElfFile::_CheckRange(uint64 offset, uint64 size) const 559 { 560 return offset < fFileSize && offset + size <= fFileSize; 561 } 562 563 564 template<typename ElfClass> 565 bool 566 ElfFile::_CheckElfHeader(typename ElfClass::Ehdr& elfHeader) 567 { 568 if (Get(elfHeader.e_shnum) > 0) { 569 if (Get(elfHeader.e_shoff) == 0 570 || Get(elfHeader.e_shentsize) < sizeof(typename ElfClass::Shdr) 571 || Get(elfHeader.e_shstrndx) == SHN_UNDEF 572 || Get(elfHeader.e_shstrndx) >= Get(elfHeader.e_shnum)) { 573 return false; 574 } 575 } 576 577 if (Get(elfHeader.e_phnum) > 0) { 578 if (Get(elfHeader.e_phoff) == 0 579 || Get(elfHeader.e_phentsize) < sizeof(typename ElfClass::Phdr)) { 580 return false; 581 } 582 } 583 584 return true; 585 } 586