1 /*
2  * File:  StELFFile.h
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7 #if !defined(_StELFFile_h_)
8 #define _StELFFile_h_
9 
10 #include "stdafx.h"
11 #include <string>
12 #include <vector>
13 #include <map>
14 #include <iostream>
15 #include <stdexcept>
16 #include "ELF.h"
17 
18 //! Variations of the ARM ELF format.
19 typedef enum {
20           eARMVariant = 1,    //!< Standard ARM ELF specification.
21           eGHSVariant,                  //!< Green Hills Software variant.
22           eGCCVariant                   //!< GNU Compiler Collection variant.
23 } ELFVariant_t;
24 
25 //! Possible ARM ELF symbol types.
26 typedef enum {
27           eUnknownSymbol,
28           eARMSymbol,
29           eThumbSymbol,
30           eDataSymbol
31 } ARMSymbolType_t;
32 
33 /*!
34  * \brief Parser for Executable and Linking Format (ELF) files.
35  *
36  * The stream passed into the constructor needs to stay open for the life
37  * of the object. This is because calls to getSectionDataAtIndex() and
38  * getSegmentDataAtIndex() read the data directly from the input stream.
39  */
40 class StELFFile
41 {
42 public:
43           typedef std::vector<Elf32_Shdr>::const_iterator const_section_iterator;
44           typedef std::vector<Elf32_Phdr>::const_iterator const_segment_iterator;
45 
46 public:
47           //! \brief Constructor.
48           StELFFile(std::istream & inStream);
49 
50           //! \brief Destructor.
51           virtual ~StELFFile();
52 
53           //! \name File format variant
54           //@{
55           //! \brief Return the ELF format variant to which this file is set.
ELFVariant()56           virtual ELFVariant_t ELFVariant() { return m_elfVariant; }
57 
58           //! \brief Set the ELF format variation to either #eARMVariant or #eGHSVariant.
setELFVariant(ELFVariant_t variant)59           virtual void setELFVariant(ELFVariant_t variant) { m_elfVariant = variant; }
60           //@}
61 
62           //! \name File name
63           //@{
setName(const std::string & inName)64           virtual void setName(const std::string & inName) { m_name = inName; }
getName()65           virtual std::string getName() const { return m_name; }
66           //@}
67 
68           //! \name ELF header
69           //@{
70           //! \brief Returns the ELF file header.
getFileHeader()71           inline const Elf32_Ehdr & getFileHeader() const { return m_header; }
72           //@}
73 
74           //! \name Sections
75           //! Methods pertaining to the object file's sections.
76           //@{
77           //! \brief Returns the number of sections in the file.
getSectionCount()78           inline unsigned getSectionCount() const { return static_cast<unsigned>(m_sectionHeaders.size()); }
79 
80           //! \brief Returns a reference to section number \a inIndex.
81           const Elf32_Shdr & getSectionAtIndex(unsigned inIndex) const;
82 
getSectionBegin()83           inline const_section_iterator getSectionBegin() const { return m_sectionHeaders.begin(); }
getSectionEnd()84           inline const_section_iterator getSectionEnd() const { return m_sectionHeaders.end(); }
85 
86           //! \brief Returns the index of the section with the name \a inName.
87           unsigned getIndexOfSectionWithName(const std::string & inName);
88 
89           //! \brief Returns the data for the section.
90           uint8_t * getSectionDataAtIndex(unsigned inIndex);
91 
92           //! \brief Returns the data for the section.
93           uint8_t * getSectionData(const_section_iterator inSection);
94           //@}
95 
96           //! \name Segments
97           //! Methods for accessing the file's program headers for segments.
98           //@{
99           //! \brief Returns the number of segments, or program headers, in the file.
getSegmentCount()100           inline unsigned getSegmentCount() const { return static_cast<unsigned>(m_programHeaders.size()); }
101 
102           //! \brief Returns a reference to the given segment.
103           const Elf32_Phdr & getSegmentAtIndex(unsigned inIndex) const;
104 
getSegmentBegin()105           inline const_segment_iterator getSegmentBegin() const { return m_programHeaders.begin(); }
getSegmentEnd()106           inline const_segment_iterator getSegmentEnd() const { return m_programHeaders.end(); }
107 
108           //! \brief Returns the data of the specified segment.
109           uint8_t * getSegmentDataAtIndex(unsigned inIndex);
110 
111           //! \brief Returns the data of the specified segment.
112           uint8_t * getSegmentData(const_segment_iterator inSegment);
113           //@}
114 
115           //! \name String table
116           //! Methods for accessing the string tables.
117           //@{
118           //! \brief Returns a string from the file's section name string table.
119           std::string getSectionNameAtIndex(unsigned inIndex);
120 
121           //! \brief Returns a string from any string table in the object file.
122           std::string getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex);
123           //@}
124 
125           //! \name Symbol table
126           //! Methods for accessing the object file's symbol table. Currently only
127           //! a single symbol table with the section name ".symtab" is supported.
128           //@{
129           //! \brief Returns the number of symbols in the default ".symtab" symbol table.
130           unsigned getSymbolCount();
131 
132           //! \brief Returns the symbol with index \a inIndex.
133           const Elf32_Sym & getSymbolAtIndex(unsigned inIndex);
134 
135           //! \brief Returns the section index of the string table containing symbol names.
136           unsigned getSymbolNameStringTableIndex() const;
137 
138           //! \brief Returns the name of the symbol described by \a inSymbol.
139           std::string getSymbolName(const Elf32_Sym & inSymbol);
140 
141           unsigned getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict=true);
142 
143           ARMSymbolType_t getTypeOfSymbolAtIndex(unsigned symbolIndex);
144           //@}
145 
146           //! \name Debugging
147           //@{
148           void dumpSections();
149           void dumpSymbolTable();
150           //@}
151 
152 protected:
153           std::istream & m_stream;      //!< The source stream for the ELF file.
154           ELFVariant_t m_elfVariant;    //!< Variant of the ARM ELF format specification.
155           std::string m_name;                     //!< File name. (optional)
156           Elf32_Ehdr m_header;          //!< The ELF file header.
157           std::vector<Elf32_Shdr> m_sectionHeaders;         //!< All of the section headers.
158           std::vector<Elf32_Phdr> m_programHeaders;         //!< All of the program headers.
159           unsigned m_symbolTableIndex;  //!< Index of ".symtab" section, or #SHN_UNDEF if not present.
160 
161           /*!
162            * Little structure containing information about cached section data.
163            */
164           struct SectionDataInfo
165           {
166                     uint8_t * m_data;   //!< Pointer to section data.
167                     unsigned m_size;    //!< Section data size in bytes.
168                     bool m_swapped;     //!< Has this section been byte swapped yet? Used for symbol table.
169           };
170           typedef std::map<unsigned, SectionDataInfo> SectionDataMap;
171           SectionDataMap m_sectionDataCache;      //!< Cached data of sections.
172 
173           //! \brief Reads a section's data either from cache or from disk.
174           SectionDataInfo & getCachedSectionData(unsigned inSectionIndex);
175 
176           //! \brief Reads the file, section, and program headers into memory.
177           void readFileHeaders();
178 
179           uint8_t * readSectionData(const Elf32_Shdr & inHeader);
180           uint8_t * readSegmentData(const Elf32_Phdr & inHeader);
181 
182           //! \brief Byte swaps the symbol table data into host endianness.
183           void byteSwapSymbolTable(const Elf32_Shdr & header, SectionDataInfo & info);
184 };
185 
186 /*!
187  * \brief Simple exception thrown to indicate an error in the input ELF file format.
188  */
189 class StELFFileException : public std::runtime_error
190 {
191 public:
192           //! \brief Default constructor.
StELFFileException(const std::string & inMessage)193           StELFFileException(const std::string & inMessage) : std::runtime_error(inMessage) {}
194 };
195 
196 #endif // _StELFFile_h_
197