xref: /haiku/src/kits/debugger/elf/ElfFile.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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 
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 
45 ElfSection::~ElfSection()
46 {
47 	free(fData);
48 }
49 
50 
51 status_t
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
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 
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 
104 ElfSegment::~ElfSegment()
105 {
106 }
107 
108 
109 // #pragma mark - SymbolLookupSource
110 
111 
112 struct ElfFile::SymbolLookupSource : public ElfSymbolLookupSource {
113 	SymbolLookupSource(int fd)
114 		:
115 		fFd(fd),
116 		fSegments(8, true)
117 	{
118 	}
119 
120 	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 
131 	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 
162 		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 
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 
194 ElfFile::~ElfFile()
195 {
196 	if (fFD >= 0)
197 		close(fFD);
198 }
199 
200 
201 status_t
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*
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
268 ElfFile::PutSection(ElfSection* section)
269 {
270 	if (section != NULL)
271 		section->Unload();
272 }
273 
274 
275 ElfSection*
276 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*
290 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*
304 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*
318 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*
332 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
347 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
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
539 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
559 ElfFile::_CheckRange(uint64 offset, uint64 size) const
560 {
561 	return offset < fFileSize && offset + size <= fFileSize;
562 }
563 
564 
565 template<typename ElfClass>
566 bool
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