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