2 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
19 #include <AutoDeleter.h>
21 #include "ElfSymbolLookup.h"
25 // #pragma mark - ElfSection
28 ElfSection::ElfSection(const char* name
, uint32 type
, int fd
, uint64 offset
,
29 uint64 size
, target_addr_t loadAddress
, uint32 flags
, uint32 linkIndex
)
37 fLoadAddress(loadAddress
),
45 ElfSection::~ElfSection()
59 fData
= malloc(fSize
);
63 ssize_t bytesRead
= pread(fFD
, fData
, fSize
, fOffset
);
64 if (bytesRead
< 0 || (uint64
)bytesRead
!= fSize
) {
67 return bytesRead
< 0 ? errno
: B_ERROR
;
81 if (--fLoadCount
== 0) {
88 // #pragma mark - ElfSegment
91 ElfSegment::ElfSegment(uint32 type
, uint64 fileOffset
, uint64 fileSize
,
92 target_addr_t loadAddress
, target_size_t loadSize
, uint32 flags
)
94 fFileOffset(fileOffset
),
96 fLoadAddress(loadAddress
),
104 ElfSegment::~ElfSegment()
109 // #pragma mark - SymbolLookupSource
112 struct ElfFile::SymbolLookupSource
: public ElfSymbolLookupSource
{
113 SymbolLookupSource(int fd
)
120 bool AddSegment(uint64 fileOffset
, uint64 fileLength
, uint64 memoryAddress
)
122 Segment
* segment
= new(std::nothrow
) Segment(fileOffset
, fileLength
,
124 if (segment
== NULL
|| !fSegments
.AddItem(segment
)) {
131 virtual ssize_t
Read(uint64 address
, void* buffer
, size_t size
)
133 for (int32 i
= 0; Segment
* segment
= fSegments
.ItemAt(i
); i
++) {
134 if (address
< segment
->fMemoryAddress
135 || address
- segment
->fMemoryAddress
136 > segment
->fFileLength
) {
140 uint64 offset
= address
- segment
->fMemoryAddress
;
141 size_t toRead
= (size_t)std::min((uint64
)size
,
142 segment
->fFileLength
- offset
);
146 ssize_t bytesRead
= pread(fFd
, buffer
, toRead
,
147 (off_t
)(segment
->fFileOffset
+ offset
));
160 uint64 fMemoryAddress
;
162 Segment(uint64 fileOffset
, uint64 fileLength
, uint64 memoryAddress
)
164 fFileOffset(fileOffset
),
165 fFileLength(fileLength
),
166 fMemoryAddress(memoryAddress
)
173 BObjectList
<Segment
> fSegments
;
177 // #pragma mark - ElfFile
187 fSwappedByteOrder(false),
202 ElfFile::Init(const char* fileName
)
205 fFD
= open(fileName
, O_RDONLY
);
207 WARNING("Failed to open \"%s\": %s\n", fileName
, strerror(errno
));
211 // stat() file to get its size
213 if (fstat(fFD
, &st
) < 0) {
214 WARNING("Failed to stat \"%s\": %s\n", fileName
, strerror(errno
));
217 fFileSize
= st
.st_size
;
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
;
227 if (!memcmp(elfIdent
, ELF_MAGIC
, 4) == 0)
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;
236 WARNING("%s: Invalid ELF data byte order: %d\n", fileName
,
241 // determine class and load
242 if(elfIdent
[EI_CLASS
] == ELFCLASS64
) {
244 return _LoadFile
<ElfClass64
>(fileName
);
246 if(elfIdent
[EI_CLASS
] == ELFCLASS32
) {
248 return _LoadFile
<ElfClass32
>(fileName
);
251 WARNING("%s: Invalid ELF class: %d\n", fileName
, elfIdent
[EI_CLASS
]);
257 ElfFile::GetSection(const char* name
)
259 ElfSection
* section
= FindSection(name
);
260 if (section
!= NULL
&& section
->Load() == B_OK
)
268 ElfFile::PutSection(ElfSection
* section
)
276 ElfFile::FindSection(const char* name
) const
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)
290 ElfFile::FindSection(uint32 type
) const
292 int32 count
= fSections
.CountItems();
293 for (int32 i
= 0; i
< count
; i
++) {
294 ElfSection
* section
= fSections
.ItemAt(i
);
295 if (section
->Type() == type
)
304 ElfFile::TextSegment() const
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())
318 ElfFile::DataSegment() const
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())
331 ElfSymbolLookupSource
*
332 ElfFile::CreateSymbolLookupSource(uint64 fileOffset
, uint64 fileLength
,
333 uint64 memoryAddress
) const
335 SymbolLookupSource
* source
= new(std::nothrow
) SymbolLookupSource(fFD
);
337 || !source
->AddSegment(fileOffset
, fileLength
, memoryAddress
)) {
346 ElfFile::CreateSymbolLookup(uint64 textDelta
, ElfSymbolLookup
*& _lookup
) const
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
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
;
360 // create a source with a segment for each section
361 SymbolLookupSource
* source
= new(std::nothrow
) SymbolLookupSource(fFD
);
364 BReference
<SymbolLookupSource
> sourceReference(source
, true);
366 if (!source
->AddSegment(symbolSection
->Offset(), symbolSection
->Size(),
367 symbolSection
->Offset())
368 || !source
->AddSegment(stringSection
->Offset(), stringSection
->Size(),
369 stringSection
->Offset())) {
374 size_t symbolTableEntrySize
= Is64Bit()
375 ? sizeof(ElfClass64::Sym
) : sizeof(ElfClass32::Sym
);
376 uint32 symbolCount
= uint32(symbolSection
->Size() / symbolTableEntrySize
);
378 return ElfSymbolLookup::Create(source
, symbolSection
->Offset(), 0,
379 stringSection
->Offset(), symbolCount
, symbolTableEntrySize
, textDelta
,
380 f64Bit
, fSwappedByteOrder
, true, _lookup
);
384 template<typename ElfClass
>
386 ElfFile::_LoadFile(const char* fileName
)
388 typedef typename
ElfClass::Ehdr Ehdr
;
389 typedef typename
ElfClass::Phdr Phdr
;
390 typedef typename
ElfClass::Shdr Shdr
;
392 // read the elf header
394 ssize_t bytesRead
= pread(fFD
, &elfHeader
, sizeof(elfHeader
), 0);
395 if (bytesRead
!= (ssize_t
)sizeof(elfHeader
))
396 return bytesRead
< 0 ? errno
: B_ERROR
;
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
);
405 fType
= Get(elfHeader
.e_type
);
406 fMachine
= Get(elfHeader
.e_machine
);
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
);
419 // read the section header table
420 uint8
* sectionHeaderTable
= (uint8
*)malloc(sectionHeaderTableSize
);
421 if (sectionHeaderTable
== NULL
)
423 MemoryDeleter
sectionHeaderTableDeleter(sectionHeaderTable
);
425 bytesRead
= pread(fFD
, sectionHeaderTable
, sectionHeaderTableSize
,
426 sectionHeadersOffset
);
427 if (bytesRead
!= (ssize_t
)sectionHeaderTableSize
)
428 return bytesRead
< 0 ? errno
: B_ERROR
;
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
);
438 size_t sectionStringSize
= Get(stringSectionHeader
->sh_size
);
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
)
448 if (!fSections
.AddItem(sectionStringSection
)) {
449 delete sectionStringSection
;
453 status_t error
= sectionStringSection
->Load();
457 const char* sectionStrings
= (const char*)sectionStringSection
->Data();
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
)) {
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
));
479 if (!fSections
.AddItem(section
, i
)) {
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
);
497 // read the program header table
498 uint8
* programHeaderTable
= (uint8
*)malloc(programHeaderTableSize
);
499 if (programHeaderTable
== NULL
)
501 MemoryDeleter
programHeaderTableDeleter(programHeaderTable
);
503 bytesRead
= pread(fFD
, programHeaderTable
, programHeaderTableSize
,
504 programHeadersOffset
);
505 if (bytesRead
!= (ssize_t
)programHeaderTableSize
)
506 return bytesRead
< 0 ? errno
: B_ERROR
;
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
))) {
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
));
526 if (!fSegments
.AddItem(segment
)) {
538 ElfFile::_FindSymbolSections(ElfSection
*& _symbolSection
,
539 ElfSection
*& _stringSection
, uint32 type
) const
541 // get the symbol table section
542 ElfSection
* symbolSection
= FindSection(type
);
543 if (symbolSection
== NULL
)
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
)
551 _symbolSection
= symbolSection
;
552 _stringSection
= stringSection
;
558 ElfFile::_CheckRange(uint64 offset
, uint64 size
) const
560 return offset
< fFileSize
&& offset
+ size
<= fFileSize
;
564 template<typename ElfClass
>
566 ElfFile::_CheckElfHeader(typename
ElfClass::Ehdr
& elfHeader
)
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
)) {
577 if (Get(elfHeader
.e_phnum
) > 0) {
578 if (Get(elfHeader
.e_phoff
) == 0
579 || Get(elfHeader
.e_phentsize
) < sizeof(typename
ElfClass::Phdr
)) {