diff -r 1af5c1be89f8 -r 92d87f2e53c2 tools/elf4rom/src/dwarfmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/elf4rom/src/dwarfmanager.cpp Fri Jan 15 09:07:44 2010 +0000 @@ -0,0 +1,436 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*/ + +#include +#include + +#include "dwarfmanager.h" +#include "inputfile.h" +#include "outputfile.h" +#include "filefragment.h" + +void DwarfSectionManager::AddSection(XIPFileDetails & aXIPFileDetails, Elf32_Shdr * aShdr){ + if (iRomDetails->iTrace){ + cout << " " << GetSectionName() << " - DWARF\n"; + } + + FileShdrPair aFileShdrPair(aXIPFileDetails, aShdr); + iFileShdrList.push_back(aFileShdrPair); +} + +void DwarfSectionManager::SetupSection(){ + if (!iFileShdrList.empty()){ + ElfSectionElfData * aDwarfSectionData = new ElfSectionElfData(*this); + Elf32_Shdr aDwarfShdr; + aDwarfShdr.sh_name = 0; // for now. + aDwarfShdr.sh_type = SHT_PROGBITS; + aDwarfShdr.sh_flags = 0; + aDwarfShdr.sh_addr = 0; + aDwarfShdr.sh_offset = 0; // for now + aDwarfShdr.sh_size = 0; // for now. + aDwarfShdr.sh_link = 0; + aDwarfShdr.sh_info = 0; + aDwarfShdr.sh_addralign = 4; + aDwarfShdr.sh_entsize = sizeof(Elf32_Sym); + + ElfSection aDwarfSection(aDwarfSectionData, GetSectionName().c_str(), aDwarfShdr); + iElfSectionManager.AddSection(aDwarfSection); + } +} + +Dwarf_Unsigned DwarfSectionManager::DecodeUnsignedLeb128(Dwarf_Byte_Ptr leb128, size_t & leb128_length){ + Dwarf_Ubyte byte; + Dwarf_Word word_number; + Dwarf_Unsigned number; + Dwarf_Sword shift; + Dwarf_Sword byte_length; + + /* The following unrolls-the-loop for the first few bytes and + unpacks into 32 bits to make this as fast as possible. + word_number is assumed big enough that the shift has a defined + result. */ + if ((*leb128 & 0x80) == 0) { + leb128_length = 1; + return *leb128; + } else if ((*(leb128 + 1) & 0x80) == 0) { + leb128_length = 2; + + word_number = *leb128 & 0x7f; + word_number |= (*(leb128 + 1) & 0x7f) << 7; + return word_number; + } else if ((*(leb128 + 2) & 0x80) == 0) { + leb128_length = 3; + + word_number = *leb128 & 0x7f; + word_number |= (*(leb128 + 1) & 0x7f) << 7; + word_number |= (*(leb128 + 2) & 0x7f) << 14; + return word_number; + } else if ((*(leb128 + 3) & 0x80) == 0) { + leb128_length = 4; + + word_number = *leb128 & 0x7f; + word_number |= (*(leb128 + 1) & 0x7f) << 7; + word_number |= (*(leb128 + 2) & 0x7f) << 14; + word_number |= (*(leb128 + 3) & 0x7f) << 21; + return word_number; + } + + /* The rest handles long numbers Because the 'number' may be larger + than the default int/unsigned, we must cast the 'byte' before + the shift for the shift to have a defined result. */ + number = 0; + shift = 0; + byte_length = 1; + byte = *(leb128); + for (;;) { + number |= ((Dwarf_Unsigned) (byte & 0x7f)) << shift; + + if ((byte & 0x80) == 0) { + leb128_length = byte_length; + return number; + } + shift += 7; + + byte_length++; + ++leb128; + byte = *leb128; + } +} + +#define BITSINBYTE 8 +Dwarf_Signed DwarfSectionManager::DecodeSignedLeb128(Dwarf_Byte_Ptr leb128, size_t & leb128_length){ + Dwarf_Signed number = 0; + Dwarf_Bool sign = 0; + Dwarf_Word shift = 0; + Dwarf_Ubyte byte = *leb128; + Dwarf_Word byte_length = 1; + + /* byte_length being the number of bytes of data absorbed so far in + turning the leb into a Dwarf_Signed. */ + + for (;;) { + sign = byte & 0x40; + number |= ((Dwarf_Signed) ((byte & 0x7f))) << shift; + shift += 7; + + if ((byte & 0x80) == 0) { + break; + } + ++leb128; + byte = *leb128; + byte_length++; + } + + if ((shift < sizeof(Dwarf_Signed) * BITSINBYTE) && sign) { + number |= -((Dwarf_Signed) 1 << shift); + } + + leb128_length = byte_length; + return number; +} + +Dwarf_Byte_Ptr DwarfSectionManager::GetSectionData(FileShdrPair & aPair){ + + InputFile in(aPair.iXIPFileDetails.iElfFile); + in.SetOffset(aPair.iShdr.sh_offset); + return (Dwarf_Byte_Ptr)in.GetData(aPair.iShdr.sh_size); +} + +void DwarfConcatenatedSectionManager::GetFileFragmentData(FileFragmentData & aFileFragmentData ){ + ConcatenateData(); + if (iRomDetails->iTrace){ + cout << "\nGenerating DWARF section " << GetSectionName() << " size = " + << dec << Size() << " bytes\n"; + } + FileShdrList::iterator e = iFileShdrList.end(); + for (FileShdrList::iterator i = iFileShdrList.begin(); i < e; i++){ + if (iRomDetails->iTrace){ + cout << " " << i->iXIPFileDetails.iElfFile << " " << dec << i->iShdr.sh_size << " bytes\n" << flush; + } + ProcessSection(*i); + } + SetFileFragmentData(aFileFragmentData, iSize, reinterpret_cast(iData)); +} + +void DwarfConcatenatedSectionManager::ConcatenateData(){ + if (iData == NULL) { + size_t sectionSize = Size(); + iData = new Dwarf_Ubyte[sectionSize]; + Dwarf_Byte_Ptr p = iData; + FileShdrList::iterator e = iFileShdrList.end(); + for (FileShdrList::iterator i = iFileShdrList.begin(); i < e; i++){ + size_t off = p - iData; + size_t soff = GetSectionOffset(i->iXIPFileDetails.iElfFile); + if (off >= sectionSize) + assert(off < sectionSize); + if (off != soff) + assert(off == soff); + size_t n = i->iShdr.sh_size; + Dwarf_Byte_Ptr contrib = GetSectionData(*i); + memcpy(p, contrib, n); + p += n; + delete [] contrib; + } + } +} + +size_t DwarfConcatenatedSectionManager::Size(){ + if (iSizeValid) + return iSize; + //cerr << "Size for " << GetSectionName() << "\n"; + size_t offset = 0; + FileShdrList::iterator e = iFileShdrList.end(); + for (FileShdrList::iterator i = iFileShdrList.begin(); i != e; i++){ + //cerr << "offset = 0x" << offset << "\t"; + SetSectionOffset(i->iXIPFileDetails.iElfFile, offset); + size_t size = i->iShdr.sh_size; + //cerr << "section size for " << i->iXIPFileDetails.iElfFile << " 0x" << size << "\n"; + SetSectionSize(i->iXIPFileDetails.iElfFile, size); + size_t newOffset = offset + size; + if (newOffset < offset){ + cerr << "Error: The combined section " << GetSectionName() + << " requires translation from 32 to 64 bit Dwarf which is not currently supported.\n" + << "Exclude the following files (or their equivalent in terms of their contribution to Dwarf):\n"; + for (; i != e; i++){ + cerr << i->iXIPFileDetails.iE32File << "\n"; + } + exit(EXIT_FAILURE); + } + offset = newOffset; + } + //cerr << "Size = 0x" << offset << "\n"; + iSizeValid = true; + return iSize = offset; +} + +void DwarfConcatenatedSectionManager::ProcessSection(FileShdrPair & aPair){ + Dwarf_Byte_Ptr start = GetSection(aPair.iXIPFileDetails.iElfFile); + Dwarf_Byte_Ptr end = start + aPair.iShdr.sh_size; + ProcessSection(aPair, start, end); +} + +void DwarfConcatenatedSectionManager::SetSectionOffset(PathName & aPathName, size_t aOffset) { + iPathNameSectionOffsetMap[aPathName] = aOffset; +} + +void DwarfConcatenatedSectionManager::InitOffsetMap(){ + Size(); // forces the map to be set up if it hasn't been already +} + +size_t DwarfConcatenatedSectionManager::GetSectionOffset(PathName & aPathName){ + if (!iSizeValid) // if the size is valid then so must be the offsets. + InitOffsetMap(); + return iPathNameSectionOffsetMap[aPathName]; +} + +void DwarfConcatenatedSectionManager::SetSectionSize(PathName & aPathName, size_t aSize) { + iPathNameSectionSizeMap[aPathName] = aSize; +} + +size_t DwarfConcatenatedSectionManager::GetSectionSize(PathName & aPathName){ + if (!iSizeValid) // if the size is valid then so must be the offsets. + InitOffsetMap(); + return iPathNameSectionSizeMap[aPathName]; +} + +Dwarf_Byte_Ptr DwarfConcatenatedSectionManager::GetSection(PathName & aPathName){ + ConcatenateData(); + size_t offset = GetSectionOffset(aPathName); + return iData + offset; +} + +class ElfSectionFragmentedDwarfData : public ElfSectionElfData { +public: + ElfSectionFragmentedDwarfData(FileFragmentOwner & aSource) : + ElfSectionElfData(aSource) + {} + + ElfSectionFragmentedDwarfData(const ElfSectionElfData & aData) : + ElfSectionElfData(aData) + {} + + // ElfSection protocol + virtual ElfSectionFragmentedDwarfData * Clone(){ + return new ElfSectionFragmentedDwarfData(*this); + } + + virtual void AddData(OutputFile & aOutputFile){ + return; + } +}; + +class DwarfSectionFragment : public FileFragmentOwner { +public: + DwarfSectionFragment(DwarfFragmentedSectionManager & aSource, + FileShdrPair & aPair): + iSource(aSource), + iPair(aPair), + iData(NULL) + {} + + // Bitwise copy is OK so don't need to write our own copy ctor etc. + + // The FileFragmentOwner protocol + virtual void GetFileFragmentData(FileFragmentData & aFileFragmentData ); + virtual size_t Size(); + virtual void DeleteFileFragmentData(); + +private: + DwarfSectionFragment(); + +private: + DwarfFragmentedSectionManager & iSource; + FileShdrPair & iPair; + Dwarf_Byte_Ptr iData; +}; + +void DwarfSectionFragment::GetFileFragmentData(FileFragmentData & aFileFragmentData ){ + iSource.ProcessSection(iPair, iData); + SetFileFragmentData(aFileFragmentData, Size(), reinterpret_cast(iData)); +} + +size_t DwarfSectionFragment::Size(){ + return iPair.iShdr.sh_size; +} + +void DwarfSectionFragment::DeleteFileFragmentData(){ + delete [] iData; + // + delete this; +} + +void DwarfFragmentedSectionManager::SetupSection(){ + if (!iFileShdrList.empty()){ + ElfSectionFragmentedDwarfData * aDwarfSectionData = new ElfSectionFragmentedDwarfData(*this); + Elf32_Shdr aDwarfShdr; + aDwarfShdr.sh_name = 0; // for now. + aDwarfShdr.sh_type = SHT_PROGBITS; + aDwarfShdr.sh_flags = 0; + aDwarfShdr.sh_addr = 0; + aDwarfShdr.sh_offset = 0; // for now + aDwarfShdr.sh_size = 0; // for now. + aDwarfShdr.sh_link = 0; + aDwarfShdr.sh_info = 0; + aDwarfShdr.sh_addralign = 4; + aDwarfShdr.sh_entsize = sizeof(Elf32_Sym); + + // aDwarfSectionData will ask the secton manager (i.e. its source) for the offset of the section. + // So we better record it here. We assume that it is the current size of the output file. + // As long as we are single threaded and all the fragments get added consecutively as below + // this is a safe assumption. + SetOffset(iDwarfManager.GetOutputFile().Size()); + + ElfSection aDwarfSection(aDwarfSectionData, GetSectionName().c_str(), aDwarfShdr); + iElfSectionManager.AddSection(aDwarfSection); + + for (FileShdrList::iterator i = iFileShdrList.begin(); i < iFileShdrList.end(); i++ ){ + DwarfSectionFragment * aFrag = new DwarfSectionFragment(*this, *i); + aFrag->AddData(iDwarfManager.GetOutputFile()); + } + } +} + +// NB the section itself doesn't write any data +// The FileFragmentOwner protocol + +void DwarfFragmentedSectionManager::GetFileFragmentData(FileFragmentData & aFileFragmentData ){ + SetFileFragmentData(aFileFragmentData, 0, reinterpret_cast(NULL)); +} + +// This should never get called +void DwarfFragmentedSectionManager::ConcatenateData(){ + assert(1 == 0); + return; +} + +void DwarfFragmentedSectionManager::ProcessSection(FileShdrPair & aPair, Dwarf_Byte_Ptr & aData){ + if (iInitialTraceMessage & iRomDetails->iTrace){ + cout << "\nGenerating DWARF section " << GetSectionName() << " size = " + << dec << Size() << " bytes\n"; + iInitialTraceMessage = false; + } + if (iRomDetails->iTrace){ + cout << " " << aPair.iXIPFileDetails.iElfFile << " size = " + << dec << aPair.iShdr.sh_size << "\n" << flush; + } + Dwarf_Byte_Ptr start = GetSectionData(aPair); + aData = start; + Dwarf_Byte_Ptr end = start + aPair.iShdr.sh_size; + ProcessSection(aPair, start, end); +} + +#if 0 +// This should never get called +void DwarfFragmentedSectionManager::ProcessSection(FileShdrPair & aPair, Dwarf_Byte_Ptr start, Dwarf_Byte_Ptr end){ + assert(1 == 0); + return; +} +#endif + +const string DwarfMacinfoManager::iMacinfoSectionName(".debug_macinfo"); +const string DwarfStrManager::iStrSectionName(".debug_str"); + + +void DwarfManager::AddSection(XIPFileDetails & aXIPFileDetails, string aSectionName, Elf32_Shdr * aShdr){ + if (iDwarfAbbrevManager.GetSectionName() == aSectionName) + iDwarfAbbrevManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfArangesManager.GetSectionName() == aSectionName) + iDwarfArangesManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfFrameManager.GetSectionName() == aSectionName) + iDwarfFrameManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfInfoManager.GetSectionName() == aSectionName) + iDwarfInfoManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfLineManager.GetSectionName() == aSectionName) + iDwarfLineManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfLocManager.GetSectionName() == aSectionName) + iDwarfLocManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfMacinfoManager.GetSectionName() == aSectionName) + iDwarfMacinfoManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfPubnamesManager.GetSectionName() == aSectionName) + iDwarfPubnamesManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfPubtypesManager.GetSectionName() == aSectionName) + iDwarfPubtypesManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfRangesManager.GetSectionName() == aSectionName) + iDwarfRangesManager.AddSection(aXIPFileDetails, aShdr); + else if (iDwarfStrManager.GetSectionName() == aSectionName) + iDwarfStrManager.AddSection(aXIPFileDetails, aShdr); +#if 0 + else + cerr << "Warning: unrecognised debug section name " << aSectionName << " ignored\n"; +#endif +} + +void DwarfManager::SetupSections(){ + // The order here is important for fix up + // first the purely concatenated 'leaf' sections + // See the diagram on p.182 of the Dwarf 3 spec + // to understand the 'dependenices' + iDwarfAbbrevManager.SetupSection(); + iDwarfFrameManager.SetupSection(); + iDwarfPubnamesManager.SetupSection(); + iDwarfPubtypesManager.SetupSection(); + iDwarfArangesManager.SetupSection(); + iDwarfMacinfoManager.SetupSection(); + + iDwarfInfoManager.SetupSection(); + iDwarfLineManager.SetupSection(); + iDwarfLocManager.SetupSection(); + + iDwarfRangesManager.SetupSection(); + iDwarfStrManager.SetupSection(); +}