]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/elftosb/common/ELFSourceFile.cpp
merged tx6dl-devel into denx master branch
[karo-tx-uboot.git] / tools / elftosb / common / ELFSourceFile.cpp
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
31 ELFSourceFile::ELFSourceFile(const std::string & path)
32 :       SourceFile(path),
33         m_toolset(kUnknownToolset),
34         m_secinfoOption(kSecinfoDefault)
35 {
36 }
37
38 ELFSourceFile::~ELFSourceFile()
39 {
40 }
41
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
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
90 void ELFSourceFile::close()
91 {
92         SourceFile::close();
93         
94         m_file.safe_delete();
95 }
96
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.
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&).
191 DataSource * ELFSourceFile::createDataSource()
192 {
193         WildcardMatcher matcher;
194         return createDataSource(matcher);
195 }
196         
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                 switch (header.sh_type) {
214                 case SHT_PROGBITS:
215                 case SHT_NOBITS:
216                 case SHT_REL:
217                 case SHT_DYNSYM:
218                         break;
219
220                 default:
221                         continue;
222                 }
223
224                 // Ignore sections that don't have the allocate flag set.
225                 if ((header.sh_flags & SHF_ALLOC) == 0)
226                 {
227                         continue;
228                 }
229
230                 if (matcher.match(name))
231                 {
232                         Log::log(Logger::DEBUG2, "creating segment for section %s\n", name.c_str());
233                         source->addSection(index);
234                 }
235                 else
236                 {
237                         Log::log(Logger::DEBUG2, "section %s did not match\n", name.c_str());
238                 }
239         }
240         
241         return source;
242 }
243
244 //! It is assumed that all ELF files have an entry point.
245 //!
246 bool ELFSourceFile::hasEntryPoint()
247 {
248         return true;
249 }
250
251 //! The StELFFile::getTypeOfSymbolAtIndex() method uses different methods of determining
252 //! ARM/Thumb mode depending on the toolset.
253 uint32_t ELFSourceFile::getEntryPointAddress()
254 {
255         uint32_t entryPoint = 0;
256         
257         // get entry point address
258         const Elf32_Ehdr & header = m_file->getFileHeader();
259
260         // find symbol corresponding to entry point and determine if
261         // it is arm or thumb mode
262         unsigned symbolIndex = m_file->getIndexOfSymbolAtAddress(header.e_entry);
263         if (symbolIndex != 0)
264         {
265                 ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(symbolIndex);
266                 bool entryPointIsThumb = (symbolType == eThumbSymbol);
267                 const Elf32_Sym & symbol = m_file->getSymbolAtIndex(symbolIndex);
268                 std::string symbolName = m_file->getSymbolName(symbol);
269
270                 Log::log(Logger::DEBUG2, "Entry point is %s@0x%08x (%s)\n", symbolName.c_str(), symbol.st_value, entryPointIsThumb ? "Thumb" : "ARM");
271
272                 // set entry point, setting the low bit if it is thumb mode
273                 entryPoint = header.e_entry + (entryPointIsThumb ? 1 : 0);
274         }
275         else
276         {
277                 entryPoint = header.e_entry;
278         }
279         
280         return entryPoint;
281 }
282
283 //! \return A DataTarget that describes the named section.
284 //! \retval NULL There was no section with the requested name.
285 DataTarget * ELFSourceFile::createDataTargetForSection(const std::string & section)
286 {
287         assert(m_file);
288         unsigned index = m_file->getIndexOfSectionWithName(section);
289         if (index == SHN_UNDEF)
290         {
291                 return NULL;
292         }
293         
294         const Elf32_Shdr & sectionHeader = m_file->getSectionAtIndex(index);
295         uint32_t beginAddress = sectionHeader.sh_addr;
296         uint32_t endAddress = beginAddress + sectionHeader.sh_size;
297         ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
298         return target;
299 }
300
301 //! \return A DataTarget instance pointing at the requested symbol.
302 //! \retval NULL No symbol matching the requested name was found.
303 DataTarget * ELFSourceFile::createDataTargetForSymbol(const std::string & symbol)
304 {
305         assert(m_file);
306         unsigned symbolCount = m_file->getSymbolCount();
307         unsigned i;
308         
309         for (i=0; i < symbolCount; ++i)
310         {
311                 const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
312                 std::string symbolName = m_file->getSymbolName(symbolHeader);
313                 if (symbolName == symbol)
314                 {
315             ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
316             bool symbolIsThumb = (symbolType == eThumbSymbol);
317             
318                         uint32_t beginAddress = symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
319                         uint32_t endAddress = beginAddress + symbolHeader.st_size;
320                         ConstantDataTarget * target = new ConstantDataTarget(beginAddress, endAddress);
321                         return target;
322                 }
323         }
324         
325         // didn't find a matching symbol
326         return NULL; 
327 }
328
329 bool ELFSourceFile::hasSymbol(const std::string & name)
330 {
331         Elf32_Sym symbol;
332         return lookupSymbol(name, symbol);
333 }
334
335 uint32_t ELFSourceFile::getSymbolValue(const std::string & name)
336 {
337         unsigned symbolCount = m_file->getSymbolCount();
338         unsigned i;
339         
340         for (i=0; i < symbolCount; ++i)
341         {
342                 const Elf32_Sym & symbolHeader = m_file->getSymbolAtIndex(i);
343                 std::string symbolName = m_file->getSymbolName(symbolHeader);
344                 if (symbolName == name)
345                 {
346             // If the symbol is a function, then we check to see if it is Thumb code and set bit 0 if so.
347             if (ELF32_ST_TYPE(symbolHeader.st_info) == STT_FUNC)
348             {
349                 ARMSymbolType_t symbolType = m_file->getTypeOfSymbolAtIndex(i);
350                 bool symbolIsThumb = (symbolType == eThumbSymbol);
351                 return symbolHeader.st_value + (symbolIsThumb ? 1 : 0);
352             }
353             else
354             {
355                             return symbolHeader.st_value;
356             }
357                 }
358         }
359         
360     // Couldn't find the symbol, so return 0.
361         return 0;
362 }
363
364 unsigned ELFSourceFile::getSymbolSize(const std::string & name)
365 {
366         Elf32_Sym symbol;
367         if (!lookupSymbol(name, symbol))
368         {
369                 return 0;
370         }
371         
372         return symbol.st_size;
373 }
374
375 //! \param name The name of the symbol on which info is wanted.
376 //! \param[out] info Upon succssful return this is filled in with the symbol's information.
377 //!
378 //! \retval true The symbol was found and \a info is valid.
379 //! \retval false No symbol with \a name was found in the file.
380 bool ELFSourceFile::lookupSymbol(const std::string & name, Elf32_Sym & info)
381 {
382         assert(m_file);
383         unsigned symbolCount = m_file->getSymbolCount();
384         unsigned i;
385         
386         for (i=0; i < symbolCount; ++i)
387         {
388                 const Elf32_Sym & symbol = m_file->getSymbolAtIndex(i);
389                 std::string thisSymbolName = m_file->getSymbolName(symbol);
390                 
391                 // Is this the symbol we're looking for?
392                 if (thisSymbolName == name)
393                 {
394                         info = symbol;
395                         return true;
396                 }
397         }
398         
399         // Didn't file the symbol.
400         return false;
401 }
402
403 ELFSourceFile::ELFDataSource::~ELFDataSource()
404 {
405         segment_vector_t::iterator it = m_segments.begin();
406         for (; it != m_segments.end(); ++it)
407         {
408                 delete *it;
409         }
410 }
411
412 //! Not all sections will actually result in a new segment being created. Only
413 //! those sections whose type is #SHT_PROGBITS or #SHT_NOBITS will create
414 //! a new segment. Also, only sections whose size is non-zero will actually
415 //! create a segment.
416 //!
417 //! In addition to this, ELF files that have been marked as being created by
418 //! the Green Hills Software toolset have an extra step. #SHT_NOBITS sections
419 //! are looked up in the .secinfo section to determine if they really
420 //! should be filled. If not in the .secinfo table, no segment will be
421 //! created for the section.
422 void ELFSourceFile::ELFDataSource::addSection(unsigned sectionIndex)
423 {
424         // get section info
425         const Elf32_Shdr & section = m_elf->getSectionAtIndex(sectionIndex);
426         if (section.sh_size == 0)
427         {
428                 // empty section, so ignore it
429                 return;
430         }
431         
432         // create the right segment subclass based on the section type
433         DataSource::Segment * segment = NULL;
434         switch (section.sh_type) {
435         case SHT_PROGBITS:
436         case SHT_REL:
437         case SHT_DYNSYM:
438                 segment = new ProgBitsSegment(*this, m_elf, sectionIndex);
439                 break;
440
441         case SHT_NOBITS:
442         {
443                 // Always add NOBITS sections by default.
444                 bool addNobits = true;
445
446                 // For GHS ELF files, we use the secinfoClear option to figure out what to do.
447                 // If set to ignore, treat like a normal ELF file and always add. If set to
448                 // ROM, then only clear if the section is listed in .secinfo. Otherwise if set
449                 // to C startup, then let the C startup do all clearing.
450                 addNobits = false;
451                 if (m_elf->ELFVariant() == eGHSVariant)
452                 {
453                         GHSSecInfo secinfo(m_elf);
454
455                         // If there isn't a .secinfo section present then use the normal ELF rules
456                         // and always add NOBITS sections.
457                         if (secinfo.hasSecinfo() && m_secinfoOption != kSecinfoIgnore)
458                         {
459                                 switch (m_secinfoOption)
460                                 {
461                                         case kSecinfoROMClear:
462                                                 addNobits = secinfo.isSectionFilled(section);
463                                                 break;
464
465                                         case kSecinfoCStartupClear:
466                                                 addNobits = false;
467                                                 break;
468                                 }
469                         }
470                 }
471
472                 if (addNobits)
473                 {
474                         segment = new NoBitsSegment(*this, m_elf, sectionIndex);
475                 }
476                 else
477                 {
478                         std::string name = m_elf->getSectionNameAtIndex(section.sh_name);
479                         Log::log(Logger::DEBUG2, "..section %s is not filled\n", name.c_str());
480                 }
481         }
482         break;
483         }
484         // add segment if one was created
485         if (segment)
486         {
487                 m_segments.push_back(segment);
488         }
489 }
490
491 ELFSourceFile::ELFDataSource::ProgBitsSegment::ProgBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
492 :       DataSource::Segment(source), m_elf(elf), m_sectionIndex(index)
493 {
494 }
495
496 unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)
497 {
498         const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
499         uint8_t * data = m_elf->getSectionDataAtIndex(m_sectionIndex);
500         
501         assert(offset < section.sh_size);
502         
503         unsigned copyBytes = std::min<unsigned>(section.sh_size - offset, maxBytes);
504         if (copyBytes)
505         {
506                 memcpy(buffer, &data[offset], copyBytes);
507         }
508         
509         return copyBytes;
510 }
511
512 unsigned ELFSourceFile::ELFDataSource::ProgBitsSegment::getLength()
513 {
514         const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
515         return section.sh_size;
516 }
517
518 uint32_t ELFSourceFile::ELFDataSource::ProgBitsSegment::getBaseAddress()
519 {
520         const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
521         return section.sh_addr;
522 }
523
524 ELFSourceFile::ELFDataSource::NoBitsSegment::NoBitsSegment(ELFDataSource & source, StELFFile * elf, unsigned index)
525 :       DataSource::PatternSegment(source), m_elf(elf), m_sectionIndex(index)
526 {
527 }
528
529 unsigned ELFSourceFile::ELFDataSource::NoBitsSegment::getLength()
530 {
531         const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
532         return section.sh_size;
533 }
534
535 uint32_t ELFSourceFile::ELFDataSource::NoBitsSegment::getBaseAddress()
536 {
537         const Elf32_Shdr & section = m_elf->getSectionAtIndex(m_sectionIndex);
538         return section.sh_addr;
539 }
540