4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5 * See included license file for license details.
12 #include "EndianUtilities.h"
14 //! \exception StELFFileException is thrown if there is a problem with the file format.
16 StELFFile::StELFFile(std::istream & inStream)
22 //! Disposes of the string table data.
23 StELFFile::~StELFFile()
25 SectionDataMap::iterator it = m_sectionDataCache.begin();
26 for (; it != m_sectionDataCache.end(); ++it)
28 SectionDataInfo & info = it->second;
29 if (info.m_data != NULL)
31 delete [] info.m_data;
36 //! \exception StELFFileException is thrown if the file is not an ELF file.
38 void StELFFile::readFileHeaders()
40 // move read head to beginning of stream
41 m_stream.seekg(0, std::ios_base::beg);
44 m_stream.read(reinterpret_cast<char *>(&m_header), sizeof(m_header));
47 throw StELFFileException("could not read file header");
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);
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))
68 throw StELFFileException("invalid magic number in ELF header");
75 // read section headers
76 if (m_header.e_shoff != 0 && m_header.e_shnum > 0)
78 Elf32_Shdr sectionHeader;
79 for (i=0; i < m_header.e_shnum; ++i)
81 m_stream.seekg(m_header.e_shoff + m_header.e_shentsize * i, std::ios::beg);
82 m_stream.read(reinterpret_cast<char *>(§ionHeader), sizeof(sectionHeader));
85 throw StELFFileException("could not read section header");
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);
100 m_sectionHeaders.push_back(sectionHeader);
104 // read program headers
105 if (m_header.e_phoff != 0 && m_header.e_phnum > 0)
107 Elf32_Phdr programHeader;
108 for (i=0; i < m_header.e_phnum; ++i)
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));
114 throw StELFFileException("could not read program header");
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);
127 m_programHeaders.push_back(programHeader);
131 // look up symbol table section index
133 std::string symtab_section_name(SYMTAB_SECTION_NAME);
134 m_symbolTableIndex = getIndexOfSectionWithName(symtab_section_name);
139 throw StELFFileException("error reading file");
143 const Elf32_Shdr & StELFFile::getSectionAtIndex(unsigned inIndex) const
145 if (inIndex > m_sectionHeaders.size())
146 throw std::invalid_argument("inIndex");
148 return m_sectionHeaders[inIndex];
151 //! If there is not a matching section, then #SHN_UNDEF is returned instead.
153 unsigned StELFFile::getIndexOfSectionWithName(const std::string & inName)
155 unsigned sectionIndex = 0;
156 const_section_iterator it = getSectionBegin();
157 for (; it != getSectionEnd(); ++it, ++sectionIndex)
159 const Elf32_Shdr & header = *it;
160 if (header.sh_name != 0)
162 std::string sectionName = getSectionNameAtIndex(header.sh_name);
163 if (inName == sectionName)
168 // no matching section
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.
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.
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)
183 return readSectionData(m_sectionHeaders[inIndex]);
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.
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.
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)
197 return readSectionData(*inSection);
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)
204 // check for empty data
205 if (inHeader.sh_offset == 0 || inHeader.sh_size == 0)
208 uint8_t * sectionData = new uint8_t[inHeader.sh_size];
212 m_stream.seekg(inHeader.sh_offset, std::ios::beg);
213 m_stream.read(reinterpret_cast<char *>(sectionData), inHeader.sh_size);
215 throw StELFFileException("could not read entire section");
217 catch (StELFFileException)
223 throw StELFFileException("error reading section data");
229 const Elf32_Phdr & StELFFile::getSegmentAtIndex(unsigned inIndex) const
231 if (inIndex > m_programHeaders.size())
232 throw std::invalid_argument("inIndex");
234 return m_programHeaders[inIndex];
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.
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.
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)
248 return readSegmentData(m_programHeaders[inIndex]);
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.
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.
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)
262 return readSegmentData(*inSegment);
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)
269 // check for empty data
270 if (inHeader.p_offset == 0 || inHeader.p_filesz== 0)
273 uint8_t * segmentData = new uint8_t[inHeader.p_filesz];
277 m_stream.seekg(inHeader.p_offset, std::ios::beg);
278 m_stream.read(reinterpret_cast<char *>(segmentData), inHeader.p_filesz);
280 throw StELFFileException("could not read entire segment");
282 catch (StELFFileException)
288 throw StELFFileException("error reading segment data");
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
298 std::string StELFFile::getSectionNameAtIndex(unsigned inIndex)
300 // make sure there's a section name string table
301 if (m_header.e_shstrndx == SHN_UNDEF)
302 return std::string("");
304 return getStringAtIndex(m_header.e_shstrndx, inIndex);
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)
312 // check section type
313 const Elf32_Shdr & header = getSectionAtIndex(inStringTableSectionIndex);
314 if (header.sh_type != SHT_STRTAB)
315 throw std::invalid_argument("inStringTableSectionIndex");
317 if (inStringIndex >= header.sh_size)
318 throw std::invalid_argument("inStringTableSectionIndex");
321 SectionDataInfo & info = getCachedSectionData(inStringTableSectionIndex);
322 return std::string(&reinterpret_cast<char *>(info.m_data)[inStringIndex]);
325 StELFFile::SectionDataInfo & StELFFile::getCachedSectionData(unsigned inSectionIndex)
328 SectionDataMap::iterator it = m_sectionDataCache.find(inSectionIndex);
329 if (it != m_sectionDataCache.end())
332 // not in cache, add it
333 const Elf32_Shdr & header = getSectionAtIndex(inSectionIndex);
334 uint8_t * data = getSectionDataAtIndex(inSectionIndex);
336 SectionDataInfo info;
338 info.m_size = header.sh_size;
340 m_sectionDataCache[inSectionIndex] = info;
341 return m_sectionDataCache[inSectionIndex];
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()
349 if (m_symbolTableIndex == SHN_UNDEF)
352 const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
353 return header.sh_size / header.sh_entsize;
356 //! \exception std::invalid_argument is thrown if \a inIndex is out of range.]
358 const Elf32_Sym & StELFFile::getSymbolAtIndex(unsigned inIndex)
361 const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
362 SectionDataInfo & info = getCachedSectionData(m_symbolTableIndex);
364 // has the symbol table been byte swapped yet?
367 byteSwapSymbolTable(header, info);
370 unsigned symbolOffset = header.sh_entsize * inIndex;
371 if (symbolOffset >= info.m_size)
373 throw std::invalid_argument("inIndex");
376 Elf32_Sym * symbol = reinterpret_cast<Elf32_Sym *>(&info.m_data[symbolOffset]);
380 void StELFFile::byteSwapSymbolTable(const Elf32_Shdr & header, SectionDataInfo & info)
382 unsigned symbolCount = getSymbolCount();
384 unsigned symbolOffset = 0;
386 for (; i < symbolCount; ++i, symbolOffset += header.sh_entsize)
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);
395 // remember that we've byte swapped the symbols
396 info.m_swapped = true;
399 unsigned StELFFile::getSymbolNameStringTableIndex() const
401 const Elf32_Shdr & header = getSectionAtIndex(m_symbolTableIndex);
402 return header.sh_link;
405 std::string StELFFile::getSymbolName(const Elf32_Sym & inSymbol)
407 unsigned symbolStringTableIndex = getSymbolNameStringTableIndex();
408 return getStringAtIndex(symbolStringTableIndex, inSymbol.st_name);
411 //! Returns STN_UNDEF if it cannot find a symbol at the given \a symbolAddress.
412 unsigned StELFFile::getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict)
414 unsigned symbolCount = getSymbolCount();
415 unsigned symbolIndex = 0;
416 for (; symbolIndex < symbolCount; ++symbolIndex)
418 const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
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
425 if (symbol.st_value == symbolAddress && (strict && ELF32_ST_TYPE(symbol.st_info) == STT_FUNC && symbol.st_size != 0))
427 std::string symbolName = getSymbolName(symbol);
429 // ignore symbols that start with two dots
430 if (symbolName[0] == '.' && symbolName[1] == '.')
441 ARMSymbolType_t StELFFile::getTypeOfSymbolAtIndex(unsigned symbolIndex)
443 ARMSymbolType_t symType = eARMSymbol;
444 const Elf32_Sym & symbol = getSymbolAtIndex(symbolIndex);
446 if (m_elfVariant == eGHSVariant)
448 if (symbol.st_other & STO_THUMB)
449 symType = eThumbSymbol;
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;
458 // first symbol '$m' is number of mapping syms
459 const Elf32_Sym & mappingSymCountSym = getSymbolAtIndex(1);
460 if (getSymbolName(mappingSymCountSym) == MAPPING_SYMBOL_COUNT_TAGSYM)
462 mappingSymCount = mappingSymCountSym.st_value;
468 uint32_t lastMappingSymAddress = 0;
469 unsigned mappingSymIndex = mappingSymStart;
470 for (; mappingSymIndex < mappingSymCount + mappingSymStart; ++mappingSymIndex)
472 const Elf32_Sym & mappingSym = getSymbolAtIndex(mappingSymIndex);
473 std::string mappingSymName = getSymbolName(mappingSym);
474 ARMSymbolType_t nextSymType = eUnknownSymbol;
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;
483 if (nextSymType != eUnknownSymbol)
485 if (symbol.st_value >= lastMappingSymAddress && symbol.st_value < mappingSym.st_value)
488 symType = nextSymType;
489 lastMappingSymAddress = mappingSym.st_value;
497 void StELFFile::dumpSections()
499 unsigned count = getSectionCount();
502 const char * sectionTypes[12] = { "NULL", "PROGBITS", "SYMTAB", "STRTAB", "RELA", "HASH", "DYNAMIC", "NOTE", "NOBITS", "REL", "SHLIB", "DYNSYM" };
504 for (; i < count; ++i)
506 const Elf32_Shdr & header = getSectionAtIndex(i);
507 std::string name = getSectionNameAtIndex(header.sh_name);
509 if (header.sh_type < sizeof(sectionTypes) / sizeof(sectionTypes[0])) {
510 printf("%s: %s, 0x%08x, 0x%08x, 0x%08x, %d, %d, %d\n",
511 name.c_str(), sectionTypes[header.sh_type],
512 header.sh_addr, header.sh_offset,
513 header.sh_size, header.sh_link,
514 header.sh_info, header.sh_entsize);
516 printf("%s: 0x%02x, 0x%08x, 0x%08x, 0x%08x, %d, %d, %d\n",
517 name.c_str(), header.sh_type,
518 header.sh_addr, header.sh_offset,
519 header.sh_size, header.sh_link,
520 header.sh_info, header.sh_entsize);
525 void StELFFile::dumpSymbolTable()
527 const char * symbolTypes[5] = { "NOTYPE", "OBJECT", "FUNC", "SECTION", "FILE" };
528 const char * symbolBinding[3] = { "LOCAL", "GLOBAL", "WEAK" };
530 unsigned count = getSymbolCount();
533 for (; i < count; ++i)
535 const Elf32_Sym & symbol = getSymbolAtIndex(i);
536 std::string name = getSymbolName(symbol);
538 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);