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