LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - DbiStreamBuilder.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 211 214 98.6 %
Date: 2018-10-20 13:21:21 Functions: 35 36 97.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
      11             : 
      12             : #include "llvm/ADT/ArrayRef.h"
      13             : #include "llvm/BinaryFormat/COFF.h"
      14             : #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
      15             : #include "llvm/DebugInfo/MSF/MSFBuilder.h"
      16             : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
      17             : #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
      18             : #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
      19             : #include "llvm/DebugInfo/PDB/Native/RawError.h"
      20             : #include "llvm/Object/COFF.h"
      21             : #include "llvm/Support/BinaryStreamWriter.h"
      22             : 
      23             : using namespace llvm;
      24             : using namespace llvm::codeview;
      25             : using namespace llvm::msf;
      26             : using namespace llvm::pdb;
      27             : 
      28         108 : DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
      29         108 :     : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
      30             :       PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
      31         216 :       Header(nullptr) {}
      32             : 
      33         324 : DbiStreamBuilder::~DbiStreamBuilder() {}
      34             : 
      35         108 : void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
      36             : 
      37         108 : void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
      38             : 
      39          20 : void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
      40             : 
      41          88 : void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) {
      42          88 :   BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) &
      43             :                 DbiBuildNo::BuildMajorMask;
      44          88 :   BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) &
      45             :                  DbiBuildNo::BuildMinorMask;
      46          88 :   BuildNumber |= DbiBuildNo::NewVersionFormatMask;
      47          88 : }
      48             : 
      49          20 : void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
      50             : 
      51          20 : void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
      52             : 
      53          20 : void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
      54             : 
      55          20 : void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
      56             : 
      57          88 : void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) {
      58             :   // These enums are mirrors of each other, so we can just cast the value.
      59          88 :   MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M));
      60          88 : }
      61             : 
      62          88 : void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) {
      63          88 :   SectionMap = SecMap;
      64          88 : }
      65             : 
      66          88 : void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
      67          88 :   GlobalsStreamIndex = Index;
      68          88 : }
      69             : 
      70          88 : void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
      71          88 :   SymRecordStreamIndex = Index;
      72          88 : }
      73             : 
      74          88 : void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) {
      75          88 :   PublicsStreamIndex = Index;
      76          88 : }
      77             : 
      78          38 : void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) {
      79          38 :   if (!NewFpoData.hasValue())
      80             :     NewFpoData.emplace(false);
      81             : 
      82          38 :   NewFpoData->addFrameData(FD);
      83          38 : }
      84             : 
      85           1 : void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) {
      86           1 :   OldFpoData.push_back(FD);
      87           1 : }
      88             : 
      89          88 : Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
      90             :                                      ArrayRef<uint8_t> Data) {
      91             :   assert(Type != DbgHeaderType::NewFPO &&
      92             :          "NewFPO data should be written via addFrameData()!");
      93             : 
      94          88 :   DbgStreams[(int)Type].emplace();
      95          88 :   DbgStreams[(int)Type]->Size = Data.size();
      96             :   DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) {
      97          88 :     return Writer.writeArray(Data);
      98          88 :   };
      99          88 :   return Error::success();
     100             : }
     101             : 
     102          88 : uint32_t DbiStreamBuilder::addECName(StringRef Name) {
     103          88 :   return ECNamesBuilder.insert(Name);
     104             : }
     105             : 
     106         108 : uint32_t DbiStreamBuilder::calculateSerializedLength() const {
     107             :   // For now we only support serializing the header.
     108         108 :   return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
     109         108 :          calculateModiSubstreamSize() + calculateSectionContribsStreamSize() +
     110         108 :          calculateSectionMapStreamSize() + calculateDbgStreamsSize() +
     111         108 :          ECNamesBuilder.calculateSerializedSize();
     112             : }
     113             : 
     114             : Expected<DbiModuleDescriptorBuilder &>
     115         219 : DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
     116         219 :   uint32_t Index = ModiList.size();
     117         219 :   ModiList.push_back(
     118         438 :       llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf));
     119         219 :   return *ModiList.back();
     120             : }
     121             : 
     122          68 : Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module,
     123             :                                             StringRef File) {
     124          68 :   uint32_t Index = SourceFileNames.size();
     125          68 :   SourceFileNames.insert(std::make_pair(File, Index));
     126          68 :   Module.addSourceFile(File);
     127          68 :   return Error::success();
     128             : }
     129             : 
     130           0 : Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) {
     131           0 :   auto NameIter = SourceFileNames.find(File);
     132           0 :   if (NameIter == SourceFileNames.end())
     133             :     return make_error<RawError>(raw_error_code::no_entry,
     134             :                                 "The specified source file was not found");
     135             :   return NameIter->getValue();
     136             : }
     137             : 
     138         216 : uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
     139             :   uint32_t Size = 0;
     140         654 :   for (const auto &M : ModiList)
     141         438 :     Size += M->calculateSerializedLength();
     142         216 :   return Size;
     143             : }
     144             : 
     145         216 : uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
     146         216 :   if (SectionContribs.empty())
     147             :     return 0;
     148         176 :   return sizeof(enum PdbRaw_DbiSecContribVer) +
     149         176 :          sizeof(SectionContribs[0]) * SectionContribs.size();
     150             : }
     151             : 
     152         216 : uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const {
     153         216 :   if (SectionMap.empty())
     154             :     return 0;
     155         176 :   return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size();
     156             : }
     157             : 
     158         324 : uint32_t DbiStreamBuilder::calculateNamesOffset() const {
     159             :   uint32_t Offset = 0;
     160             :   Offset += sizeof(ulittle16_t);                         // NumModules
     161             :   Offset += sizeof(ulittle16_t);                         // NumSourceFiles
     162         324 :   Offset += ModiList.size() * sizeof(ulittle16_t);       // ModIndices
     163         324 :   Offset += ModiList.size() * sizeof(ulittle16_t);       // ModFileCounts
     164             :   uint32_t NumFileInfos = 0;
     165         981 :   for (const auto &M : ModiList)
     166         657 :     NumFileInfos += M->source_files().size();
     167         324 :   Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
     168         324 :   return Offset;
     169             : }
     170             : 
     171         216 : uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
     172         216 :   uint32_t Size = calculateNamesOffset();
     173         216 :   Size += calculateNamesBufferSize();
     174         432 :   return alignTo(Size, sizeof(uint32_t));
     175             : }
     176             : 
     177         216 : uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
     178             :   uint32_t Size = 0;
     179         564 :   for (const auto &F : SourceFileNames) {
     180         132 :     Size += F.getKeyLength() + 1; // Names[I];
     181             :   }
     182         216 :   return Size;
     183             : }
     184             : 
     185         108 : uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
     186         108 :   return DbgStreams.size() * sizeof(uint16_t);
     187             : }
     188             : 
     189         108 : Error DbiStreamBuilder::generateFileInfoSubstream() {
     190         108 :   uint32_t Size = calculateFileInfoSubstreamSize();
     191         108 :   auto Data = Allocator.Allocate<uint8_t>(Size);
     192         108 :   uint32_t NamesOffset = calculateNamesOffset();
     193             : 
     194         108 :   FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
     195             :                                            llvm::support::little);
     196             : 
     197             :   WritableBinaryStreamRef MetadataBuffer =
     198         216 :       WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
     199         108 :   BinaryStreamWriter MetadataWriter(MetadataBuffer);
     200             : 
     201         216 :   uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
     202         108 :   uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
     203         216 :   if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
     204             :     return EC;
     205         216 :   if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
     206             :     return EC;
     207         327 :   for (uint16_t I = 0; I < ModiCount; ++I) {
     208         438 :     if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
     209             :       return EC;
     210             :   }
     211         327 :   for (const auto &MI : ModiList) {
     212         219 :     FileCount = static_cast<uint16_t>(MI->source_files().size());
     213         438 :     if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
     214             :       return EC;
     215             :   }
     216             : 
     217             :   // Before writing the FileNameOffsets array, write the NamesBuffer array.
     218             :   // A side effect of this is that this will actually compute the various
     219             :   // file name offsets, so we can then go back and write the FileNameOffsets
     220             :   // array to the other substream.
     221         216 :   NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset);
     222         108 :   BinaryStreamWriter NameBufferWriter(NamesBuffer);
     223         282 :   for (auto &Name : SourceFileNames) {
     224          66 :     Name.second = NameBufferWriter.getOffset();
     225         132 :     if (auto EC = NameBufferWriter.writeCString(Name.getKey()))
     226             :       return EC;
     227             :   }
     228             : 
     229         327 :   for (const auto &MI : ModiList) {
     230         287 :     for (StringRef Name : MI->source_files()) {
     231          68 :       auto Result = SourceFileNames.find(Name);
     232         136 :       if (Result == SourceFileNames.end())
     233             :         return make_error<RawError>(raw_error_code::no_entry,
     234             :                                     "The source file was not found.");
     235         136 :       if (auto EC = MetadataWriter.writeInteger(Result->second))
     236             :         return EC;
     237             :     }
     238             :   }
     239             : 
     240         216 :   if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t)))
     241             :     return EC;
     242             : 
     243         108 :   if (NameBufferWriter.bytesRemaining() > 0)
     244             :     return make_error<RawError>(raw_error_code::invalid_format,
     245             :                                 "The names buffer contained unexpected data.");
     246             : 
     247         108 :   if (MetadataWriter.bytesRemaining() > sizeof(uint32_t))
     248             :     return make_error<RawError>(
     249             :         raw_error_code::invalid_format,
     250             :         "The metadata buffer contained unexpected data.");
     251             : 
     252             :   return Error::success();
     253             : }
     254             : 
     255         108 : Error DbiStreamBuilder::finalize() {
     256         108 :   if (Header)
     257             :     return Error::success();
     258             : 
     259         327 :   for (auto &MI : ModiList)
     260         219 :     MI->finalize();
     261             : 
     262         216 :   if (auto EC = generateFileInfoSubstream())
     263             :     return EC;
     264             : 
     265         108 :   DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
     266         108 :   ::memset(H, 0, sizeof(DbiStreamHeader));
     267         108 :   H->VersionHeader = *VerHeader;
     268             :   H->VersionSignature = -1;
     269         108 :   H->Age = Age;
     270         108 :   H->BuildNumber = BuildNumber;
     271         108 :   H->Flags = Flags;
     272         108 :   H->PdbDllRbld = PdbDllRbld;
     273         108 :   H->PdbDllVersion = PdbDllVersion;
     274         108 :   H->MachineType = static_cast<uint16_t>(MachineType);
     275             : 
     276         108 :   H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize();
     277             :   H->FileInfoSize = FileInfoBuffer.getLength();
     278         108 :   H->ModiSubstreamSize = calculateModiSubstreamSize();
     279             :   H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
     280         108 :   H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
     281         108 :   H->SectionMapSize = calculateSectionMapStreamSize();
     282             :   H->TypeServerSize = 0;
     283         108 :   H->SymRecordStreamIndex = SymRecordStreamIndex;
     284         108 :   H->PublicSymbolStreamIndex = PublicsStreamIndex;
     285             :   H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0.
     286         108 :   H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
     287             : 
     288         108 :   Header = H;
     289             :   return Error::success();
     290             : }
     291             : 
     292         108 : Error DbiStreamBuilder::finalizeMsfLayout() {
     293         108 :   if (NewFpoData.hasValue()) {
     294             :     DbgStreams[(int)DbgHeaderType::NewFPO].emplace();
     295           5 :     DbgStreams[(int)DbgHeaderType::NewFPO]->Size =
     296           5 :         NewFpoData->calculateSerializedSize();
     297             :     DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn =
     298             :         [this](BinaryStreamWriter &Writer) {
     299           5 :           return NewFpoData->commit(Writer);
     300           5 :         };
     301             :   }
     302             : 
     303         108 :   if (!OldFpoData.empty()) {
     304             :     DbgStreams[(int)DbgHeaderType::FPO].emplace();
     305           1 :     DbgStreams[(int)DbgHeaderType::FPO]->Size =
     306           1 :         sizeof(object::FpoData) * OldFpoData.size();
     307             :     DbgStreams[(int)DbgHeaderType::FPO]->WriteFn =
     308             :         [this](BinaryStreamWriter &Writer) {
     309           1 :           return Writer.writeArray(makeArrayRef(OldFpoData));
     310           1 :         };
     311             :   }
     312             : 
     313        1296 :   for (auto &S : DbgStreams) {
     314        1188 :     if (!S.hasValue())
     315        1094 :       continue;
     316          94 :     auto ExpectedIndex = Msf.addStream(S->Size);
     317          94 :     if (!ExpectedIndex)
     318             :       return ExpectedIndex.takeError();
     319          94 :     S->StreamNumber = *ExpectedIndex;
     320             :   }
     321             : 
     322         327 :   for (auto &MI : ModiList) {
     323         438 :     if (auto EC = MI->finalizeMsfLayout())
     324             :       return EC;
     325             :   }
     326             : 
     327         108 :   uint32_t Length = calculateSerializedLength();
     328         216 :   if (auto EC = Msf.setStreamSize(StreamDBI, Length))
     329             :     return EC;
     330             :   return Error::success();
     331             : }
     332             : 
     333         223 : static uint16_t toSecMapFlags(uint32_t Flags) {
     334             :   uint16_t Ret = 0;
     335         223 :   if (Flags & COFF::IMAGE_SCN_MEM_READ)
     336             :     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read);
     337         223 :   if (Flags & COFF::IMAGE_SCN_MEM_WRITE)
     338          12 :     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write);
     339         223 :   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
     340          86 :     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
     341         223 :   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
     342          86 :     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
     343         223 :   if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT))
     344         223 :     Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit);
     345             : 
     346             :   // This seems always 1.
     347         223 :   Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector);
     348             : 
     349         223 :   return Ret;
     350             : }
     351             : 
     352             : // A utility function to create a Section Map for a given list of COFF sections.
     353             : //
     354             : // A Section Map seem to be a copy of a COFF section list in other format.
     355             : // I don't know why a PDB file contains both a COFF section header and
     356             : // a Section Map, but it seems it must be present in a PDB.
     357          88 : std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap(
     358             :     ArrayRef<llvm::object::coff_section> SecHdrs) {
     359             :   std::vector<SecMapEntry> Ret;
     360          88 :   int Idx = 0;
     361             : 
     362             :   auto Add = [&]() -> SecMapEntry & {
     363             :     Ret.emplace_back();
     364             :     auto &Entry = Ret.back();
     365             :     memset(&Entry, 0, sizeof(Entry));
     366             : 
     367             :     Entry.Frame = Idx + 1;
     368             : 
     369             :     // We don't know the meaning of these fields yet.
     370             :     Entry.SecName = UINT16_MAX;
     371             :     Entry.ClassName = UINT16_MAX;
     372             : 
     373             :     return Entry;
     374          88 :   };
     375             : 
     376         311 :   for (auto &Hdr : SecHdrs) {
     377         223 :     auto &Entry = Add();
     378         223 :     Entry.Flags = toSecMapFlags(Hdr.Characteristics);
     379         223 :     Entry.SecByteLength = Hdr.VirtualSize;
     380         223 :     ++Idx;
     381             :   }
     382             : 
     383             :   // The last entry is for absolute symbols.
     384          88 :   auto &Entry = Add();
     385             :   Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) |
     386             :                 static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress);
     387             :   Entry.SecByteLength = UINT32_MAX;
     388             : 
     389          88 :   return Ret;
     390             : }
     391             : 
     392         108 : Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
     393             :                                WritableBinaryStreamRef MsfBuffer) {
     394         216 :   if (auto EC = finalize())
     395             :     return EC;
     396             : 
     397             :   auto DbiS = WritableMappedBlockStream::createIndexedStream(
     398         324 :       Layout, MsfBuffer, StreamDBI, Allocator);
     399             : 
     400         108 :   BinaryStreamWriter Writer(*DbiS);
     401         216 :   if (auto EC = Writer.writeObject(*Header))
     402             :     return EC;
     403             : 
     404         327 :   for (auto &M : ModiList) {
     405         438 :     if (auto EC = M->commit(Writer, Layout, MsfBuffer))
     406             :       return EC;
     407             :   }
     408             : 
     409         108 :   if (!SectionContribs.empty()) {
     410          88 :     if (auto EC = Writer.writeEnum(DbiSecContribVer60))
     411             :       return EC;
     412         176 :     if (auto EC = Writer.writeArray(makeArrayRef(SectionContribs)))
     413             :       return EC;
     414             :   }
     415             : 
     416         108 :   if (!SectionMap.empty()) {
     417          88 :     ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size());
     418          88 :     SecMapHeader SMHeader = {Size, Size};
     419          88 :     if (auto EC = Writer.writeObject(SMHeader))
     420             :       return EC;
     421         176 :     if (auto EC = Writer.writeArray(SectionMap))
     422             :       return EC;
     423             :   }
     424             : 
     425         216 :   if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
     426             :     return EC;
     427             : 
     428         216 :   if (auto EC = ECNamesBuilder.commit(Writer))
     429             :     return EC;
     430             : 
     431        1296 :   for (auto &Stream : DbgStreams) {
     432             :     uint16_t StreamNumber = kInvalidStreamIndex;
     433        1188 :     if (Stream.hasValue())
     434          94 :       StreamNumber = Stream->StreamNumber;
     435        2376 :     if (auto EC = Writer.writeInteger(StreamNumber))
     436             :       return EC;
     437             :   }
     438             : 
     439        1296 :   for (auto &Stream : DbgStreams) {
     440        1188 :     if (!Stream.hasValue())
     441        1094 :       continue;
     442             :     assert(Stream->StreamNumber != kInvalidStreamIndex);
     443             : 
     444             :     auto WritableStream = WritableMappedBlockStream::createIndexedStream(
     445         282 :         Layout, MsfBuffer, Stream->StreamNumber, Allocator);
     446          94 :     BinaryStreamWriter DbgStreamWriter(*WritableStream);
     447             : 
     448          94 :     if (auto EC = Stream->WriteFn(DbgStreamWriter))
     449             :       return EC;
     450             :   }
     451             : 
     452         108 :   if (Writer.bytesRemaining() > 0)
     453             :     return make_error<RawError>(raw_error_code::invalid_format,
     454             :                                 "Unexpected bytes found in DBI Stream");
     455             :   return Error::success();
     456             : }

Generated by: LCOV version 1.13