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