Home | History | Annotate | Line # | Download | only in common
      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 //!
     16 StELFFile::StELFFile(std::istream & inStream)
     17 :	m_stream(inStream)
     18 {
     19 	readFileHeaders();
     20 }
     21 
     22 //! Disposes of the string table data.
     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 //!
     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 
    143 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 //!
    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.
    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.
    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.
    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 
    229 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.
    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.
    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.
    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.
    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.
    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 
    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).
    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 //!
    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 
    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 
    399 unsigned StELFFile::getSymbolNameStringTableIndex() const
    400 {
    401 	const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
    402 	return header.sh_link;
    403 }
    404 
    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.
    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 
    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 
    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 
    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