This provides a better layering of responsibilities among different aspects of PDB writing code. Some of the MSF related code was contained in CodeView, and some was in PDB prior to this. Further, we were often saying PDB when we meant MSF, and the two are actually independent of each other since in theory you can have other types of data besides PDB data in an MSF. So, this patch separates the MSF specific code into its own library, with no dependencies on anything else, and DebugInfoCodeView and DebugInfoPDB take dependencies on DebugInfoMsf. llvm-svn: 276458
240 lines
8.4 KiB
C++
240 lines
8.4 KiB
C++
//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
|
|
|
|
#include "llvm/DebugInfo/Msf/MappedBlockStream.h"
|
|
#include "llvm/DebugInfo/Msf/StreamWriter.h"
|
|
#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
|
|
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::codeview;
|
|
using namespace llvm::msf;
|
|
using namespace llvm::pdb;
|
|
|
|
namespace {
|
|
class ModiSubstreamBuilder {};
|
|
}
|
|
|
|
DbiStreamBuilder::DbiStreamBuilder(BumpPtrAllocator &Allocator)
|
|
: Allocator(Allocator), Age(1), BuildNumber(0), PdbDllVersion(0),
|
|
PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86) {}
|
|
|
|
void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
|
|
|
|
void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
|
|
|
|
void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
|
|
|
|
void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
|
|
|
|
void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
|
|
|
|
void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
|
|
|
|
void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
|
|
|
|
uint32_t DbiStreamBuilder::calculateSerializedLength() const {
|
|
// For now we only support serializing the header.
|
|
return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
|
|
calculateModiSubstreamSize();
|
|
}
|
|
|
|
Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
|
|
auto Entry = llvm::make_unique<ModuleInfo>();
|
|
ModuleInfo *M = Entry.get();
|
|
Entry->Mod = Module;
|
|
Entry->Obj = ObjFile;
|
|
auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
|
|
if (!Result.second)
|
|
return make_error<RawError>(raw_error_code::duplicate_entry,
|
|
"The specified module already exists");
|
|
ModuleInfoList.push_back(M);
|
|
return Error::success();
|
|
}
|
|
|
|
Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
|
|
auto ModIter = ModuleInfos.find(Module);
|
|
if (ModIter == ModuleInfos.end())
|
|
return make_error<RawError>(raw_error_code::no_entry,
|
|
"The specified module was not found");
|
|
uint32_t Index = SourceFileNames.size();
|
|
SourceFileNames.insert(std::make_pair(File, Index));
|
|
auto &ModEntry = *ModIter;
|
|
ModEntry.second->SourceFiles.push_back(File);
|
|
return Error::success();
|
|
}
|
|
|
|
uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
|
|
uint32_t Size = 0;
|
|
for (const auto &M : ModuleInfoList) {
|
|
Size += sizeof(ModuleInfoHeader);
|
|
Size += M->Mod.size() + 1;
|
|
Size += M->Obj.size() + 1;
|
|
}
|
|
return Size;
|
|
}
|
|
|
|
uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
|
|
uint32_t Size = 0;
|
|
Size += sizeof(ulittle16_t); // NumModules
|
|
Size += sizeof(ulittle16_t); // NumSourceFiles
|
|
Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
|
|
Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
|
|
uint32_t NumFileInfos = 0;
|
|
for (const auto &M : ModuleInfoList)
|
|
NumFileInfos += M->SourceFiles.size();
|
|
Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
|
|
Size += calculateNamesBufferSize();
|
|
return Size;
|
|
}
|
|
|
|
uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
|
|
uint32_t Size = 0;
|
|
for (const auto &F : SourceFileNames) {
|
|
Size += F.getKeyLength() + 1; // Names[I];
|
|
}
|
|
return Size;
|
|
}
|
|
|
|
Error DbiStreamBuilder::generateModiSubstream() {
|
|
uint32_t Size = calculateModiSubstreamSize();
|
|
auto Data = Allocator.Allocate<uint8_t>(Size);
|
|
|
|
ModInfoBuffer = ByteStream<true>(MutableArrayRef<uint8_t>(Data, Size));
|
|
|
|
StreamWriter ModiWriter(ModInfoBuffer);
|
|
for (const auto &M : ModuleInfoList) {
|
|
ModuleInfoHeader Layout = {};
|
|
Layout.ModDiStream = kInvalidStreamIndex;
|
|
Layout.NumFiles = M->SourceFiles.size();
|
|
if (auto EC = ModiWriter.writeObject(Layout))
|
|
return EC;
|
|
if (auto EC = ModiWriter.writeZeroString(M->Mod))
|
|
return EC;
|
|
if (auto EC = ModiWriter.writeZeroString(M->Obj))
|
|
return EC;
|
|
}
|
|
if (ModiWriter.bytesRemaining() != 0)
|
|
return make_error<RawError>(raw_error_code::invalid_format,
|
|
"Unexpected bytes in Modi Stream Data");
|
|
return Error::success();
|
|
}
|
|
|
|
Error DbiStreamBuilder::generateFileInfoSubstream() {
|
|
uint32_t Size = calculateFileInfoSubstreamSize();
|
|
uint32_t NameSize = calculateNamesBufferSize();
|
|
auto Data = Allocator.Allocate<uint8_t>(Size);
|
|
uint32_t NamesOffset = Size - NameSize;
|
|
|
|
FileInfoBuffer = ByteStream<true>(MutableArrayRef<uint8_t>(Data, Size));
|
|
|
|
StreamRef MetadataBuffer = StreamRef(FileInfoBuffer).keep_front(NamesOffset);
|
|
StreamWriter MetadataWriter(MetadataBuffer);
|
|
|
|
uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
|
|
uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
|
|
if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
|
|
return EC;
|
|
if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
|
|
return EC;
|
|
for (uint16_t I = 0; I < ModiCount; ++I) {
|
|
if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
|
|
return EC;
|
|
}
|
|
for (const auto MI : ModuleInfoList) {
|
|
FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
|
|
if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
|
|
return EC;
|
|
}
|
|
|
|
// Before writing the FileNameOffsets array, write the NamesBuffer array.
|
|
// A side effect of this is that this will actually compute the various
|
|
// file name offsets, so we can then go back and write the FileNameOffsets
|
|
// array to the other substream.
|
|
NamesBuffer = StreamRef(FileInfoBuffer).drop_front(NamesOffset);
|
|
StreamWriter NameBufferWriter(NamesBuffer);
|
|
for (auto &Name : SourceFileNames) {
|
|
Name.second = NameBufferWriter.getOffset();
|
|
if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
|
|
return EC;
|
|
}
|
|
|
|
for (const auto MI : ModuleInfoList) {
|
|
for (StringRef Name : MI->SourceFiles) {
|
|
auto Result = SourceFileNames.find(Name);
|
|
if (Result == SourceFileNames.end())
|
|
return make_error<RawError>(raw_error_code::no_entry,
|
|
"The source file was not found.");
|
|
if (auto EC = MetadataWriter.writeInteger(Result->second))
|
|
return EC;
|
|
}
|
|
}
|
|
|
|
if (NameBufferWriter.bytesRemaining() > 0)
|
|
return make_error<RawError>(raw_error_code::invalid_format,
|
|
"The names buffer contained unexpected data.");
|
|
|
|
if (MetadataWriter.bytesRemaining() > 0)
|
|
return make_error<RawError>(
|
|
raw_error_code::invalid_format,
|
|
"The metadata buffer contained unexpected data.");
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) {
|
|
if (!VerHeader.hasValue())
|
|
return make_error<RawError>(raw_error_code::unspecified,
|
|
"Missing DBI Stream Version");
|
|
|
|
auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, File);
|
|
if (!DbiS)
|
|
return DbiS.takeError();
|
|
auto DS = std::move(*DbiS);
|
|
DbiStreamHeader *H = DS->getAllocator().Allocate<DbiStreamHeader>(1);
|
|
|
|
if (auto EC = generateModiSubstream())
|
|
return std::move(EC);
|
|
if (auto EC = generateFileInfoSubstream())
|
|
return std::move(EC);
|
|
|
|
H->VersionHeader = *VerHeader;
|
|
H->VersionSignature = -1;
|
|
H->Age = Age;
|
|
H->BuildNumber = BuildNumber;
|
|
H->Flags = Flags;
|
|
H->PdbDllRbld = PdbDllRbld;
|
|
H->PdbDllVersion = PdbDllVersion;
|
|
H->MachineType = static_cast<uint16_t>(MachineType);
|
|
|
|
H->ECSubstreamSize = 0;
|
|
H->FileInfoSize = FileInfoBuffer.getLength();
|
|
H->ModiSubstreamSize = ModInfoBuffer.getLength();
|
|
H->OptionalDbgHdrSize = 0;
|
|
H->SecContrSubstreamSize = 0;
|
|
H->SectionMapSize = 0;
|
|
H->TypeServerSize = 0;
|
|
H->SymRecordStreamIndex = kInvalidStreamIndex;
|
|
H->PublicSymbolStreamIndex = kInvalidStreamIndex;
|
|
H->MFCTypeServerIndex = kInvalidStreamIndex;
|
|
H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
|
|
|
|
auto Dbi = llvm::make_unique<DbiStream>(File, std::move(DS));
|
|
Dbi->Header = H;
|
|
Dbi->FileInfoSubstream = StreamRef(FileInfoBuffer);
|
|
Dbi->ModInfoSubstream = StreamRef(ModInfoBuffer);
|
|
if (auto EC = Dbi->initializeModInfoArray())
|
|
return std::move(EC);
|
|
if (auto EC = Dbi->initializeFileInfo())
|
|
return std::move(EC);
|
|
return std::move(Dbi);
|
|
}
|