summaryrefslogtreecommitdiffstats
path: root/common/StELFFile.h
blob: 3ab989956c37ec502b35686653c5020c98324c49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*
 * File:	StELFFile.h
 *
 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
 * See included license file for license details.
 */
#if !defined(_StELFFile_h_)
#define _StELFFile_h_

#include "stdafx.h"
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <stdexcept>
#include "ELF.h"

//! Variations of the ARM ELF format.
typedef enum {
	eARMVariant = 1,	//!< Standard ARM ELF specification.
	eGHSVariant,		//!< Green Hills Software variant.
	eGCCVariant		//!< GNU Compiler Collection variant.
} ELFVariant_t;

//! Possible ARM ELF symbol types.
typedef enum {
	eUnknownSymbol,
	eARMSymbol,
	eThumbSymbol,
	eDataSymbol
} ARMSymbolType_t;

/*!
 * \brief Parser for Executable and Linking Format (ELF) files.
 *
 * The stream passed into the constructor needs to stay open for the life
 * of the object. This is because calls to getSectionDataAtIndex() and
 * getSegmentDataAtIndex() read the data directly from the input stream.
 */
class StELFFile
{
public:
	typedef std::vector<Elf32_Shdr>::const_iterator const_section_iterator;
	typedef std::vector<Elf32_Phdr>::const_iterator const_segment_iterator;
	
public:
	//! \brief Constructor.
	StELFFile(std::istream & inStream);
	
	//! \brief Destructor.
	virtual ~StELFFile();
	
	//! \name File format variant
	//@{
	//! \brief Return the ELF format variant to which this file is set.
	virtual ELFVariant_t ELFVariant() { return m_elfVariant; }
	
	//! \brief Set the ELF format variation to either #eARMVariant or #eGHSVariant.
	virtual void setELFVariant(ELFVariant_t variant) { m_elfVariant = variant; }
	//@}
	
	//! \name File name
	//@{
	virtual void setName(const std::string & inName) { m_name = inName; }
	virtual std::string getName() const { return m_name; }
	//@}
	
	//! \name ELF header
	//@{
	//! \brief Returns the ELF file header.
	inline const Elf32_Ehdr & getFileHeader() const { return m_header; }
	//@}
	
	//! \name Sections
	//! Methods pertaining to the object file's sections.
	//@{
	//! \brief Returns the number of sections in the file.
	inline unsigned getSectionCount() const { return static_cast<unsigned>(m_sectionHeaders.size()); }
	
	//! \brief Returns a reference to section number \a inIndex.
	const Elf32_Shdr & getSectionAtIndex(unsigned inIndex) const;
	
	inline const_section_iterator getSectionBegin() const { return m_sectionHeaders.begin(); }
	inline const_section_iterator getSectionEnd() const { return m_sectionHeaders.end(); }
	
	//! \brief Returns the index of the section with the name \a inName.
	unsigned getIndexOfSectionWithName(const std::string & inName);
	
	//! \brief Returns the data for the section.
	uint8_t * getSectionDataAtIndex(unsigned inIndex);
	
	//! \brief Returns the data for the section.
	uint8_t * getSectionData(const_section_iterator inSection);
	//@}
	
	//! \name Segments
	//! Methods for accessing the file's program headers for segments.
	//@{
	//! \brief Returns the number of segments, or program headers, in the file.
	inline unsigned getSegmentCount() const { return static_cast<unsigned>(m_programHeaders.size()); }
	
	//! \brief Returns a reference to the given segment.
	const Elf32_Phdr & getSegmentAtIndex(unsigned inIndex) const;

	inline const_segment_iterator getSegmentBegin() const { return m_programHeaders.begin(); }
	inline const_segment_iterator getSegmentEnd() const { return m_programHeaders.end(); }
	
	//! \brief Returns the data of the specified segment.
	uint8_t * getSegmentDataAtIndex(unsigned inIndex);
	
	//! \brief Returns the data of the specified segment.
	uint8_t * getSegmentData(const_segment_iterator inSegment);
	//@}
	
	//! \name String table
	//! Methods for accessing the string tables.
	//@{
	//! \brief Returns a string from the file's section name string table.
	std::string getSectionNameAtIndex(unsigned inIndex);
	
	//! \brief Returns a string from any string table in the object file.
	std::string getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex);
	//@}
	
	//! \name Symbol table
	//! Methods for accessing the object file's symbol table. Currently only
	//! a single symbol table with the section name ".symtab" is supported.
	//@{
	//! \brief Returns the number of symbols in the default ".symtab" symbol table.
	unsigned getSymbolCount();
	
	//! \brief Returns the symbol with index \a inIndex.
	const Elf32_Sym & getSymbolAtIndex(unsigned inIndex);
	
	//! \brief Returns the section index of the string table containing symbol names.
	unsigned getSymbolNameStringTableIndex() const;
	
	//! \brief Returns the name of the symbol described by \a inSymbol.
	std::string getSymbolName(const Elf32_Sym & inSymbol);
	
	unsigned getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict=true);
	
	ARMSymbolType_t getTypeOfSymbolAtIndex(unsigned symbolIndex);
	//@}
	
	//! \name Debugging
	//@{
	void dumpSections();
	void dumpSymbolTable();
	//@}

protected:
	std::istream & m_stream;	//!< The source stream for the ELF file.
	ELFVariant_t m_elfVariant;	//!< Variant of the ARM ELF format specification.
	std::string m_name;			//!< File name. (optional)
	Elf32_Ehdr m_header;	//!< The ELF file header.
	std::vector<Elf32_Shdr> m_sectionHeaders;	//!< All of the section headers.
	std::vector<Elf32_Phdr> m_programHeaders;	//!< All of the program headers.
	unsigned m_symbolTableIndex;	//!< Index of ".symtab" section, or #SHN_UNDEF if not present.
	
	/*!
	 * Little structure containing information about cached section data.
	 */
	struct SectionDataInfo
	{
		uint8_t * m_data;	//!< Pointer to section data.
		unsigned m_size;	//!< Section data size in bytes.
		bool m_swapped;	//!< Has this section been byte swapped yet? Used for symbol table.
	};
	typedef std::map<unsigned, SectionDataInfo> SectionDataMap;
	SectionDataMap m_sectionDataCache;	//!< Cached data of sections.
	
	//! \brief Reads a section's data either from cache or from disk.
	SectionDataInfo & getCachedSectionData(unsigned inSectionIndex);
	
	//! \brief Reads the file, section, and program headers into memory.
	void readFileHeaders();
	
	uint8_t * readSectionData(const Elf32_Shdr & inHeader);
	uint8_t * readSegmentData(const Elf32_Phdr & inHeader);
	
	//! \brief Byte swaps the symbol table data into host endianness.
	void byteSwapSymbolTable(const Elf32_Shdr & header, SectionDataInfo & info);
};

/*!
 * \brief Simple exception thrown to indicate an error in the input ELF file format.
 */
class StELFFileException : public std::runtime_error
{
public:
	//! \brief Default constructor.
	StELFFileException(const std::string & inMessage) : std::runtime_error(inMessage) {}
};

#endif // _StELFFile_h_