llvm-project/llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp

137 lines
4.7 KiB
C++

//===- ModInfoBuilder.cpp - PDB Module Info 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/Native/ModInfoBuilder.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryItemStream.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/COFF.h"
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
namespace llvm {
template <> struct BinaryItemTraits<CVSymbol> {
static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); }
static ArrayRef<uint8_t> bytes(const CVSymbol &Item) {
return Item.RecordData;
}
};
}
static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) {
uint32_t Size = sizeof(uint32_t); // Signature
Size += SymbolByteSize; // Symbol Data
Size += 0; // TODO: Layout.LineBytes
Size += 0; // TODO: Layout.C13Bytes
Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)
Size += 0; // GlobalRefs substream bytes
return Size;
}
ModInfoBuilder::ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex,
msf::MSFBuilder &Msf)
: MSF(Msf), ModuleName(ModuleName) {
Layout.Mod = ModIndex;
}
uint16_t ModInfoBuilder::getStreamIndex() const { return Layout.ModDiStream; }
void ModInfoBuilder::setObjFileName(StringRef Name) { ObjFileName = Name; }
void ModInfoBuilder::addSymbol(CVSymbol Symbol) {
Symbols.push_back(Symbol);
SymbolByteSize += Symbol.data().size();
}
void ModInfoBuilder::addSourceFile(StringRef Path) {
SourceFiles.push_back(Path);
}
uint32_t ModInfoBuilder::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 ModInfoBuilder::finalize() {
Layout.C13Bytes = 0;
Layout.FileNameOffs = 0; // TODO: Fix this
Layout.Flags = 0; // TODO: Fix this
Layout.LineBytes = 0;
(void)Layout.Mod; // Set in constructor
(void)Layout.ModDiStream; // Set in finalizeMsfLayout
Layout.NumFiles = SourceFiles.size();
Layout.PdbFilePathNI = 0;
Layout.SrcFileNameNI = 0;
// This value includes both the signature field as well as the record bytes
// from the symbol stream.
Layout.SymBytes = SymbolByteSize + sizeof(uint32_t);
}
Error ModInfoBuilder::finalizeMsfLayout() {
this->Layout.ModDiStream = kInvalidStreamIndex;
auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize));
if (!ExpectedSN)
return ExpectedSN.takeError();
Layout.ModDiStream = *ExpectedSN;
return Error::success();
}
Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter,
const msf::MSFLayout &MsfLayout,
WritableBinaryStreamRef MsfBuffer) {
// 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;
if (Layout.ModDiStream != kInvalidStreamIndex) {
auto NS = WritableMappedBlockStream::createIndexedStream(
MsfLayout, MsfBuffer, Layout.ModDiStream);
WritableBinaryStreamRef Ref(*NS);
BinaryStreamWriter SymbolWriter(Ref);
// Write the symbols.
if (auto EC =
SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
return EC;
BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little);
Records.setItems(Symbols);
BinaryStreamRef RecordsRef(Records);
if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
return EC;
// TODO: Write C11 Line data
// TODO: Write C13 Line data
// 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();
}