2 //------------------------------------------------------------------------------
3 // Copyright (c) 2003, Ingo Weinhold
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:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
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.
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
28 //------------------------------------------------------------------------------
38 static const uint32 kMaxELFHeaderSize
= sizeof(Elf32_Ehdr
) + 32;
43 read_exactly(BPositionIO
&file
, off_t position
, void *buffer
, size_t size
,
44 const char *errorMessage
= NULL
)
46 status_t error
= B_OK
;
47 ssize_t read
= file
.ReadAt(position
, buffer
, size
);
50 else if ((size_t)read
!= size
)
52 if (error
!= B_OK
&& errorMessage
)
60 class SymbolPatcher::ElfSection
{
65 void SetTo(ElfFile
* file
, Elf32_Shdr
* header
);
67 bool IsInitialized() const { return fHeader
; }
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;
92 ElfSection::ElfSection()
100 ElfSection::~ElfSection()
107 ElfSection::SetTo(ElfFile
* file
, Elf32_Shdr
* header
)
125 ElfSection::GetFile() const
132 ElfSection::GetName() const
134 const char* name
= NULL
;
135 if (fHeader
&& fFile
) {
137 const char* nameSection
= fFile
->GetSectionHeaderStrings(&size
);
138 if (nameSection
&& fHeader
->sh_name
< size
)
139 name
= nameSection
+ fHeader
->sh_name
;
146 ElfSection::GetSize() const
148 return fHeader
->sh_size
;
153 ElfSection::GetType() const
155 return fHeader
->sh_type
;
160 ElfSection::GetLink() const
162 return fHeader
->sh_link
;
167 ElfSection::GetInfo() const
169 return fHeader
->sh_info
;
174 ElfSection::GetEntrySize() const
176 return fHeader
->sh_entsize
;
181 ElfSection::CountEntries() const
185 if (GetEntrySize() == 0)
187 count
= GetSize() / GetEntrySize();
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();
201 fData
= new uint8
[fHeader
->sh_size
];
205 error
= read_exactly(*file
, fHeader
->sh_offset
, fData
,
206 fHeader
->sh_size
, "Failed to read section!\n");
227 printf("section %32s: size: %lu\n", GetName(), GetSize());
234 ElfSymbol::ElfSymbol(ElfSection
* section
, int32 index
)
242 ElfSymbol::~ElfSymbol()
249 ElfSymbol::SetTo(ElfSection
* section
, int32 index
)
267 ElfSymbol::GetSymbolStruct()
269 Elf32_Sym
* symbol
= fSymbol
;
270 if (!symbol
&& fSection
&& fSection
->GetData()) {
271 size_t symbolSize
= fSection
->GetEntrySize();
274 int32 symbolCount
= fSection
->GetSize() / symbolSize
;
275 if (fIndex
>= 0 && fIndex
< symbolCount
)
276 symbol
= (Elf32_Sym
*)(fSection
->GetData() + fIndex
* symbolSize
);
285 const char* name
= NULL
;
286 if (const Elf32_Sym
* symbol
= GetSymbolStruct()) {
288 const char* data
= fSection
->GetFile()->GetStringSectionStrings(
289 fSection
->GetLink(), &size
);
290 if (data
&& symbol
->st_name
< size
)
291 name
= data
+ symbol
->st_name
;
298 ElfSymbol::GetBinding()
300 uint32 binding
= STB_LOCAL
;
301 if (const Elf32_Sym
* symbol
= GetSymbolStruct())
302 binding
= ELF32_ST_BIND(symbol
->st_info
);
310 uint32 type
= STT_NOTYPE
;
311 if (const Elf32_Sym
* symbol
= GetSymbolStruct())
312 type
= ELF32_ST_TYPE(symbol
->st_info
);
316 // GetTargetSectionIndex
318 ElfSymbol::GetTargetSectionIndex()
320 uint32 index
= SHN_UNDEF
;
321 if (const Elf32_Sym
* symbol
= GetSymbolStruct())
322 index
= symbol
->st_shndx
;
330 ElfRelocation::ElfRelocation(ElfSection
* section
, int32 index
)
338 ElfRelocation::~ElfRelocation()
345 ElfRelocation::SetTo(ElfSection
* section
, int32 index
)
354 ElfRelocation::Unset()
361 // GetRelocationStruct
363 ElfRelocation::GetRelocationStruct()
365 Elf32_Rel
* relocation
= fRelocation
;
366 if (!relocation
&& fSection
) {
367 if (!fSection
->GetData()) {
368 if (fSection
->Load() != B_OK
)
371 size_t entrySize
= fSection
->GetEntrySize();
372 if (entrySize
== 0 || entrySize
< sizeof(Elf32_Rel
))
374 int32 entryCount
= fSection
->GetSize() / entrySize
;
375 if (fIndex
>= 0 && fIndex
< entryCount
) {
376 relocation
= (Elf32_Rel
*)(fSection
->GetData()
377 + fIndex
* entrySize
);
385 ElfRelocation::GetType()
387 uint32 type
= R_386_NONE
;
388 if (Elf32_Rel
* relocation
= GetRelocationStruct())
389 type
= ELF32_R_TYPE(relocation
->r_info
);
395 ElfRelocation::GetSymbolIndex()
398 if (Elf32_Rel
* relocation
= GetRelocationStruct())
399 index
= ELF32_R_SYM(relocation
->r_info
);
405 ElfRelocation::GetOffset()
407 Elf32_Addr offset
= 0;
408 if (Elf32_Rel
* relocation
= GetRelocationStruct())
409 offset
= relocation
->r_offset
;
415 ElfRelocation::GetSymbol(ElfSymbol
* symbol
)
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())
431 // ElfRelocationIterator
434 ElfRelocationIterator::ElfRelocationIterator(ElfFile
* file
)
442 ElfRelocationIterator::~ElfRelocationIterator()
448 ElfRelocationIterator::GetNext(ElfRelocation
* relocation
)
451 if (fFile
&& relocation
) {
452 // set to possible entry
453 ElfSection
* section
= NULL
;
454 if (fSectionIndex
< 0) {
457 section
= _FindNextSection();
460 section
= fFile
->SectionAt(fSectionIndex
);
462 // find next valid entry
463 while (section
&& fEntryIndex
>= section
->CountEntries()) {
465 section
= _FindNextSection();
470 relocation
->SetTo(section
, fEntryIndex
);
479 ElfRelocationIterator::_FindNextSection()
482 for (; fSectionIndex
< fFile
->CountSections(); fSectionIndex
++) {
483 ElfSection
* section
= fFile
->SectionAt(fSectionIndex
);
484 if (section
&& section
->GetType() == SHT_REL
)
497 fSectionHeaders(NULL
),
500 fSectionHeaderSize(0)
512 ElfFile::SetTo(const char *filename
)
515 status_t error
= _SetTo(filename
);
530 // delete section headers
531 if (fSectionHeaders
) {
532 delete[] fSectionHeaders
;
533 fSectionHeaders
= NULL
;
536 fSectionHeaderSize
= 0;
544 for (int i
= 0; i
< fSectionCount
; i
++)
545 fSections
[i
].Unload();
548 // GetSectionHeaderStrings
550 ElfFile::GetSectionHeaderStrings(size_t* size
)
552 return GetStringSectionStrings(fHeader
.e_shstrndx
, size
);
555 // GetStringSectionStrings
557 ElfFile::GetStringSectionStrings(int32 index
, size_t* _size
)
559 const char* data
= NULL
;
561 if (ElfSection
* section
= SectionAt(index
, true)) {
562 data
= (const char*)section
->GetData();
563 size
= (data
? section
->GetSize() : 0);
573 ElfFile::SectionAt(int32 index
, bool load
)
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
) {
581 printf("Failed to load section %ld\n", index
);
592 printf("%ld sections\n", fSectionCount
);
593 for (int i
= 0; i
< fSectionCount
; i
++)
599 ElfFile::_SetTo(const char *filename
)
604 status_t error
= fFile
.SetTo(filename
, B_READ_ONLY
);
607 error
= fFile
.GetSize(&fileSize
);
609 printf("Failed to get file size!\n");
613 error
= read_exactly(fFile
, 0, &fHeader
, sizeof(Elf32_Ehdr
),
614 "Failed to read ELF object header!\n");
617 // check the ident field
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");
627 if (fHeader
.e_ident
[EI_CLASS
] != ELFCLASS32
) {
628 printf("Wrong ELF class!\n");
631 // check data encoding (endianess)
632 if (fHeader
.e_ident
[EI_DATA
] != ELFDATA2LSB
) {
633 printf("Wrong data encoding!\n");
637 if (fHeader
.e_ident
[EI_VERSION
] != EV_CURRENT
) {
638 printf("Wrong data encoding!\n");
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
648 if (headerSize
< sizeof(Elf32_Ehdr
) || headerSize
> kMaxELFHeaderSize
) {
649 printf("Invalid ELF header: invalid ELF header size: %lu.",
653 // section header table offset
654 if (sectionHeaderTableOffset
== 0) {
655 printf("ELF file has no section header table!\n");
658 uint32 sectionHeaderTableSize
= 0;
659 if (sectionHeaderTableOffset
< headerSize
660 || sectionHeaderTableOffset
> fileSize
) {
661 printf("Invalid ELF header: invalid section header table offset: %lu.",
662 sectionHeaderTableOffset
);
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
);
673 // allocate memory for the section header table and read it
674 fSectionHeaders
= new(std::nothrow
) uint8
[sectionHeaderTableSize
];
675 fSectionCount
= sectionHeaderCount
;
676 fSectionHeaderSize
= sectionHeaderSize
;
677 if (!fSectionHeaders
)
679 error
= read_exactly(fFile
, sectionHeaderTableOffset
, fSectionHeaders
,
680 sectionHeaderTableSize
,
681 "Failed to read section headers!\n");
684 // allocate memory for the section pointers
685 fSections
= new(std::nothrow
) ElfSection
[fSectionCount
];
689 for (int i
= 0; i
< fSectionCount
; i
++)
690 fSections
[i
].SetTo(this, _SectionHeaderAt(i
));
696 ElfFile::_SectionHeaderAt(int32 index
)
698 Elf32_Shdr
* header
= NULL
;
699 if (fSectionHeaders
&& index
>= 0 && index
< fSectionCount
)
700 header
= (Elf32_Shdr
*)(fSectionHeaders
+ index
* fSectionHeaderSize
);
706 ElfFile::_LoadSection(int32 index
)
708 status_t error
= B_OK
;
709 if (fSections
&& index
>= 0 && index
< fSectionCount
) {
710 ElfSection
& section
= fSections
[index
];
711 error
= section
.Load();