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