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