219 lines
7.6 KiB
C++
219 lines
7.6 KiB
C++
|
//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
|
||
|
|
||
|
#include "llvm/ADT/ArrayRef.h"
|
||
|
#include "llvm/BinaryFormat/COFF.h"
|
||
|
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
|
||
|
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||
|
#include "llvm/DebugInfo/MSF/MSFCommon.h"
|
||
|
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||
|
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||
|
#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
|
||
|
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||
|
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||
|
#include "llvm/Support/BinaryStreamWriter.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
using namespace llvm::codeview;
|
||
|
using namespace llvm::msf;
|
||
|
using namespace llvm::pdb;
|
||
|
|
||
|
static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,
|
||
|
uint32_t C13Size) {
|
||
|
uint32_t Size = sizeof(uint32_t); // Signature
|
||
|
Size += alignTo(SymbolByteSize, 4); // Symbol Data
|
||
|
Size += 0; // TODO: Layout.C11Bytes
|
||
|
Size += C13Size; // C13 Debug Info Size
|
||
|
Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)
|
||
|
Size += 0; // GlobalRefs substream bytes
|
||
|
return Size;
|
||
|
}
|
||
|
|
||
|
DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName,
|
||
|
uint32_t ModIndex,
|
||
|
msf::MSFBuilder &Msf)
|
||
|
: MSF(Msf), ModuleName(std::string(ModuleName)) {
|
||
|
::memset(&Layout, 0, sizeof(Layout));
|
||
|
Layout.Mod = ModIndex;
|
||
|
}
|
||
|
|
||
|
DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {}
|
||
|
|
||
|
uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {
|
||
|
return Layout.ModDiStream;
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {
|
||
|
ObjFileName = std::string(Name);
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) {
|
||
|
PdbFilePathNI = NI;
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::setFirstSectionContrib(
|
||
|
const SectionContrib &SC) {
|
||
|
Layout.SC = SC;
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
|
||
|
// Defer to the bulk API. It does the same thing.
|
||
|
addSymbolsInBulk(Symbol.data());
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::addSymbolsInBulk(
|
||
|
ArrayRef<uint8_t> BulkSymbols) {
|
||
|
// Do nothing for empty runs of symbols.
|
||
|
if (BulkSymbols.empty())
|
||
|
return;
|
||
|
|
||
|
Symbols.push_back(SymbolListWrapper(BulkSymbols));
|
||
|
// Symbols written to a PDB file are required to be 4 byte aligned. The same
|
||
|
// is not true of object files.
|
||
|
assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||
|
"Invalid Symbol alignment!");
|
||
|
SymbolByteSize += BulkSymbols.size();
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc,
|
||
|
uint32_t SymLength) {
|
||
|
assert(SymLength > 0);
|
||
|
Symbols.push_back(SymbolListWrapper(SymSrc, SymLength));
|
||
|
|
||
|
// Symbols written to a PDB file are required to be 4 byte aligned. The same
|
||
|
// is not true of object files.
|
||
|
assert(SymLength % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||
|
"Invalid Symbol alignment!");
|
||
|
SymbolByteSize += SymLength;
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
|
||
|
SourceFiles.push_back(std::string(Path));
|
||
|
}
|
||
|
|
||
|
uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {
|
||
|
uint32_t Result = 0;
|
||
|
for (const auto &Builder : C13Builders) {
|
||
|
Result += Builder.calculateSerializedLength();
|
||
|
}
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
|
||
|
uint32_t L = sizeof(Layout);
|
||
|
uint32_t M = ModuleName.size() + 1;
|
||
|
uint32_t O = ObjFileName.size() + 1;
|
||
|
return alignTo(L + M + O, sizeof(uint32_t));
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::finalize() {
|
||
|
Layout.FileNameOffs = 0; // TODO: Fix this
|
||
|
Layout.Flags = 0; // TODO: Fix this
|
||
|
Layout.C11Bytes = 0;
|
||
|
Layout.C13Bytes = calculateC13DebugInfoSize();
|
||
|
(void)Layout.Mod; // Set in constructor
|
||
|
(void)Layout.ModDiStream; // Set in finalizeMsfLayout
|
||
|
Layout.NumFiles = SourceFiles.size();
|
||
|
Layout.PdbFilePathNI = PdbFilePathNI;
|
||
|
Layout.SrcFileNameNI = 0;
|
||
|
|
||
|
// This value includes both the signature field as well as the record bytes
|
||
|
// from the symbol stream.
|
||
|
Layout.SymBytes =
|
||
|
Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset();
|
||
|
}
|
||
|
|
||
|
Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {
|
||
|
this->Layout.ModDiStream = kInvalidStreamIndex;
|
||
|
uint32_t C13Size = calculateC13DebugInfoSize();
|
||
|
if (!C13Size && !SymbolByteSize)
|
||
|
return Error::success();
|
||
|
auto ExpectedSN =
|
||
|
MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));
|
||
|
if (!ExpectedSN)
|
||
|
return ExpectedSN.takeError();
|
||
|
Layout.ModDiStream = *ExpectedSN;
|
||
|
return Error::success();
|
||
|
}
|
||
|
|
||
|
Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {
|
||
|
// We write the Modi record to the `ModiWriter`, but we additionally write its
|
||
|
// symbol stream to a brand new stream.
|
||
|
if (auto EC = ModiWriter.writeObject(Layout))
|
||
|
return EC;
|
||
|
if (auto EC = ModiWriter.writeCString(ModuleName))
|
||
|
return EC;
|
||
|
if (auto EC = ModiWriter.writeCString(ObjFileName))
|
||
|
return EC;
|
||
|
if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
|
||
|
return EC;
|
||
|
return Error::success();
|
||
|
}
|
||
|
|
||
|
Error DbiModuleDescriptorBuilder::commitSymbolStream(
|
||
|
const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) {
|
||
|
if (Layout.ModDiStream == kInvalidStreamIndex)
|
||
|
return Error::success();
|
||
|
|
||
|
auto NS = WritableMappedBlockStream::createIndexedStream(
|
||
|
MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
|
||
|
WritableBinaryStreamRef Ref(*NS);
|
||
|
BinaryStreamWriter SymbolWriter(Ref);
|
||
|
// Write the symbols.
|
||
|
if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
|
||
|
return EC;
|
||
|
for (const SymbolListWrapper &Sym : Symbols) {
|
||
|
if (Sym.NeedsToBeMerged) {
|
||
|
assert(MergeSymsCallback);
|
||
|
if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter))
|
||
|
return EC;
|
||
|
} else {
|
||
|
if (auto EC = SymbolWriter.writeBytes(Sym.asArray()))
|
||
|
return EC;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Apply the string table fixups.
|
||
|
auto SavedOffset = SymbolWriter.getOffset();
|
||
|
for (const StringTableFixup &Fixup : StringTableFixups) {
|
||
|
SymbolWriter.setOffset(Fixup.SymOffsetOfReference);
|
||
|
if (auto E = SymbolWriter.writeInteger<uint32_t>(Fixup.StrTabOffset))
|
||
|
return E;
|
||
|
}
|
||
|
SymbolWriter.setOffset(SavedOffset);
|
||
|
|
||
|
assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||
|
"Invalid debug section alignment!");
|
||
|
// TODO: Write C11 Line data
|
||
|
for (const auto &Builder : C13Builders) {
|
||
|
if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))
|
||
|
return EC;
|
||
|
}
|
||
|
|
||
|
// TODO: Figure out what GlobalRefs substream actually is and populate it.
|
||
|
if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
|
||
|
return EC;
|
||
|
if (SymbolWriter.bytesRemaining() > 0)
|
||
|
return make_error<RawError>(raw_error_code::stream_too_long);
|
||
|
|
||
|
return Error::success();
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::addDebugSubsection(
|
||
|
std::shared_ptr<DebugSubsection> Subsection) {
|
||
|
assert(Subsection);
|
||
|
C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection)));
|
||
|
}
|
||
|
|
||
|
void DbiModuleDescriptorBuilder::addDebugSubsection(
|
||
|
const DebugSubsectionRecord &SubsectionContents) {
|
||
|
C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents));
|
||
|
}
|