1 // ElfFile.cpp 2 //------------------------------------------------------------------------------ 3 // Copyright (c) 2003, Ingo Weinhold 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a 6 // copy of this software and associated documentation files (the "Software"), 7 // to deal in the Software without restriction, including without limitation 8 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 // and/or sell copies of the Software, and to permit persons to whom the 10 // Software is furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 // DEALINGS IN THE SOFTWARE. 22 // 23 // File Name: ElfFile.cpp 24 // Author: Ingo Weinhold (bonefish@users.sf.net) 25 // Description: Implementation of classes for accessing ELF file, 26 // or more precisely for iterating through their relocation 27 // sections. 28 //------------------------------------------------------------------------------ 29 30 #include <new> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include "ElfFile.h" 36 37 // sanity bounds 38 static const uint32 kMaxELFHeaderSize = sizeof(Elf32_Ehdr) + 32; 39 40 // read_exactly 41 static 42 status_t 43 read_exactly(BPositionIO &file, off_t position, void *buffer, size_t size, 44 const char *errorMessage = NULL) 45 { 46 status_t error = B_OK; 47 ssize_t read = file.ReadAt(position, buffer, size); 48 if (read < 0) 49 error = read; 50 else if ((size_t)read != size) 51 error = B_ERROR; 52 if (error != B_OK && errorMessage) 53 puts(errorMessage); 54 return error; 55 } 56 57 58 // ElfSection 59 60 class ElfSection { 61 public: 62 ElfSection(); 63 ~ElfSection(); 64 65 void SetTo(ElfFile* file, Elf32_Shdr* header); 66 void Unset(); 67 bool IsInitialized() const { return fHeader; } 68 69 ElfFile* GetFile() const; 70 Elf32_Shdr* GetHeader() const { return fHeader; } 71 const char* GetName() const; 72 uint8* GetData() const { return fData; } 73 size_t GetSize() const; 74 Elf32_Word GetType() const; 75 Elf32_Word GetLink() const; 76 Elf32_Word GetInfo() const; 77 size_t GetEntrySize() const; 78 int32 CountEntries() const; 79 80 status_t Load(); 81 void Unload(); 82 83 void Dump(); 84 85 private: 86 ElfFile* fFile; 87 Elf32_Shdr* fHeader; 88 uint8* fData; 89 }; 90 91 // constructor 92 ElfSection::ElfSection() 93 : fFile(NULL), 94 fHeader(NULL), 95 fData(NULL) 96 { 97 } 98 99 // destructor 100 ElfSection::~ElfSection() 101 { 102 Unset(); 103 } 104 105 // SetTo 106 void 107 ElfSection::SetTo(ElfFile* file, Elf32_Shdr* header) 108 { 109 Unset(); 110 fFile = file; 111 fHeader = header; 112 } 113 114 // Unset 115 void 116 ElfSection::Unset() 117 { 118 Unload(); 119 fFile = NULL; 120 fHeader = NULL; 121 } 122 123 // GetFile 124 ElfFile* 125 ElfSection::GetFile() const 126 { 127 return fFile; 128 } 129 130 // GetName 131 const char* 132 ElfSection::GetName() const 133 { 134 const char* name = NULL; 135 if (fHeader && fFile) { 136 size_t size = 0; 137 const char* nameSection = fFile->GetSectionHeaderStrings(&size); 138 if (nameSection && fHeader->sh_name < size) 139 name = nameSection + fHeader->sh_name; 140 } 141 return name; 142 } 143 144 // GetSize 145 size_t 146 ElfSection::GetSize() const 147 { 148 return fHeader->sh_size; 149 } 150 151 // GetType 152 Elf32_Word 153 ElfSection::GetType() const 154 { 155 return fHeader->sh_type; 156 } 157 158 // GetLink 159 Elf32_Word 160 ElfSection::GetLink() const 161 { 162 return fHeader->sh_link; 163 } 164 165 // GetInfo 166 Elf32_Word 167 ElfSection::GetInfo() const 168 { 169 return fHeader->sh_info; 170 } 171 172 // GetEntrySize 173 size_t 174 ElfSection::GetEntrySize() const 175 { 176 return fHeader->sh_entsize; 177 } 178 179 // CountEntries 180 int32 181 ElfSection::CountEntries() const 182 { 183 int32 count = 0; 184 if (fHeader) { 185 if (GetEntrySize() == 0) 186 return 0; 187 count = GetSize() / GetEntrySize(); 188 } 189 return count; 190 } 191 192 // Load 193 status_t 194 ElfSection::Load() 195 { 196 status_t error = B_ERROR; 197 if (fHeader && !fData && fHeader->sh_type != SHT_NULL 198 && fHeader->sh_type != SHT_NOBITS) { 199 BFile* file = fFile->GetFile(); 200 // allocate memory 201 fData = new uint8[fHeader->sh_size]; 202 if (!fData) 203 return B_NO_MEMORY; 204 // read the data 205 error = read_exactly(*file, fHeader->sh_offset, fData, 206 fHeader->sh_size, "Failed to read section!\n"); 207 if (error != B_OK) 208 Unload(); 209 } 210 return error; 211 } 212 213 // Unload 214 void 215 ElfSection::Unload() 216 { 217 if (fData) { 218 delete[] fData; 219 fData = NULL; 220 } 221 } 222 223 // Dump 224 void 225 ElfSection::Dump() 226 { 227 printf("section %32s: size: %lu\n", GetName(), GetSize()); 228 } 229 230 231 // ElfSymbol 232 233 // constructor 234 ElfSymbol::ElfSymbol(ElfSection* section, int32 index) 235 : fSection(section), 236 fIndex(index), 237 fSymbol(NULL) 238 { 239 } 240 241 // destructor 242 ElfSymbol::~ElfSymbol() 243 { 244 Unset(); 245 } 246 247 // SetTo 248 void 249 ElfSymbol::SetTo(ElfSection* section, int32 index) 250 { 251 Unset(); 252 fSection = section; 253 fIndex = index; 254 } 255 256 // Unset 257 void 258 ElfSymbol::Unset() 259 { 260 fSection = NULL; 261 fIndex = -1; 262 fSymbol = NULL; 263 } 264 265 // GetSymbolStruct 266 const Elf32_Sym* 267 ElfSymbol::GetSymbolStruct() 268 { 269 Elf32_Sym* symbol = fSymbol; 270 if (!symbol && fSection && fSection->GetData()) { 271 size_t symbolSize = fSection->GetEntrySize(); 272 if (symbolSize == 0) 273 return NULL; 274 int32 symbolCount = fSection->GetSize() / symbolSize; 275 if (fIndex >= 0 && fIndex < symbolCount) 276 symbol = (Elf32_Sym*)(fSection->GetData() + fIndex * symbolSize); 277 } 278 return symbol; 279 } 280 281 // GetName 282 const char* 283 ElfSymbol::GetName() 284 { 285 const char* name = NULL; 286 if (const Elf32_Sym* symbol = GetSymbolStruct()) { 287 size_t size = 0; 288 const char* data = fSection->GetFile()->GetStringSectionStrings( 289 fSection->GetLink(), &size); 290 if (data && symbol->st_name < size) 291 name = data + symbol->st_name; 292 } 293 return name; 294 } 295 296 // GetBinding 297 uint32 298 ElfSymbol::GetBinding() 299 { 300 uint32 binding = STB_LOCAL; 301 if (const Elf32_Sym* symbol = GetSymbolStruct()) 302 binding = ELF32_ST_BIND(symbol->st_info); 303 return binding; 304 } 305 306 // GetType 307 uint32 308 ElfSymbol::GetType() 309 { 310 uint32 type = STT_NOTYPE; 311 if (const Elf32_Sym* symbol = GetSymbolStruct()) 312 type = ELF32_ST_TYPE(symbol->st_info); 313 return type; 314 } 315 316 // GetTargetSectionIndex 317 uint32 318 ElfSymbol::GetTargetSectionIndex() 319 { 320 uint32 index = SHN_UNDEF; 321 if (const Elf32_Sym* symbol = GetSymbolStruct()) 322 index = symbol->st_shndx; 323 return index; 324 } 325 326 327 // ElfRelocation 328 329 // constructor 330 ElfRelocation::ElfRelocation(ElfSection* section, int32 index) 331 : fSection(section), 332 fIndex(index), 333 fRelocation(NULL) 334 { 335 } 336 337 // destructor 338 ElfRelocation::~ElfRelocation() 339 { 340 Unset(); 341 } 342 343 // SetTo 344 void 345 ElfRelocation::SetTo(ElfSection* section, int32 index) 346 { 347 Unset(); 348 fSection = section; 349 fIndex = index; 350 } 351 352 // Unset 353 void 354 ElfRelocation::Unset() 355 { 356 fSection = NULL; 357 fIndex = -1; 358 fRelocation = NULL; 359 } 360 361 // GetRelocationStruct 362 Elf32_Rel* 363 ElfRelocation::GetRelocationStruct() 364 { 365 Elf32_Rel* relocation = fRelocation; 366 if (!relocation && fSection) { 367 if (!fSection->GetData()) { 368 if (fSection->Load() != B_OK) 369 return NULL; 370 } 371 size_t entrySize = fSection->GetEntrySize(); 372 if (entrySize == 0 || entrySize < sizeof(Elf32_Rel)) 373 return NULL; 374 int32 entryCount = fSection->GetSize() / entrySize; 375 if (fIndex >= 0 && fIndex < entryCount) { 376 relocation = (Elf32_Rel*)(fSection->GetData() 377 + fIndex * entrySize); 378 } 379 } 380 return relocation; 381 } 382 383 // GetType 384 uint32 385 ElfRelocation::GetType() 386 { 387 uint32 type = R_386_NONE; 388 if (Elf32_Rel* relocation = GetRelocationStruct()) 389 type = ELF32_R_TYPE(relocation->r_info); 390 return type; 391 } 392 393 // GetSymbolIndex 394 uint32 395 ElfRelocation::GetSymbolIndex() 396 { 397 uint32 index = 0; 398 if (Elf32_Rel* relocation = GetRelocationStruct()) 399 index = ELF32_R_SYM(relocation->r_info); 400 return index; 401 } 402 403 // GetOffset 404 Elf32_Addr 405 ElfRelocation::GetOffset() 406 { 407 Elf32_Addr offset = 0; 408 if (Elf32_Rel* relocation = GetRelocationStruct()) 409 offset = relocation->r_offset; 410 return offset; 411 } 412 413 // GetSymbol 414 status_t 415 ElfRelocation::GetSymbol(ElfSymbol* symbol) 416 { 417 status_t error = B_BAD_VALUE; 418 if (symbol && fSection) { 419 uint32 index = GetSymbolIndex(); 420 if (ElfSection* symbols 421 = fSection->GetFile()->SectionAt(fSection->GetLink(), true)) { 422 symbol->SetTo(symbols, index); 423 if (symbol->GetSymbolStruct()) 424 error = B_OK; 425 } 426 } 427 return error; 428 } 429 430 431 // ElfRelocationIterator 432 433 // constructor 434 ElfRelocationIterator::ElfRelocationIterator(ElfFile* file) 435 : fFile(file), 436 fSectionIndex(-1), 437 fEntryIndex(-1) 438 { 439 } 440 441 // destructor 442 ElfRelocationIterator::~ElfRelocationIterator() 443 { 444 } 445 446 // GetNext 447 bool 448 ElfRelocationIterator::GetNext(ElfRelocation* relocation) 449 { 450 bool result = false; 451 if (fFile && relocation) { 452 // set to possible entry 453 ElfSection* section = NULL; 454 if (fSectionIndex < 0) { 455 fSectionIndex = 0; 456 fEntryIndex = 0; 457 section = _FindNextSection(); 458 } else { 459 fEntryIndex++; 460 section = fFile->SectionAt(fSectionIndex); 461 } 462 // find next valid entry 463 while (section && fEntryIndex >= section->CountEntries()) { 464 fSectionIndex++; 465 section = _FindNextSection(); 466 fEntryIndex = 0; 467 } 468 // set result 469 if (section) { 470 relocation->SetTo(section, fEntryIndex); 471 result = true; 472 } 473 } 474 return result; 475 } 476 477 // _FindNextSection 478 ElfSection* 479 ElfRelocationIterator::_FindNextSection() 480 { 481 if (fFile) { 482 for (; fSectionIndex < fFile->CountSections(); fSectionIndex++) { 483 ElfSection* section = fFile->SectionAt(fSectionIndex); 484 if (section && section->GetType() == SHT_REL) 485 return section; 486 } 487 } 488 return NULL; 489 } 490 491 492 // ElfFile 493 494 // constructor 495 ElfFile::ElfFile() 496 : fFile(), 497 fSectionHeaders(NULL), 498 fSections(NULL), 499 fSectionCount(0), 500 fSectionHeaderSize(0) 501 { 502 } 503 504 // destructor 505 ElfFile::~ElfFile() 506 { 507 Unset(); 508 } 509 510 // SetTo 511 status_t 512 ElfFile::SetTo(const char *filename) 513 { 514 Unset(); 515 status_t error = _SetTo(filename); 516 if (error) 517 Unset(); 518 return error; 519 } 520 521 // Unset 522 void 523 ElfFile::Unset() 524 { 525 // delete sections 526 if (fSections) { 527 delete[] fSections; 528 fSections = NULL; 529 } 530 // delete section headers 531 if (fSectionHeaders) { 532 delete[] fSectionHeaders; 533 fSectionHeaders = NULL; 534 } 535 fSectionCount = 0; 536 fSectionHeaderSize = 0; 537 fFile.Unset(); 538 } 539 540 // Unload 541 void 542 ElfFile::Unload() 543 { 544 for (int i = 0; i < fSectionCount; i++) 545 fSections[i].Unload(); 546 } 547 548 // GetSectionHeaderStrings 549 const char* 550 ElfFile::GetSectionHeaderStrings(size_t* size) 551 { 552 return GetStringSectionStrings(fHeader.e_shstrndx, size); 553 } 554 555 // GetStringSectionStrings 556 const char* 557 ElfFile::GetStringSectionStrings(int32 index, size_t* _size) 558 { 559 const char* data = NULL; 560 size_t size = 0; 561 if (ElfSection* section = SectionAt(index, true)) { 562 data = (const char*)section->GetData(); 563 size = (data ? section->GetSize() : 0); 564 } 565 // set results 566 if (_size) 567 *_size = size; 568 return data; 569 } 570 571 // SectionAt 572 ElfSection* 573 ElfFile::SectionAt(int32 index, bool load) 574 { 575 ElfSection* section = NULL; 576 if (fSections && index >= 0 && index < fSectionCount) { 577 section = fSections + index; 578 if (load && !section->GetData()) { 579 if (section->Load() != B_OK) { 580 section = NULL; 581 printf("Failed to load section %ld\n", index); 582 } 583 } 584 } 585 return section; 586 } 587 588 // Dump 589 void 590 ElfFile::Dump() 591 { 592 printf("%ld sections\n", fSectionCount); 593 for (int i = 0; i < fSectionCount; i++) 594 fSections[i].Dump(); 595 } 596 597 // _SetTo 598 status_t 599 ElfFile::_SetTo(const char *filename) 600 { 601 if (!filename) 602 return B_BAD_VALUE; 603 // open file 604 status_t error = fFile.SetTo(filename, B_READ_ONLY); 605 // get the file size 606 off_t fileSize = 0; 607 error = fFile.GetSize(&fileSize); 608 if (error != B_OK) { 609 printf("Failed to get file size!\n"); 610 return error; 611 } 612 // read ELF header 613 error = read_exactly(fFile, 0, &fHeader, sizeof(Elf32_Ehdr), 614 "Failed to read ELF object header!\n"); 615 if (error != B_OK) 616 return error; 617 // check the ident field 618 // magic 619 if (fHeader.e_ident[EI_MAG0] != ELFMAG0 620 || fHeader.e_ident[EI_MAG1] != ELFMAG1 621 || fHeader.e_ident[EI_MAG2] != ELFMAG2 622 || fHeader.e_ident[EI_MAG3] != ELFMAG3) { 623 printf("Bad ELF file magic!\n"); 624 return B_BAD_VALUE; 625 } 626 // class 627 if (fHeader.e_ident[EI_CLASS] != ELFCLASS32) { 628 printf("Wrong ELF class!\n"); 629 return B_BAD_VALUE; 630 } 631 // check data encoding (endianess) 632 if (fHeader.e_ident[EI_DATA] != ELFDATA2LSB) { 633 printf("Wrong data encoding!\n"); 634 return B_BAD_VALUE; 635 } 636 // version 637 if (fHeader.e_ident[EI_VERSION] != EV_CURRENT) { 638 printf("Wrong data encoding!\n"); 639 return B_BAD_VALUE; 640 } 641 // get the header values 642 uint32 headerSize = fHeader.e_ehsize; 643 uint32 sectionHeaderTableOffset = fHeader.e_shoff; 644 uint32 sectionHeaderSize = fHeader.e_shentsize; 645 uint32 sectionHeaderCount = fHeader.e_shnum; 646 // check the sanity of the header values 647 // ELF header size 648 if (headerSize < sizeof(Elf32_Ehdr) || headerSize > kMaxELFHeaderSize) { 649 printf("Invalid ELF header: invalid ELF header size: %lu.", 650 headerSize); 651 return B_BAD_VALUE; 652 } 653 // section header table offset 654 if (sectionHeaderTableOffset == 0) { 655 printf("ELF file has no section header table!\n"); 656 return B_BAD_VALUE; 657 } 658 uint32 sectionHeaderTableSize = 0; 659 if (sectionHeaderTableOffset < headerSize 660 || sectionHeaderTableOffset > fileSize) { 661 printf("Invalid ELF header: invalid section header table offset: %lu.", 662 sectionHeaderTableOffset); 663 return B_BAD_VALUE; 664 } 665 // section header table offset 666 sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount; 667 if (sectionHeaderSize < sizeof(Elf32_Shdr) 668 || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) { 669 printf("Invalid ELF header: section header table exceeds file: %lu.", 670 sectionHeaderTableOffset + sectionHeaderTableSize); 671 return B_BAD_VALUE; 672 } 673 // allocate memory for the section header table and read it 674 fSectionHeaders = new(nothrow) uint8[sectionHeaderTableSize]; 675 fSectionCount = sectionHeaderCount; 676 fSectionHeaderSize = sectionHeaderSize; 677 if (!fSectionHeaders) 678 return B_NO_MEMORY; 679 error = read_exactly(fFile, sectionHeaderTableOffset, fSectionHeaders, 680 sectionHeaderTableSize, 681 "Failed to read section headers!\n"); 682 if (error != B_OK) 683 return error; 684 // allocate memory for the section pointers 685 fSections = new(nothrow) ElfSection[fSectionCount]; 686 if (!fSections) 687 return B_NO_MEMORY; 688 // init the sections 689 for (int i = 0; i < fSectionCount; i++) 690 fSections[i].SetTo(this, _SectionHeaderAt(i)); 691 return error; 692 } 693 694 // _SectionHeaderAt 695 Elf32_Shdr* 696 ElfFile::_SectionHeaderAt(int32 index) 697 { 698 Elf32_Shdr* header = NULL; 699 if (fSectionHeaders && index >= 0 && index < fSectionCount) 700 header = (Elf32_Shdr*)(fSectionHeaders + index * fSectionHeaderSize); 701 return header; 702 } 703 704 // _LoadSection 705 status_t 706 ElfFile::_LoadSection(int32 index) 707 { 708 status_t error = B_OK; 709 if (fSections && index >= 0 && index < fSectionCount) { 710 ElfSection& section = fSections[index]; 711 error = section.Load(); 712 } else 713 error = B_BAD_VALUE; 714 return error; 715 } 716 717