xref: /netbsd-src/external/bsd/elftosb/dist/common/StELFFile.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
1*993229b6Sjkunz /*
2*993229b6Sjkunz  * File:	StELFFile.cpp
3*993229b6Sjkunz  *
4*993229b6Sjkunz  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5*993229b6Sjkunz  * See included license file for license details.
6*993229b6Sjkunz  */
7*993229b6Sjkunz 
8*993229b6Sjkunz #include "StELFFile.h"
9*993229b6Sjkunz #include <ios>
10*993229b6Sjkunz #include <stdexcept>
11*993229b6Sjkunz #include <stdio.h>
12*993229b6Sjkunz #include "EndianUtilities.h"
13*993229b6Sjkunz 
14*993229b6Sjkunz //! \exception StELFFileException is thrown if there is a problem with the file format.
15*993229b6Sjkunz //!
StELFFile(std::istream & inStream)16*993229b6Sjkunz StELFFile::StELFFile(std::istream & inStream)
17*993229b6Sjkunz :	m_stream(inStream)
18*993229b6Sjkunz {
19*993229b6Sjkunz 	readFileHeaders();
20*993229b6Sjkunz }
21*993229b6Sjkunz 
22*993229b6Sjkunz //! Disposes of the string table data.
~StELFFile()23*993229b6Sjkunz StELFFile::~StELFFile()
24*993229b6Sjkunz {
25*993229b6Sjkunz 	SectionDataMap::iterator it = m_sectionDataCache.begin();
26*993229b6Sjkunz 	for (; it != m_sectionDataCache.end(); ++it)
27*993229b6Sjkunz 	{
28*993229b6Sjkunz 		SectionDataInfo & info = it->second;
29*993229b6Sjkunz 		if (info.m_data != NULL)
30*993229b6Sjkunz 		{
31*993229b6Sjkunz 			delete [] info.m_data;
32*993229b6Sjkunz 		}
33*993229b6Sjkunz 	}
34*993229b6Sjkunz }
35*993229b6Sjkunz 
36*993229b6Sjkunz //! \exception StELFFileException is thrown if the file is not an ELF file.
37*993229b6Sjkunz //!
readFileHeaders()38*993229b6Sjkunz void StELFFile::readFileHeaders()
39*993229b6Sjkunz {
40*993229b6Sjkunz 	// move read head to beginning of stream
41*993229b6Sjkunz 	m_stream.seekg(0, std::ios_base::beg);
42*993229b6Sjkunz 
43*993229b6Sjkunz 	// read ELF header
44*993229b6Sjkunz 	m_stream.read(reinterpret_cast<char *>(&m_header), sizeof(m_header));
45*993229b6Sjkunz 	if (m_stream.bad())
46*993229b6Sjkunz 	{
47*993229b6Sjkunz 		throw StELFFileException("could not read file header");
48*993229b6Sjkunz 	}
49*993229b6Sjkunz 
50*993229b6Sjkunz 	// convert endianness
51*993229b6Sjkunz 	m_header.e_type = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_type);
52*993229b6Sjkunz 	m_header.e_machine = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_machine);
53*993229b6Sjkunz 	m_header.e_version = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_version);
54*993229b6Sjkunz 	m_header.e_entry = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_entry);
55*993229b6Sjkunz 	m_header.e_phoff = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_phoff);
56*993229b6Sjkunz 	m_header.e_shoff = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_shoff);
57*993229b6Sjkunz 	m_header.e_flags = ENDIAN_LITTLE_TO_HOST_U32(m_header.e_flags);
58*993229b6Sjkunz 	m_header.e_ehsize = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_ehsize);
59*993229b6Sjkunz 	m_header.e_phentsize = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_phentsize);
60*993229b6Sjkunz 	m_header.e_phnum = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_phnum);
61*993229b6Sjkunz 	m_header.e_shentsize = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_shentsize);
62*993229b6Sjkunz 	m_header.e_shnum = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_shnum);
63*993229b6Sjkunz 	m_header.e_shstrndx = ENDIAN_LITTLE_TO_HOST_U16(m_header.e_shstrndx);
64*993229b6Sjkunz 
65*993229b6Sjkunz 	// check magic number
66*993229b6Sjkunz 	if (!(m_header.e_ident[EI_MAG0] == ELFMAG0 && m_header.e_ident[EI_MAG1] == ELFMAG1 && m_header.e_ident[EI_MAG2] == ELFMAG2 && m_header.e_ident[EI_MAG3] == ELFMAG3))
67*993229b6Sjkunz 	{
68*993229b6Sjkunz 		throw StELFFileException("invalid magic number in ELF header");
69*993229b6Sjkunz 	}
70*993229b6Sjkunz 
71*993229b6Sjkunz 	try
72*993229b6Sjkunz 	{
73*993229b6Sjkunz 		int i;
74*993229b6Sjkunz 
75*993229b6Sjkunz 		// read section headers
76*993229b6Sjkunz 		if (m_header.e_shoff != 0 && m_header.e_shnum > 0)
77*993229b6Sjkunz 		{
78*993229b6Sjkunz 			Elf32_Shdr sectionHeader;
79*993229b6Sjkunz 			for (i=0; i < m_header.e_shnum; ++i)
80*993229b6Sjkunz 			{
81*993229b6Sjkunz 				m_stream.seekg(m_header.e_shoff + m_header.e_shentsize * i, std::ios::beg);
82*993229b6Sjkunz 				m_stream.read(reinterpret_cast<char *>(&sectionHeader), sizeof(sectionHeader));
83*993229b6Sjkunz 				if (m_stream.bad())
84*993229b6Sjkunz 				{
85*993229b6Sjkunz 					throw StELFFileException("could not read section header");
86*993229b6Sjkunz 				}
87*993229b6Sjkunz 
88*993229b6Sjkunz 				// convert endianness
89*993229b6Sjkunz 				sectionHeader.sh_name = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_name);
90*993229b6Sjkunz 				sectionHeader.sh_type = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_type);
91*993229b6Sjkunz 				sectionHeader.sh_flags = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_flags);
92*993229b6Sjkunz 				sectionHeader.sh_addr = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_addr);
93*993229b6Sjkunz 				sectionHeader.sh_offset = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_offset);
94*993229b6Sjkunz 				sectionHeader.sh_size = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_size);
95*993229b6Sjkunz 				sectionHeader.sh_link = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_link);
96*993229b6Sjkunz 				sectionHeader.sh_info = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_info);
97*993229b6Sjkunz 				sectionHeader.sh_addralign = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_addralign);
98*993229b6Sjkunz 				sectionHeader.sh_entsize = ENDIAN_LITTLE_TO_HOST_U32(sectionHeader.sh_entsize);
99*993229b6Sjkunz 
100*993229b6Sjkunz 				m_sectionHeaders.push_back(sectionHeader);
101*993229b6Sjkunz 			}
102*993229b6Sjkunz 		}
103*993229b6Sjkunz 
104*993229b6Sjkunz 		// read program headers
105*993229b6Sjkunz 		if (m_header.e_phoff != 0 && m_header.e_phnum > 0)
106*993229b6Sjkunz 		{
107*993229b6Sjkunz 			Elf32_Phdr programHeader;
108*993229b6Sjkunz 			for (i=0; i < m_header.e_phnum; ++i)
109*993229b6Sjkunz 			{
110*993229b6Sjkunz 				m_stream.seekg(m_header.e_phoff + m_header.e_phentsize * i, std::ios::beg);
111*993229b6Sjkunz 				m_stream.read(reinterpret_cast<char *>(&programHeader), sizeof(programHeader));
112*993229b6Sjkunz 				if (m_stream.bad())
113*993229b6Sjkunz 				{
114*993229b6Sjkunz 					throw StELFFileException("could not read program header");
115*993229b6Sjkunz 				}
116*993229b6Sjkunz 
117*993229b6Sjkunz 				// convert endianness
118*993229b6Sjkunz 				programHeader.p_type = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_type);
119*993229b6Sjkunz 				programHeader.p_offset = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_type);
120*993229b6Sjkunz 				programHeader.p_vaddr = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_vaddr);
121*993229b6Sjkunz 				programHeader.p_paddr = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_paddr);
122*993229b6Sjkunz 				programHeader.p_filesz = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_filesz);
123*993229b6Sjkunz 				programHeader.p_memsz = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_memsz);
124*993229b6Sjkunz 				programHeader.p_flags = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_flags);
125*993229b6Sjkunz 				programHeader.p_align = ENDIAN_LITTLE_TO_HOST_U32(programHeader.p_align);
126*993229b6Sjkunz 
127*993229b6Sjkunz 				m_programHeaders.push_back(programHeader);
128*993229b6Sjkunz 			}
129*993229b6Sjkunz 		}
130*993229b6Sjkunz 
131*993229b6Sjkunz 		// look up symbol table section index
132*993229b6Sjkunz 		{
133*993229b6Sjkunz 		    std::string symtab_section_name(SYMTAB_SECTION_NAME);
134*993229b6Sjkunz 		    m_symbolTableIndex = getIndexOfSectionWithName(symtab_section_name);
135*993229b6Sjkunz 		}
136*993229b6Sjkunz 	}
137*993229b6Sjkunz 	catch (...)
138*993229b6Sjkunz 	{
139*993229b6Sjkunz 		throw StELFFileException("error reading file");
140*993229b6Sjkunz 	}
141*993229b6Sjkunz }
142*993229b6Sjkunz 
getSectionAtIndex(unsigned inIndex) const143*993229b6Sjkunz const Elf32_Shdr & StELFFile::getSectionAtIndex(unsigned inIndex) const
144*993229b6Sjkunz {
145*993229b6Sjkunz 	if (inIndex > m_sectionHeaders.size())
146*993229b6Sjkunz 		throw std::invalid_argument("inIndex");
147*993229b6Sjkunz 
148*993229b6Sjkunz 	return m_sectionHeaders[inIndex];
149*993229b6Sjkunz }
150*993229b6Sjkunz 
151*993229b6Sjkunz //! If there is not a matching section, then #SHN_UNDEF is returned instead.
152*993229b6Sjkunz //!
getIndexOfSectionWithName(const std::string & inName)153*993229b6Sjkunz unsigned StELFFile::getIndexOfSectionWithName(const std::string & inName)
154*993229b6Sjkunz {
155*993229b6Sjkunz 	unsigned sectionIndex = 0;
156*993229b6Sjkunz 	const_section_iterator it = getSectionBegin();
157*993229b6Sjkunz 	for (; it != getSectionEnd(); ++it, ++sectionIndex)
158*993229b6Sjkunz 	{
159*993229b6Sjkunz 		const Elf32_Shdr & header = *it;
160*993229b6Sjkunz 		if (header.sh_name != 0)
161*993229b6Sjkunz 		{
162*993229b6Sjkunz 			std::string sectionName = getSectionNameAtIndex(header.sh_name);
163*993229b6Sjkunz 			if (inName == sectionName)
164*993229b6Sjkunz 				return sectionIndex;
165*993229b6Sjkunz 		}
166*993229b6Sjkunz 	}
167*993229b6Sjkunz 
168*993229b6Sjkunz 	// no matching section
169*993229b6Sjkunz 	return SHN_UNDEF;
170*993229b6Sjkunz }
171*993229b6Sjkunz 
172*993229b6Sjkunz //! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
173*993229b6Sjkunz //! If either the section data offset (sh_offset) or the section size (sh_size) are 0, then NULL will
174*993229b6Sjkunz //! be returned instead.
175*993229b6Sjkunz //!
176*993229b6Sjkunz //! The data is read directly from the input stream passed into the constructor. The stream must
177*993229b6Sjkunz //! still be open, or an exception will be thrown.
178*993229b6Sjkunz //!
179*993229b6Sjkunz //! \exception StELFFileException is thrown if an error occurs while reading the file.
180*993229b6Sjkunz //! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
getSectionDataAtIndex(unsigned inIndex)181*993229b6Sjkunz uint8_t * StELFFile::getSectionDataAtIndex(unsigned inIndex)
182*993229b6Sjkunz {
183*993229b6Sjkunz 	return readSectionData(m_sectionHeaders[inIndex]);
184*993229b6Sjkunz }
185*993229b6Sjkunz 
186*993229b6Sjkunz //! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
187*993229b6Sjkunz //! If either the section data offset (sh_offset) or the section size (sh_size) are 0, then NULL will
188*993229b6Sjkunz //! be returned instead.
189*993229b6Sjkunz //!
190*993229b6Sjkunz //! The data is read directly from the input stream passed into the constructor. The stream must
191*993229b6Sjkunz //! still be open, or an exception will be thrown.
192*993229b6Sjkunz //!
193*993229b6Sjkunz //! \exception StELFFileException is thrown if an error occurs while reading the file.
194*993229b6Sjkunz //! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
getSectionData(const_section_iterator inSection)195*993229b6Sjkunz uint8_t * StELFFile::getSectionData(const_section_iterator inSection)
196*993229b6Sjkunz {
197*993229b6Sjkunz 	return readSectionData(*inSection);
198*993229b6Sjkunz }
199*993229b6Sjkunz 
200*993229b6Sjkunz //! \exception StELFFileException is thrown if an error occurs while reading the file.
201*993229b6Sjkunz //! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
readSectionData(const Elf32_Shdr & inHeader)202*993229b6Sjkunz uint8_t * StELFFile::readSectionData(const Elf32_Shdr & inHeader)
203*993229b6Sjkunz {
204*993229b6Sjkunz 	// check for empty data
205*993229b6Sjkunz 	if (inHeader.sh_offset == 0 || inHeader.sh_size == 0)
206*993229b6Sjkunz 		return NULL;
207*993229b6Sjkunz 
208*993229b6Sjkunz 	uint8_t * sectionData = new uint8_t[inHeader.sh_size];
209*993229b6Sjkunz 
210*993229b6Sjkunz 	try
211*993229b6Sjkunz 	{
212*993229b6Sjkunz 		m_stream.seekg(inHeader.sh_offset, std::ios::beg);
213*993229b6Sjkunz 		m_stream.read(reinterpret_cast<char *>(sectionData), inHeader.sh_size);
214*993229b6Sjkunz 		if (m_stream.bad())
215*993229b6Sjkunz 			throw StELFFileException("could not read entire section");
216*993229b6Sjkunz 	}
217*993229b6Sjkunz 	catch (StELFFileException)
218*993229b6Sjkunz 	{
219*993229b6Sjkunz 		throw;
220*993229b6Sjkunz 	}
221*993229b6Sjkunz 	catch (...)
222*993229b6Sjkunz 	{
223*993229b6Sjkunz 		throw StELFFileException("error reading section data");
224*993229b6Sjkunz 	}
225*993229b6Sjkunz 
226*993229b6Sjkunz 	return sectionData;
227*993229b6Sjkunz }
228*993229b6Sjkunz 
getSegmentAtIndex(unsigned inIndex) const229*993229b6Sjkunz const Elf32_Phdr & StELFFile::getSegmentAtIndex(unsigned inIndex) const
230*993229b6Sjkunz {
231*993229b6Sjkunz 	if (inIndex > m_programHeaders.size())
232*993229b6Sjkunz 		throw std::invalid_argument("inIndex");
233*993229b6Sjkunz 
234*993229b6Sjkunz 	return m_programHeaders[inIndex];
235*993229b6Sjkunz }
236*993229b6Sjkunz 
237*993229b6Sjkunz //! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
238*993229b6Sjkunz //! If either the segment offset (p_offset) or the segment file size (p_filesz) are 0, then NULL will
239*993229b6Sjkunz //! be returned instead.
240*993229b6Sjkunz //!
241*993229b6Sjkunz //! The data is read directly from the input stream passed into the constructor. The stream must
242*993229b6Sjkunz //! still be open, or an exception will be thrown.
243*993229b6Sjkunz //!
244*993229b6Sjkunz //! \exception StELFFileException is thrown if an error occurs while reading the file.
245*993229b6Sjkunz //! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
getSegmentDataAtIndex(unsigned inIndex)246*993229b6Sjkunz uint8_t * StELFFile::getSegmentDataAtIndex(unsigned inIndex)
247*993229b6Sjkunz {
248*993229b6Sjkunz 	return readSegmentData(m_programHeaders[inIndex]);
249*993229b6Sjkunz }
250*993229b6Sjkunz 
251*993229b6Sjkunz //! The pointer returned from this method must be freed with the delete array operator (i.e., delete []).
252*993229b6Sjkunz //! If either the segment offset (p_offset) or the segment file size (p_filesz) are 0, then NULL will
253*993229b6Sjkunz //! be returned instead.
254*993229b6Sjkunz //!
255*993229b6Sjkunz //! The data is read directly from the input stream passed into the constructor. The stream must
256*993229b6Sjkunz //! still be open, or an exception will be thrown.
257*993229b6Sjkunz //!
258*993229b6Sjkunz //! \exception StELFFileException is thrown if an error occurs while reading the file.
259*993229b6Sjkunz //! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
getSegmentData(const_segment_iterator inSegment)260*993229b6Sjkunz uint8_t * StELFFile::getSegmentData(const_segment_iterator inSegment)
261*993229b6Sjkunz {
262*993229b6Sjkunz 	return readSegmentData(*inSegment);
263*993229b6Sjkunz }
264*993229b6Sjkunz 
265*993229b6Sjkunz //! \exception StELFFileException is thrown if an error occurs while reading the file.
266*993229b6Sjkunz //! \exception std::bad_alloc is thrown if memory for the data cannot be allocated.
readSegmentData(const Elf32_Phdr & inHeader)267*993229b6Sjkunz uint8_t * StELFFile::readSegmentData(const Elf32_Phdr & inHeader)
268*993229b6Sjkunz {
269*993229b6Sjkunz 	// check for empty data
270*993229b6Sjkunz 	if (inHeader.p_offset == 0 || inHeader.p_filesz== 0)
271*993229b6Sjkunz 		return NULL;
272*993229b6Sjkunz 
273*993229b6Sjkunz 	uint8_t * segmentData = new uint8_t[inHeader.p_filesz];
274*993229b6Sjkunz 
275*993229b6Sjkunz 	try
276*993229b6Sjkunz 	{
277*993229b6Sjkunz 		m_stream.seekg(inHeader.p_offset, std::ios::beg);
278*993229b6Sjkunz 		m_stream.read(reinterpret_cast<char *>(segmentData), inHeader.p_filesz);
279*993229b6Sjkunz 		if (m_stream.bad())
280*993229b6Sjkunz 			throw StELFFileException("could not read entire segment");
281*993229b6Sjkunz 	}
282*993229b6Sjkunz 	catch (StELFFileException)
283*993229b6Sjkunz 	{
284*993229b6Sjkunz 		throw;
285*993229b6Sjkunz 	}
286*993229b6Sjkunz 	catch (...)
287*993229b6Sjkunz 	{
288*993229b6Sjkunz 		throw StELFFileException("error reading segment data");
289*993229b6Sjkunz 	}
290*993229b6Sjkunz 
291*993229b6Sjkunz 	return segmentData;
292*993229b6Sjkunz }
293*993229b6Sjkunz 
294*993229b6Sjkunz //! If the index is out of range, or if there is no string table in the file, then
295*993229b6Sjkunz //! an empty string will be returned instead. This will also happen when the index
296*993229b6Sjkunz //! is either 0 or the last byte in the table, since the table begins and ends with
297*993229b6Sjkunz //! zero bytes.
getSectionNameAtIndex(unsigned inIndex)298*993229b6Sjkunz std::string StELFFile::getSectionNameAtIndex(unsigned inIndex)
299*993229b6Sjkunz {
300*993229b6Sjkunz 	// make sure there's a section name string table
301*993229b6Sjkunz 	if (m_header.e_shstrndx == SHN_UNDEF)
302*993229b6Sjkunz 		return std::string("");
303*993229b6Sjkunz 
304*993229b6Sjkunz 	return getStringAtIndex(m_header.e_shstrndx, inIndex);
305*993229b6Sjkunz }
306*993229b6Sjkunz 
307*993229b6Sjkunz //! \exception std::invalid_argument is thrown if the section identified by \a
308*993229b6Sjkunz //!		inStringTableSectionIndex is not actually a string table, or if \a
309*993229b6Sjkunz //!		inStringIndex is out of range for the string table.
getStringAtIndex(unsigned inStringTableSectionIndex,unsigned inStringIndex)310*993229b6Sjkunz std::string StELFFile::getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex)
311*993229b6Sjkunz {
312*993229b6Sjkunz 	// check section type
313*993229b6Sjkunz 	const Elf32_Shdr & header = getSectionAtIndex(inStringTableSectionIndex);
314*993229b6Sjkunz 	if (header.sh_type != SHT_STRTAB)
315*993229b6Sjkunz 		throw std::invalid_argument("inStringTableSectionIndex");
316*993229b6Sjkunz 
317*993229b6Sjkunz 	if (inStringIndex >= header.sh_size)
318*993229b6Sjkunz 		throw std::invalid_argument("inStringTableSectionIndex");
319*993229b6Sjkunz 
320*993229b6Sjkunz 	// check cache
321*993229b6Sjkunz 	SectionDataInfo & info = getCachedSectionData(inStringTableSectionIndex);
322*993229b6Sjkunz 	return std::string(&reinterpret_cast<char *>(info.m_data)[inStringIndex]);
323*993229b6Sjkunz }
324*993229b6Sjkunz 
getCachedSectionData(unsigned inSectionIndex)325*993229b6Sjkunz StELFFile::SectionDataInfo & StELFFile::getCachedSectionData(unsigned inSectionIndex)
326*993229b6Sjkunz {
327*993229b6Sjkunz 	// check cache
328*993229b6Sjkunz 	SectionDataMap::iterator it = m_sectionDataCache.find(inSectionIndex);
329*993229b6Sjkunz 	if (it != m_sectionDataCache.end())
330*993229b6Sjkunz 		return it->second;
331*993229b6Sjkunz 
332*993229b6Sjkunz 	// not in cache, add it
333*993229b6Sjkunz 	const Elf32_Shdr & header = getSectionAtIndex(inSectionIndex);
334*993229b6Sjkunz 	uint8_t * data = getSectionDataAtIndex(inSectionIndex);
335*993229b6Sjkunz 
336*993229b6Sjkunz 	SectionDataInfo info;
337*993229b6Sjkunz 	info.m_data = data;
338*993229b6Sjkunz 	info.m_size = header.sh_size;
339*993229b6Sjkunz 
340*993229b6Sjkunz 	m_sectionDataCache[inSectionIndex] = info;
341*993229b6Sjkunz 	return m_sectionDataCache[inSectionIndex];
342*993229b6Sjkunz }
343*993229b6Sjkunz 
344*993229b6Sjkunz //! The number of entries in the symbol table is the symbol table section size
345*993229b6Sjkunz //! divided by the size of each symbol entry (the #Elf32_Shdr::sh_entsize field of the
346*993229b6Sjkunz //! symbol table section header).
getSymbolCount()347*993229b6Sjkunz unsigned StELFFile::getSymbolCount()
348*993229b6Sjkunz {
349*993229b6Sjkunz 	if (m_symbolTableIndex == SHN_UNDEF)
350*993229b6Sjkunz 		return 0;
351*993229b6Sjkunz 
352*993229b6Sjkunz 	const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
353*993229b6Sjkunz 	return header.sh_size / header.sh_entsize;
354*993229b6Sjkunz }
355*993229b6Sjkunz 
356*993229b6Sjkunz //! \exception std::invalid_argument is thrown if \a inIndex is out of range.]
357*993229b6Sjkunz //!
getSymbolAtIndex(unsigned inIndex)358*993229b6Sjkunz const Elf32_Sym & StELFFile::getSymbolAtIndex(unsigned inIndex)
359*993229b6Sjkunz {
360*993229b6Sjkunz 	// get section data
361*993229b6Sjkunz 	const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
362*993229b6Sjkunz 	SectionDataInfo & info = getCachedSectionData(m_symbolTableIndex);
363*993229b6Sjkunz 
364*993229b6Sjkunz 	// has the symbol table been byte swapped yet?
365*993229b6Sjkunz 	if (!info.m_swapped)
366*993229b6Sjkunz 	{
367*993229b6Sjkunz 		byteSwapSymbolTable(header, info);
368*993229b6Sjkunz 	}
369*993229b6Sjkunz 
370*993229b6Sjkunz 	unsigned symbolOffset = header.sh_entsize * inIndex;
371*993229b6Sjkunz 	if (symbolOffset >= info.m_size)
372*993229b6Sjkunz 	{
373*993229b6Sjkunz 		throw std::invalid_argument("inIndex");
374*993229b6Sjkunz 	}
375*993229b6Sjkunz 
376*993229b6Sjkunz 	Elf32_Sym * symbol = reinterpret_cast<Elf32_Sym *>(&info.m_data[symbolOffset]);
377*993229b6Sjkunz 	return *symbol;
378*993229b6Sjkunz }
379*993229b6Sjkunz 
byteSwapSymbolTable(const Elf32_Shdr & header,SectionDataInfo & info)380*993229b6Sjkunz void StELFFile::byteSwapSymbolTable(const Elf32_Shdr & header, SectionDataInfo & info)
381*993229b6Sjkunz {
382*993229b6Sjkunz 	unsigned symbolCount = getSymbolCount();
383*993229b6Sjkunz 	unsigned i = 0;
384*993229b6Sjkunz 	unsigned symbolOffset = 0;
385*993229b6Sjkunz 
386*993229b6Sjkunz 	for (; i < symbolCount; ++i, symbolOffset += header.sh_entsize)
387*993229b6Sjkunz 	{
388*993229b6Sjkunz 		Elf32_Sym * symbol = reinterpret_cast<Elf32_Sym *>(&info.m_data[symbolOffset]);
389*993229b6Sjkunz 		symbol->st_name = ENDIAN_LITTLE_TO_HOST_U32(symbol->st_name);
390*993229b6Sjkunz 		symbol->st_value = ENDIAN_LITTLE_TO_HOST_U32(symbol->st_value);
391*993229b6Sjkunz 		symbol->st_size = ENDIAN_LITTLE_TO_HOST_U32(symbol->st_size);
392*993229b6Sjkunz 		symbol->st_shndx = ENDIAN_LITTLE_TO_HOST_U16(symbol->st_shndx);
393*993229b6Sjkunz 	}
394*993229b6Sjkunz 
395*993229b6Sjkunz 	// remember that we've byte swapped the symbols
396*993229b6Sjkunz 	info.m_swapped = true;
397*993229b6Sjkunz }
398*993229b6Sjkunz 
getSymbolNameStringTableIndex() const399*993229b6Sjkunz unsigned StELFFile::getSymbolNameStringTableIndex() const
400*993229b6Sjkunz {
401*993229b6Sjkunz 	const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
402*993229b6Sjkunz 	return header.sh_link;
403*993229b6Sjkunz }
404*993229b6Sjkunz 
getSymbolName(const Elf32_Sym & inSymbol)405*993229b6Sjkunz std::string StELFFile::getSymbolName(const Elf32_Sym & inSymbol)
406*993229b6Sjkunz {
407*993229b6Sjkunz 	unsigned symbolStringTableIndex = getSymbolNameStringTableIndex();
408*993229b6Sjkunz 	return getStringAtIndex(symbolStringTableIndex, inSymbol.st_name);
409*993229b6Sjkunz }
410*993229b6Sjkunz 
411*993229b6Sjkunz //! Returns STN_UNDEF if it cannot find a symbol at the given \a symbolAddress.
getIndexOfSymbolAtAddress(uint32_t symbolAddress,bool strict)412*993229b6Sjkunz unsigned StELFFile::getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict)
413*993229b6Sjkunz {
414*993229b6Sjkunz 	unsigned symbolCount = getSymbolCount();
415*993229b6Sjkunz 	unsigned symbolIndex = 0;
416*993229b6Sjkunz 	for (; symbolIndex < symbolCount; ++symbolIndex)
417*993229b6Sjkunz 	{
418*993229b6Sjkunz 		const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
419*993229b6Sjkunz 
420*993229b6Sjkunz 		// the GHS toolchain puts in STT_FUNC symbols marking the beginning and ending of each
421*993229b6Sjkunz 		// file. if the entry point happens to be at the beginning of the file, the beginning-
422*993229b6Sjkunz 		// of-file symbol will have the same value and type. fortunately, the size of these
423*993229b6Sjkunz 		// symbols is 0 (or seems to be). we also ignore symbols that start with two dots just
424*993229b6Sjkunz 		// in case.
425*993229b6Sjkunz 		if (symbol.st_value == symbolAddress && (strict && ELF32_ST_TYPE(symbol.st_info) == STT_FUNC && symbol.st_size != 0))
426*993229b6Sjkunz 		{
427*993229b6Sjkunz 			std::string symbolName = getSymbolName(symbol);
428*993229b6Sjkunz 
429*993229b6Sjkunz 			// ignore symbols that start with two dots
430*993229b6Sjkunz 			if (symbolName[0] == '.' && symbolName[1] == '.')
431*993229b6Sjkunz 				continue;
432*993229b6Sjkunz 
433*993229b6Sjkunz 			// found the symbol!
434*993229b6Sjkunz 			return symbolIndex;
435*993229b6Sjkunz 		}
436*993229b6Sjkunz 	}
437*993229b6Sjkunz 
438*993229b6Sjkunz 	return STN_UNDEF;
439*993229b6Sjkunz }
440*993229b6Sjkunz 
getTypeOfSymbolAtIndex(unsigned symbolIndex)441*993229b6Sjkunz ARMSymbolType_t StELFFile::getTypeOfSymbolAtIndex(unsigned symbolIndex)
442*993229b6Sjkunz {
443*993229b6Sjkunz 	ARMSymbolType_t symType = eARMSymbol;
444*993229b6Sjkunz 	const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
445*993229b6Sjkunz 
446*993229b6Sjkunz 	if (m_elfVariant == eGHSVariant)
447*993229b6Sjkunz 	{
448*993229b6Sjkunz 		if (symbol.st_other & STO_THUMB)
449*993229b6Sjkunz 			symType = eThumbSymbol;
450*993229b6Sjkunz 	}
451*993229b6Sjkunz 	else
452*993229b6Sjkunz 	{
453*993229b6Sjkunz 		unsigned mappingSymStart = 1;
454*993229b6Sjkunz 		unsigned mappingSymCount = getSymbolCount() - 1;	// don't include first undefined symbol
455*993229b6Sjkunz 		bool mapSymsFirst = (m_header.e_flags & EF_ARM_MAPSYMSFIRST) != 0;
456*993229b6Sjkunz 		if (mapSymsFirst)
457*993229b6Sjkunz 		{
458*993229b6Sjkunz 			// first symbol '$m' is number of mapping syms
459*993229b6Sjkunz 			const Elf32_Sym & mappingSymCountSym = getSymbolAtIndex(1);
460*993229b6Sjkunz 			if (getSymbolName(mappingSymCountSym) == MAPPING_SYMBOL_COUNT_TAGSYM)
461*993229b6Sjkunz 			{
462*993229b6Sjkunz 				mappingSymCount = mappingSymCountSym.st_value;
463*993229b6Sjkunz 				mappingSymStart = 2;
464*993229b6Sjkunz 			}
465*993229b6Sjkunz 
466*993229b6Sjkunz 		}
467*993229b6Sjkunz 
468*993229b6Sjkunz 		uint32_t lastMappingSymAddress = 0;
469*993229b6Sjkunz 		unsigned mappingSymIndex = mappingSymStart;
470*993229b6Sjkunz 		for (; mappingSymIndex < mappingSymCount + mappingSymStart; ++mappingSymIndex)
471*993229b6Sjkunz 		{
472*993229b6Sjkunz 			const Elf32_Sym & mappingSym = getSymbolAtIndex(mappingSymIndex);
473*993229b6Sjkunz 			std::string mappingSymName = getSymbolName(mappingSym);
474*993229b6Sjkunz 			ARMSymbolType_t nextSymType = eUnknownSymbol;
475*993229b6Sjkunz 
476*993229b6Sjkunz 			if (mappingSymName == ARM_SEQUENCE_MAPSYM)
477*993229b6Sjkunz 				symType = eARMSymbol;
478*993229b6Sjkunz 			else if (mappingSymName == DATA_SEQUENCE_MAPSYM)
479*993229b6Sjkunz 				symType = eDataSymbol;
480*993229b6Sjkunz 			else if (mappingSymName == THUMB_SEQUENCE_MAPSYM)
481*993229b6Sjkunz 				symType = eThumbSymbol;
482*993229b6Sjkunz 
483*993229b6Sjkunz 			if (nextSymType != eUnknownSymbol)
484*993229b6Sjkunz 			{
485*993229b6Sjkunz 				if (symbol.st_value >= lastMappingSymAddress && symbol.st_value < mappingSym.st_value)
486*993229b6Sjkunz 					break;
487*993229b6Sjkunz 
488*993229b6Sjkunz 				symType = nextSymType;
489*993229b6Sjkunz 				lastMappingSymAddress = mappingSym.st_value;
490*993229b6Sjkunz 			}
491*993229b6Sjkunz 		}
492*993229b6Sjkunz 	}
493*993229b6Sjkunz 
494*993229b6Sjkunz 	return symType;
495*993229b6Sjkunz }
496*993229b6Sjkunz 
dumpSections()497*993229b6Sjkunz void StELFFile::dumpSections()
498*993229b6Sjkunz {
499*993229b6Sjkunz 	unsigned count = getSectionCount();
500*993229b6Sjkunz 	unsigned i = 0;
501*993229b6Sjkunz 
502*993229b6Sjkunz 	const char * sectionTypes[12] = { "NULL", "PROGBITS", "SYMTAB", "STRTAB", "RELA", "HASH", "DYNAMIC", "NOTE", "NOBITS", "REL", "SHLIB", "DYNSYM" };
503*993229b6Sjkunz 
504*993229b6Sjkunz 	for (; i < count; ++i)
505*993229b6Sjkunz 	{
506*993229b6Sjkunz 		const Elf32_Shdr & header = getSectionAtIndex(i);
507*993229b6Sjkunz 		std::string name = getSectionNameAtIndex(header.sh_name);
508*993229b6Sjkunz 
509*993229b6Sjkunz 		printf("%s: %s, 0x%08x, 0x%08x, 0x%08x, %d, %d, %d\n", name.c_str(), sectionTypes[header.sh_type], header.sh_addr, header.sh_offset, header.sh_size, header.sh_link, header.sh_info, header.sh_entsize);
510*993229b6Sjkunz 	}
511*993229b6Sjkunz }
512*993229b6Sjkunz 
dumpSymbolTable()513*993229b6Sjkunz void StELFFile::dumpSymbolTable()
514*993229b6Sjkunz {
515*993229b6Sjkunz 	const char * symbolTypes[5] = { "NOTYPE", "OBJECT", "FUNC", "SECTION", "FILE" };
516*993229b6Sjkunz 	const char * symbolBinding[3] = { "LOCAL", "GLOBAL", "WEAK" };
517*993229b6Sjkunz 
518*993229b6Sjkunz 	unsigned count = getSymbolCount();
519*993229b6Sjkunz 	unsigned i = 0;
520*993229b6Sjkunz 
521*993229b6Sjkunz 	for (; i < count; ++i)
522*993229b6Sjkunz 	{
523*993229b6Sjkunz 		const Elf32_Sym & symbol = getSymbolAtIndex(i);
524*993229b6Sjkunz 		std::string name = getSymbolName(symbol);
525*993229b6Sjkunz 
526*993229b6Sjkunz 		printf("'%s': %s, %s, 0x%08x, 0x%08x, %d. 0x%08x\n", name.c_str(), symbolTypes[ELF32_ST_TYPE(symbol.st_info)], symbolBinding[ELF32_ST_BIND(symbol.st_info)], symbol.st_value, symbol.st_size, symbol.st_shndx, symbol.st_other);
527*993229b6Sjkunz 	}
528*993229b6Sjkunz }
529*993229b6Sjkunz 
530*993229b6Sjkunz 
531*993229b6Sjkunz 
532