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