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 38static const uint32 kMaxELFHeaderSize = sizeof(Elf_Ehdr) + 32; 39 40// read_exactly 41static 42status_t 43read_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 60class SymbolPatcher::ElfSection { 61public: 62 ElfSection(); 63 ~ElfSection(); 64 65 void SetTo(ElfFile* file, Elf_Shdr* header); 66 void Unset(); 67 bool IsInitialized() const { return fHeader; } 68 69 ElfFile* GetFile() const; 70 Elf_Shdr* GetHeader() const { return fHeader; } 71 const char* GetName() const; 72 uint8* GetData() const { return fData; } 73 size_t GetSize() const; 74 Elf_Word GetType() const; 75 Elf_Word GetLink() const; 76 Elf_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 85private: 86 ElfFile* fFile; 87 Elf_Shdr* fHeader; 88 uint8* fData; 89}; 90 91// constructor 92ElfSection::ElfSection() 93 : fFile(NULL), 94 fHeader(NULL), 95 fData(NULL) 96{ 97} 98 99// destructor 100ElfSection::~ElfSection() 101{ 102 Unset(); 103} 104 105// SetTo 106void 107ElfSection::SetTo(ElfFile* file, Elf_Shdr* header) 108{ 109 Unset(); 110 fFile = file; 111 fHeader = header; 112} 113 114// Unset 115void 116ElfSection::Unset() 117{ 118 Unload(); 119 fFile = NULL; 120 fHeader = NULL; 121} 122 123// GetFile 124ElfFile* 125ElfSection::GetFile() const 126{ 127 return fFile; 128} 129 130// GetName 131const char* 132ElfSection::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 145size_t 146ElfSection::GetSize() const 147{ 148 return fHeader->sh_size; 149} 150 151// GetType 152Elf_Word 153ElfSection::GetType() const 154{ 155 return fHeader->sh_type; 156} 157 158// GetLink 159Elf_Word 160ElfSection::GetLink() const 161{ 162 return fHeader->sh_link; 163} 164 165// GetInfo 166Elf_Word 167ElfSection::GetInfo() const 168{ 169 return fHeader->sh_info; 170} 171 172// GetEntrySize 173size_t 174ElfSection::GetEntrySize() const 175{ 176 return fHeader->sh_entsize; 177} 178 179// CountEntries 180int32 181ElfSection::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 193status_t 194ElfSection::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 214void 215ElfSection::Unload() 216{ 217 if (fData) { 218 delete[] fData; 219 fData = NULL; 220 } 221} 222 223// Dump 224void 225ElfSection::Dump() 226{ 227 printf("section %32s: size: %lu\n", GetName(), GetSize()); 228} 229 230 231// ElfSymbol 232 233// constructor 234ElfSymbol::ElfSymbol(ElfSection* section, int32 index) 235 : fSection(section), 236 fIndex(index), 237 fSymbol(NULL) 238{ 239} 240 241// destructor 242ElfSymbol::~ElfSymbol() 243{ 244 Unset(); 245} 246 247// SetTo 248void 249ElfSymbol::SetTo(ElfSection* section, int32 index) 250{ 251 Unset(); 252 fSection = section; 253 fIndex = index; 254} 255 256// Unset 257void 258ElfSymbol::Unset() 259{ 260 fSection = NULL; 261 fIndex = -1; 262 fSymbol = NULL; 263} 264 265// GetSymbolStruct 266const Elf_Sym* 267ElfSymbol::GetSymbolStruct() 268{ 269 Elf_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 = (Elf_Sym*)(fSection->GetData() + fIndex * symbolSize); 277 } 278 return symbol; 279} 280 281// GetName 282const char* 283ElfSymbol::GetName() 284{ 285 const char* name = NULL; 286 if (const Elf_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 297uint32 298ElfSymbol::GetBinding() 299{ 300 uint32 binding = STB_LOCAL; 301 if (const Elf_Sym* symbol = GetSymbolStruct()) 302 binding = ELF_ST_BIND(symbol->st_info); 303 return binding; 304} 305 306// GetType 307uint32 308ElfSymbol::GetType() 309{ 310 uint32 type = STT_NOTYPE; 311 if (const Elf_Sym* symbol = GetSymbolStruct()) 312 type = ELF_ST_TYPE(symbol->st_info); 313 return type; 314} 315 316// GetTargetSectionIndex 317uint32 318ElfSymbol::GetTargetSectionIndex() 319{ 320 uint32 index = SHN_UNDEF; 321 if (const Elf_Sym* symbol = GetSymbolStruct()) 322 index = symbol->st_shndx; 323 return index; 324} 325 326 327// ElfRelocation 328 329// constructor 330ElfRelocation::ElfRelocation(ElfSection* section, int32 index) 331 : fSection(section), 332 fIndex(index), 333 fRelocation(NULL) 334{ 335} 336 337// destructor 338ElfRelocation::~ElfRelocation() 339{ 340 Unset(); 341} 342 343// SetTo 344void 345ElfRelocation::SetTo(ElfSection* section, int32 index) 346{ 347 Unset(); 348 fSection = section; 349 fIndex = index; 350} 351 352// Unset 353void 354ElfRelocation::Unset() 355{ 356 fSection = NULL; 357 fIndex = -1; 358 fRelocation = NULL; 359} 360 361// GetRelocationStruct 362Elf_Rel* 363ElfRelocation::GetRelocationStruct() 364{ 365 Elf_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(Elf_Rel)) 373 return NULL; 374 int32 entryCount = fSection->GetSize() / entrySize; 375 if (fIndex >= 0 && fIndex < entryCount) { 376 relocation = (Elf_Rel*)(fSection->GetData() 377 + fIndex * entrySize); 378 } 379 } 380 return relocation; 381} 382 383// GetType 384uint32 385ElfRelocation::GetType() 386{ 387 uint32 type = R_NONE; 388 if (Elf_Rel* relocation = GetRelocationStruct()) 389 type = ELF_R_TYPE(relocation->r_info); 390 return type; 391} 392 393// GetSymbolIndex 394uint32 395ElfRelocation::GetSymbolIndex() 396{ 397 uint32 index = 0; 398 if (Elf_Rel* relocation = GetRelocationStruct()) 399 index = ELF_R_SYM(relocation->r_info); 400 return index; 401} 402 403// GetOffset 404Elf_Addr 405ElfRelocation::GetOffset() 406{ 407 Elf_Addr offset = 0; 408 if (Elf_Rel* relocation = GetRelocationStruct()) 409 offset = relocation->r_offset; 410 return offset; 411} 412 413// GetSymbol 414status_t 415ElfRelocation::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 434ElfRelocationIterator::ElfRelocationIterator(ElfFile* file) 435 : fFile(file), 436 fSectionIndex(-1), 437 fEntryIndex(-1) 438{ 439} 440 441// destructor 442ElfRelocationIterator::~ElfRelocationIterator() 443{ 444} 445 446// GetNext 447bool 448ElfRelocationIterator::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 478ElfSection* 479ElfRelocationIterator::_FindNextSection() 480{ 481 if (fFile) { 482 for (; fSectionIndex < fFile->CountSections(); fSectionIndex++) { 483 ElfSection* section = fFile->SectionAt(fSectionIndex); 484 if (section && (section->GetType() == SHT_REL || section->GetType() == SHT_RELA)) 485 return section; 486 } 487 } 488 return NULL; 489} 490 491 492// ElfFile 493 494// constructor 495ElfFile::ElfFile() 496 : fFile(), 497 fSectionHeaders(NULL), 498 fSections(NULL), 499 fSectionCount(0), 500 fSectionHeaderSize(0) 501{ 502} 503 504// destructor 505ElfFile::~ElfFile() 506{ 507 Unset(); 508} 509 510// SetTo 511status_t 512ElfFile::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 522void 523ElfFile::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 541void 542ElfFile::Unload() 543{ 544 for (int i = 0; i < fSectionCount; i++) 545 fSections[i].Unload(); 546} 547 548// GetSectionHeaderStrings 549const char* 550ElfFile::GetSectionHeaderStrings(size_t* size) 551{ 552 return GetStringSectionStrings(fHeader.e_shstrndx, size); 553} 554 555// GetStringSectionStrings 556const char* 557ElfFile::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 572ElfSection* 573ElfFile::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 %" B_PRId32 "\n", index); 582 } 583 } 584 } 585 return section; 586} 587 588// Dump 589void 590ElfFile::Dump() 591{ 592 printf("%" B_PRId32 " sections\n", fSectionCount); 593 for (int i = 0; i < fSectionCount; i++) 594 fSections[i].Dump(); 595} 596 597// _SetTo 598status_t 599ElfFile::_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(Elf_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] != ELFCLASS) { 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(Elf_Ehdr) || headerSize > kMaxELFHeaderSize) { 649 printf("Invalid ELF header: invalid ELF header size: %" B_PRIu32 ".", headerSize); 650 return B_BAD_VALUE; 651 } 652 // section header table offset 653 if (sectionHeaderTableOffset == 0) { 654 printf("ELF file has no section header table!\n"); 655 return B_BAD_VALUE; 656 } 657 uint32 sectionHeaderTableSize = 0; 658 if (sectionHeaderTableOffset < headerSize 659 || sectionHeaderTableOffset > fileSize) { 660 printf("Invalid ELF header: invalid section header table offset: %" B_PRIu32 ".", 661 sectionHeaderTableOffset); 662 return B_BAD_VALUE; 663 } 664 // section header table offset 665 sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount; 666 if (sectionHeaderSize < sizeof(Elf_Shdr) 667 || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) { 668 printf("Invalid ELF header: section header table exceeds file: %" B_PRIu32 ".", 669 sectionHeaderTableOffset + sectionHeaderTableSize); 670 return B_BAD_VALUE; 671 } 672 // allocate memory for the section header table and read it 673 fSectionHeaders = new(std::nothrow) uint8[sectionHeaderTableSize]; 674 fSectionCount = sectionHeaderCount; 675 fSectionHeaderSize = sectionHeaderSize; 676 if (!fSectionHeaders) 677 return B_NO_MEMORY; 678 error = read_exactly(fFile, sectionHeaderTableOffset, fSectionHeaders, 679 sectionHeaderTableSize, 680 "Failed to read section headers!\n"); 681 if (error != B_OK) 682 return error; 683 // allocate memory for the section pointers 684 fSections = new(std::nothrow) ElfSection[fSectionCount]; 685 if (!fSections) 686 return B_NO_MEMORY; 687 // init the sections 688 for (int i = 0; i < fSectionCount; i++) 689 fSections[i].SetTo(this, _SectionHeaderAt(i)); 690 return error; 691} 692 693// _SectionHeaderAt 694Elf_Shdr* 695ElfFile::_SectionHeaderAt(int32 index) 696{ 697 Elf_Shdr* header = NULL; 698 if (fSectionHeaders && index >= 0 && index < fSectionCount) 699 header = (Elf_Shdr*)(fSectionHeaders + index * fSectionHeaderSize); 700 return header; 701} 702 703// _LoadSection 704status_t 705ElfFile::_LoadSection(int32 index) 706{ 707 status_t error = B_OK; 708 if (fSections && index >= 0 && index < fSectionCount) { 709 ElfSection& section = fSections[index]; 710 error = section.Load(); 711 } else 712 error = B_BAD_VALUE; 713 return error; 714} 715 716