1 /*
2  * File:  ELFSourceFile.cpp
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7 
8 #include "ELFSourceFile.h"
9 #include "Logging.h"
10 #include "GHSSecInfo.h"
11 #include <ctype.h>
12 #include <algorithm>
13 #include "string.h"
14 
15 //! The name of the toolset option.
16 #define kToolsetOptionName "toolset"
17 #define kGHSToolsetName "GHS"
18 #define kGCCToolsetName "GCC"
19 #define kGNUToolsetName "GNU"
20 #define kADSToolsetName "ADS"
21 
22 //! Name of the option to control .secinfo action.
23 #define kSecinfoClearOptionName "secinfoClear"
24 #define kSecinfoDefaultName "DEFAULT"
25 #define kSecinfoIgnoreName "IGNORE"
26 #define kSecinfoROMName "ROM"
27 #define kSecinfoCName "C"
28 
29 using namespace elftosb;
30 
ELFSourceFile(const std::string & path)31 ELFSourceFile::ELFSourceFile(const std::string & path)
32 :         SourceFile(path),
33           m_toolset(kUnknownToolset),
34           m_secinfoOption(kSecinfoDefault)
35 {
36 }
37 
~ELFSourceFile()38 ELFSourceFile::~ELFSourceFile()
39 {
40 }
41 
isELFFile(std::istream & stream)42 bool ELFSourceFile::isELFFile(std::istream & stream)
43 {
44           try
45           {
46                     StELFFile elf(stream);
47                     return true;
48           }
49           catch (...)
50           {
51                     return false;
52           }
53 }
54 
open()55 void ELFSourceFile::open()
56 {
57           // Read toolset option
58           m_toolset = readToolsetOption();
59 
60           // Read option and select default value
61           m_secinfoOption = readSecinfoClearOption();
62           if (m_secinfoOption == kSecinfoDefault)
63           {
64                     m_secinfoOption = kSecinfoCStartupClear;
65           }
66 
67           // Open the stream
68           SourceFile::open();
69 
70           m_file = new StELFFile(*m_stream);
71 //        m_file->dumpSections();
72 
73           // Set toolset in elf file object
74           switch (m_toolset)
75           {
76         // default toolset is GHS
77                     case kGHSToolset:
78         case kUnknownToolset:
79                               m_file->setELFVariant(eGHSVariant);
80                               break;
81                     case kGCCToolset:
82                               m_file->setELFVariant(eGCCVariant);
83                               break;
84                     case kADSToolset:
85                               m_file->setELFVariant(eARMVariant);
86                               break;
87           }
88 }
89 
close()90 void ELFSourceFile::close()
91 {
92           SourceFile::close();
93 
94           m_file.safe_delete();
95 }
96 
readToolsetOption()97 elf_toolset_t ELFSourceFile::readToolsetOption()
98 {
99           do {
100                     const OptionContext * options = getOptions();
101                     if (!options || !options->hasOption(kToolsetOptionName))
102                     {
103                               break;
104                     }
105 
106                     const Value * value = options->getOption(kToolsetOptionName);
107                     const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
108                     if (!stringValue)
109                     {
110                               // Not a string value, warn the user.
111                               Log::log(Logger::WARNING, "invalid type for 'toolset' option\n");
112                               break;
113                     }
114 
115                     std::string toolsetName = *stringValue;
116 
117                     // convert option value to uppercase
118                     std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(toolsetName.begin(), toolsetName.end(), toolsetName.begin(), toupper);
119 
120                     if (toolsetName == kGHSToolsetName)
121                     {
122                               return kGHSToolset;
123                     }
124                     else if (toolsetName == kGCCToolsetName || toolsetName == kGNUToolsetName)
125                     {
126                               return kGCCToolset;
127                     }
128                     else if (toolsetName == kADSToolsetName)
129                     {
130                               return kADSToolset;
131                     }
132 
133                     // Unrecognized option value, log a warning.
134                     Log::log(Logger::WARNING, "unrecognized value for 'toolset' option\n");
135           } while (0);
136 
137           return kUnknownToolset;
138 }
139 
140 //! It is up to the caller to convert from kSecinfoDefault to the actual default
141 //! value.
readSecinfoClearOption()142 secinfo_clear_t ELFSourceFile::readSecinfoClearOption()
143 {
144           do {
145                     const OptionContext * options = getOptions();
146                     if (!options || !options->hasOption(kSecinfoClearOptionName))
147                     {
148                               break;
149                     }
150 
151                     const Value * value = options->getOption(kSecinfoClearOptionName);
152                     const StringValue * stringValue = dynamic_cast<const StringValue*>(value);
153                     if (!stringValue)
154                     {
155                               // Not a string value, warn the user.
156                               Log::log(Logger::WARNING, "invalid type for 'secinfoClear' option\n");
157                               break;
158                     }
159 
160                     std::string secinfoOption = *stringValue;
161 
162                     // convert option value to uppercase
163                     std::transform<std::string::const_iterator, std::string::iterator, int (*)(int)>(secinfoOption.begin(), secinfoOption.end(), secinfoOption.begin(), toupper);
164 
165                     if (secinfoOption == kSecinfoDefaultName)
166                     {
167                               return kSecinfoDefault;
168                     }
169                     else if (secinfoOption == kSecinfoIgnoreName)
170                     {
171                               return kSecinfoIgnore;
172                     }
173                     else if (secinfoOption == kSecinfoROMName)
174                     {
175                               return kSecinfoROMClear;
176                     }
177                     else if (secinfoOption == kSecinfoCName)
178                     {
179                               return kSecinfoCStartupClear;
180                     }
181 
182                     // Unrecognized option value, log a warning.
183                     Log::log(Logger::WARNING, "unrecognized value for 'secinfoClear' option\n");
184           } while (0);
185 
186           return kSecinfoDefault;
187 }
188 
189 //! To create a data source for all sections of the ELF file, a WildcardMatcher
190 //! is instantiated and passed to createDataSource(StringMatcher&).
createDataSource()191 DataSource * ELFSourceFile::createDataSource()
192 {
193           WildcardMatcher matcher;
194           return createDataSource(matcher);
195 }
196 
createDataSource(StringMatcher & matcher)197 DataSource * ELFSourceFile::createDataSource(StringMatcher & matcher)
198 {
199           assert(m_file);
200           ELFDataSource * source = new ELFDataSource(m_file);
201           source->setSecinfoOption(m_secinfoOption);
202 
203           Log::log(Logger::DEBUG2, "filtering sections of file: %s\n", getPath().c_str());
204 
205           // We start at section 1 to skip the null section that is always first.
206           unsigned index = 1;
207           for (; index < m_file->getSectionCount(); ++index)
208           {
209                     const Elf32_Shdr & header = m_file->getSectionAtIndex(index);
210                     std::string name = m_file->getSectionNameAtIndex(header.sh_name);
211 
212                     // Ignore most section types
213                     if (!(header.sh_type == SHT_PROGBITS || header.sh_type == SHT_NOBITS))
214                     {
215                               continue;
216                     }
217 
218                     // Ignore sections that don't have the allocate flag set.
219                     if ((header.sh_flags & SHF_ALLOC) == 0)
220                     {
221                               continue;
222                     }
223 
224                     if (matcher.match(name))
225                     {
226                               Log::log(Logger::DEBUG2, "creating segment for section %s\n", name.c_str());
227                               source->addSection(index);
228                     }
229                     else
230                     {
231                               Log::log(Logger::DEBUG2, "section %s did not match\n", name.c_str());
232                     }
233           }
234 
235           return source;
236 }
237 
238 //! It is assumed that all ELF files have an entry point.
239 //!
hasEntryPoint()240 bool ELFSourceFile::hasEntryPoint()
241 {
242           return true;
243 }
244 
245 //! The StELFFile::getTypeOfSymbolAtIndex() method uses different methods of determining
246 //! ARM/Thumb mode depending on the toolset.
getEntryPointAddress()247 uint32_t ELFSourceFile::getEntryPointAddress()
248 {
249           uint32_t entryPoint = 0;
250 
251           // get entry point address
252           const Elf32_Ehdr & header = m_file->getFileHeader();
253 
254           // find symbol corresponding to entry point and determine if
255           // it is arm or thumb mode
256           unsigned symbolIndex = m_file->getIndexOfSymbolAtAddress(header.e_entry);
257           if (symbolIndex != 0)
258           {
259                     ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(symbolIndex);
260                     bool entryPointIsThumb = (symbolType == eThumbSymbol);
261                     const Elf32_Sym & symbol = m_file->getSymbolAtIndex(symbolIndex);
262                     std::string symbolName = m_file->getSymbolName(symbol);
263 
264                     Log::log(Logger::DEBUG2, "Entry point is %s@0x%08x (%s)\n", symbolName.c_str(), symbol.st_value, entryPointIsThumb ? "Thumb" : "ARM");
265 
266                     // set entry point, setting the low bit if it is thumb mode
267                     entryPoint = header.e_entry + (entryPointIsThumb ? 1 : 0);
268           }
269           else
270           {
271                     entryPoint = header.e_entry;
272           }
273 
274           return entryPoint;
275 }
276 
277 //! \return A DataTarget that describes the named section.
278 //! \retval NULL There was no section with the requested name.
createDataTargetForSection(const std::string & section)279 DataTarget * ELFSourceFile::createDataTargetForSection(const std::string & section)
280 {
281           assert(m_file);
282           unsigned index = m_file->getIndexOfSectionWithName(section);
283           if (index == SHN_UNDEF)
284           {
285                     return NULL;
286           }
287 
288           const Elf32_Shdr & sectionHeader = m_file->getSectionAtIndex(index);
289           uint32_t beginAddress = sectionHeader.sh_addr;
290           uint32_t endAddress = beginAddress + sectionHeader.sh_size;
291           ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
292           return target;
293 }
294 
295 //! \return A DataTarget instance pointing at the requested symbol.
296 //! \retval NULL No symbol matching the requested name was found.
createDataTargetForSymbol(const std::string & symbol)297 DataTarget * ELFSourceFile::createDataTargetForSymbol(const std::string & symbol)
298 {
299           assert(m_file);
300           unsigned symbolCount = m_file->getSymbolCount();
301           unsigned i;
302 
303           for (i=0; i < symbolCount; ++i)
304           {
305                     const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
306                     std::string symbolName = m_file->getSymbolName(symbolHeader);
307                     if (symbolName == symbol)
308                     {
309             ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
310             bool symbolIsThumb = (symbolType == eThumbSymbol);
311 
312                               uint32_t beginAddress = symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
313                               uint32_t endAddress = beginAddress + symbolHeader.st_size;
314                               ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
315                               return target;
316                     }
317           }
318 
319           // didn't find a matching symbol
320           return NULL;
321 }
322 
hasSymbol(const std::string & name)323 bool ELFSourceFile::hasSymbol(const std::string & name)
324 {
325           Elf32_Sym symbol;
326           return lookupSymbol(name, symbol);
327 }
328 
getSymbolValue(const std::string & name)329 uint32_t ELFSourceFile::getSymbolValue(const std::string & name)
330 {
331           unsigned symbolCount = m_file->getSymbolCount();
332           unsigned i;
333 
334           for (i=0; i < symbolCount; ++i)
335           {
336                     const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
337                     std::string symbolName = m_file->getSymbolName(symbolHeader);
338                     if (symbolName == name)
339                     {
340             // If the symbol is a function, then we check to see if it is Thumb code and set bit 0 if so.
341             if (ELF32_ST_TYPE(symbolHeader.st_info) == STT_FUNC)
342             {
343                 ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
344                 bool symbolIsThumb = (symbolType == eThumbSymbol);
345                 return symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
346             }
347             else
348             {
349                                   return symbolHeader.st_value;
350             }
351                     }
352           }
353 
354     // Couldn't find the symbol, so return 0.
355           return 0;
356 }
357 
getSymbolSize(const std::string & name)358 unsigned ELFSourceFile::getSymbolSize(const std::string & name)
359 {
360           Elf32_Sym symbol;
361           if (!lookupSymbol(name, symbol))
362           {
363                     return 0;
364           }
365 
366           return symbol.st_size;
367 }
368 
369 //! \param name The name of the symbol on which info is wanted.
370 //! \param[out] info Upon succssful return this is filled in with the symbol's information.
371 //!
372 //! \retval true The symbol was found and \a info is valid.
373 //! \retval false No symbol with \a name was found in the file.
lookupSymbol(const std::string & name,Elf32_Sym & info)374 bool ELFSourceFile::lookupSymbol(const std::string & name, Elf32_Sym & info)
375 {
376           assert(m_file);
377           unsigned symbolCount = m_file->getSymbolCount();
378           unsigned i;
379 
380           for (i=0; i < symbolCount; ++i)
381           {
382                     const Elf32_Sym & symbol = m_file->getSymbolAtIndex(i);
383                     std::string thisSymbolName = m_file->getSymbolName(symbol);
384 
385                     // Is this the symbol we're looking for?
386                     if (thisSymbolName == name)
387                     {
388                               info = symbol;
389                               return true;
390                     }
391           }
392 
393           // Didn't file the symbol.
394           return false;
395 }
396 
~ELFDataSource()397 ELFSourceFile::ELFDataSource::~ELFDataSource()
398 {
399           segment_vector_t::iterator it = m_segments.begin();
400           for (; it != m_segments.end(); ++it)
401           {
402                     delete *it;
403           }
404 }
405 
406 //! Not all sections will actually result in a new segment being created. Only
407 //! those sections whose type is #SHT_PROGBITS or #SHT_NOBITS will create
408 //! a new segment. Also, only sections whose size is non-zero will actually
409 //! create a segment.
410 //!
411 //! In addition to this, ELF files that have been marked as being created by
412 //! the Green Hills Software toolset have an extra step. #SHT_NOBITS sections
413 //! are looked up in the .secinfo section to determine if they really
414 //! should be filled. If not in the .secinfo table, no segment will be
415 //! created for the section.
addSection(unsigned sectionIndex)416 void ELFSourceFile::ELFDataSource::addSection(unsigned sectionIndex)
417 {
418           // get section info
419           const Elf32_Shdr & section = m_elf->getSectionAtIndex(sectionIndex);
420           if (section.sh_size == 0)
421           {
422                     // empty section, so ignore it
423                     return;
424           }
425 
426           // create the right segment subclass based on the section type
427           DataSource::Segment * segment = NULL;
428           if (section.sh_type == SHT_PROGBITS)
429           {
430                     segment = new ProgBitsSegment(*this, m_elf, sectionIndex);
431           }
432           else if (section.sh_type == SHT_NOBITS)
433           {
434                     // Always add NOBITS sections by default.
435                     bool addNobits = true;
436 
437                     // For GHS ELF files, we use the secinfoClear option to figure out what to do.
438                     // If set to ignore, treat like a normal ELF file and always add. If set to
439                     // ROM, then only clear if the section is listed in .secinfo. Otherwise if set
440                     // to C startup, then let the C startup do all clearing.
441                     if (m_elf->ELFVariant() == eGHSVariant)
442                     {
443                               GHSSecInfo secinfo(m_elf);
444 
445                               // If there isn't a .secinfo section present then use the normal ELF rules
446                               // and always add NOBITS sections.
447                               if (secinfo.hasSecinfo() && m_secinfoOption != kSecinfoIgnore)
448                               {
449                                         switch (m_secinfoOption)
450                                         {
451                                                   case kSecinfoROMClear:
452                                                             addNobits = secinfo.isSectionFilled(section);
453                                                             break;
454 
455                                                   case kSecinfoCStartupClear:
456                                                             addNobits = false;
457                                                             break;
458                                         }
459                               }
460                     }
461 
462                     if (addNobits)
463                     {
464                               segment = new NoBitsSegment(*this, m_elf, sectionIndex);
465                     }
466                     else
467                     {
468                               std::string name = m_elf->getSectionNameAtIndex(section.sh_name);
469                               Log::log(Logger::DEBUG2, "..section %s is not filled\n", name.c_str());
470                     }
471           }
472 
473           // add segment if one was created
474           if (segment)
475           {
476                     m_segments.push_back(segment);
477           }
478 }
479 
ProgBitsSegment(ELFDataSource & source,StELFFile * elf,unsigned index)480 ELFSourceFile::ELFDataSource::ProgBitsSegment::ProgBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
481 :         DataSource::Segment(source), m_elf(elf), m_sectionIndex(index)
482 {
483 }
484 
getData(unsigned offset,unsigned maxBytes,uint8_t * buffer)485 unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
486 {
487           const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
488           uint8_t * data = m_elf->getSectionDataAtIndex(m_sectionIndex);
489 
490           assert(offset < section.sh_size);
491 
492           unsigned copyBytes = std::min<unsigned>(section.sh_size - offset, maxBytes);
493           if (copyBytes)
494           {
495                     memcpy(buffer, &data[offset], copyBytes);
496           }
497 
498           return copyBytes;
499 }
500 
getLength()501 unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getLength()
502 {
503           const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
504           return section.sh_size;
505 }
506 
getBaseAddress()507 uint32_t ELFSourceFile::ELFDataSource::ProgBitsSegment::getBaseAddress()
508 {
509           const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
510           return section.sh_addr;
511 }
512 
NoBitsSegment(ELFDataSource & source,StELFFile * elf,unsigned index)513 ELFSourceFile::ELFDataSource::NoBitsSegment::NoBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
514 :         DataSource::PatternSegment(source), m_elf(elf), m_sectionIndex(index)
515 {
516 }
517 
getLength()518 unsigned ELFSourceFile::ELFDataSource::NoBitsSegment::getLength()
519 {
520           const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
521           return section.sh_size;
522 }
523 
getBaseAddress()524 uint32_t ELFSourceFile::ELFDataSource::NoBitsSegment::getBaseAddress()
525 {
526           const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
527           return section.sh_addr;
528 }
529 
530