⛏️ index : haiku.git

/*
 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef ELF_FILE_H
#define ELF_FILE_H

#include <sys/types.h>

#include <ByteOrder.h>
#include <SupportDefs.h>
#include <ObjectList.h>

#include <elf_private.h>
#include <util/DoublyLinkedList.h>

#include "Types.h"


class ElfSymbolLookup;
class ElfSymbolLookupSource;


class ElfSection {
public:
								ElfSection(const char* name, uint32 type,
									int fd, uint64 offset, uint64 size,
									target_addr_t loadAddress, uint32 flags,
									uint32 linkIndex);
								~ElfSection();

			const char*			Name() const	{ return fName; }
			uint32				Type() const	{ return fType; }
			uint64				Offset() const	{ return fOffset; }
			uint64				Size() const	{ return fSize; }
			const void*			Data() const	{ return fData; }
			target_addr_t		LoadAddress() const
									{ return fLoadAddress; }
			bool				IsWritable() const
									{ return (fFlags & SHF_WRITE) != 0; }

			status_t			Load();
			void				Unload();
			bool				IsLoaded() const	{ return fLoadCount > 0; }
			uint32				LinkIndex() const	{ return fLinkIndex; }

private:
			const char*			fName;
			uint32				fType;
			int					fFD;
			uint64				fOffset;
			uint64				fSize;
			void*				fData;
			target_addr_t		fLoadAddress;
			uint32				fFlags;
			int32				fLoadCount;
			uint32				fLinkIndex;
};


class ElfSegment {
public:
								ElfSegment(uint32 type, uint64 fileOffset,
									uint64 fileSize, target_addr_t loadAddress,
									target_size_t loadSize, uint32 flags);
								~ElfSegment();

			uint32				Type()				{ return fType; }
			uint64				FileOffset() const	{ return fFileOffset; }
			uint64				FileSize() const	{ return fFileSize; }
			target_addr_t		LoadAddress() const	{ return fLoadAddress; }
			target_size_t		LoadSize() const	{ return fLoadSize; }
			uint32				Flags() const		{ return fFlags; }
			bool				IsWritable() const
									{ return (fFlags & PF_WRITE) != 0; }

private:
			uint64				fFileOffset;
			uint64				fFileSize;
			target_addr_t		fLoadAddress;
			target_size_t		fLoadSize;
			uint32				fType;
			uint32				fFlags;
};


struct ElfClass32 {
	typedef uint32					Address;
	typedef uint32					Size;
	typedef Elf32_Ehdr				Ehdr;
	typedef Elf32_Phdr				Phdr;
	typedef Elf32_Shdr				Shdr;
	typedef Elf32_Sym				Sym;
	typedef Elf32_Nhdr				Nhdr;
	typedef Elf32_Note_Team			NoteTeam;
	typedef Elf32_Note_Area_Entry	NoteAreaEntry;
	typedef Elf32_Note_Image_Entry	NoteImageEntry;
	typedef Elf32_Note_Thread_Entry	NoteThreadEntry;
};


struct ElfClass64 {
	typedef uint64					Address;
	typedef uint64					Size;
	typedef Elf64_Ehdr				Ehdr;
	typedef Elf64_Phdr				Phdr;
	typedef Elf64_Shdr				Shdr;
	typedef Elf64_Sym				Sym;
	typedef Elf64_Nhdr				Nhdr;
	typedef Elf64_Note_Team			NoteTeam;
	typedef Elf64_Note_Area_Entry	NoteAreaEntry;
	typedef Elf64_Note_Image_Entry	NoteImageEntry;
	typedef Elf64_Note_Thread_Entry	NoteThreadEntry;
};


class ElfFile {
public:
								ElfFile();
								~ElfFile();

			status_t			Init(const char* fileName);

			int					FD() const	{ return fFD; }

			bool				Is64Bit() const	{ return f64Bit; }
			bool				IsByteOrderSwapped() const
									{ return fSwappedByteOrder; }
			uint16				Type() const	{ return fType; }
			uint16				Machine() const	{ return fMachine; }

			int32				CountSection() const
									{ return fSections.CountItems(); }
			ElfSection*			SectionAt(int32 index) const
									{ return fSections.ItemAt(index); }
			ElfSection*			GetSection(const char* name);
			void				PutSection(ElfSection* section);
			ElfSection*			FindSection(const char* name) const;
			ElfSection*			FindSection(uint32 type) const;

			int32				CountSegments() const
									{ return fSegments.CountItems(); }
			ElfSegment*			SegmentAt(int32 index) const
									{ return fSegments.ItemAt(index); }

			ElfSegment*			TextSegment() const;
			ElfSegment*			DataSegment() const;

			ElfSymbolLookupSource* CreateSymbolLookupSource(uint64 fileOffset,
									uint64 fileLength,
									uint64 memoryAddress) const;
			status_t			CreateSymbolLookup(uint64 textDelta,
									ElfSymbolLookup*& _lookup) const;

			template<typename Value>
			Value				Get(const Value& value) const
									{ return StaticGet(value,
										fSwappedByteOrder); }

	template<typename Value>
	static	Value				StaticGet(const Value& value,
									bool swappedByteOrder);

private:
			struct SymbolLookupSource;

			typedef BObjectList<ElfSection, true> SectionList;
			typedef BObjectList<ElfSegment, true> SegmentList;

private:
			template<typename ElfClass>
			status_t			_LoadFile(const char* fileName);

			bool				_FindSymbolSections(ElfSection*& _symbolSection,
									ElfSection*& _stringSection,
									uint32 type) const;

			bool				_CheckRange(uint64 offset, uint64 size) const;

			template<typename ElfClass>
			bool				_CheckElfHeader(
									typename ElfClass::Ehdr& elfHeader);

	static	uint8				_Swap(const uint8& value)
									{ return value; }
	static	uint16				_Swap(const uint16& value)
									{ return (uint16)B_SWAP_INT16(value); }
	static	int32				_Swap(const int32& value)
									{ return B_SWAP_INT32(value); }
	static	uint32				_Swap(const uint32& value)
									{ return (uint32)B_SWAP_INT32(value); }
	static	int64				_Swap(const int64& value)
									{ return B_SWAP_INT64(value); }
	static	uint64				_Swap(const uint64& value)
									{ return (uint64)B_SWAP_INT64(value); }

private:
			uint64				fFileSize;
			int					fFD;
			uint16				fType;
			uint16				fMachine;
			bool				f64Bit;
			bool				fSwappedByteOrder;
			SectionList			fSections;
			SegmentList			fSegments;
};


template<typename Value>
/*static*/ inline Value
ElfFile::StaticGet(const Value& value, bool swappedByteOrder)
{
	if (!swappedByteOrder)
		return value;
	return _Swap(value);
}


#endif	// ELF_FILE_H