class DbiStream {
friend class DbiStreamBuilder;
- struct HeaderInfo {
- support::little32_t VersionSignature;
- support::ulittle32_t VersionHeader;
- support::ulittle32_t Age; // Should match InfoStream.
- support::ulittle16_t GlobalSymbolStreamIndex; // Global symbol stream #
- support::ulittle16_t BuildNumber; // See DbiBuildNo structure.
- support::ulittle16_t PublicSymbolStreamIndex; // Public symbols stream #
- support::ulittle16_t PdbDllVersion; // version of mspdbNNN.dll
- support::ulittle16_t SymRecordStreamIndex; // Symbol records stream #
- support::ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll
- support::little32_t ModiSubstreamSize; // Size of module info stream
- support::little32_t SecContrSubstreamSize; // Size of sec. contrib stream
- support::little32_t SectionMapSize; // Size of sec. map substream
- support::little32_t FileInfoSize; // Size of file info substream
- support::little32_t TypeServerSize; // Size of type server map
- support::ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server
- support::little32_t OptionalDbgHdrSize; // Size of DbgHeader info
- support::little32_t ECSubstreamSize; // Size of EC stream (what is EC?)
- support::ulittle16_t Flags; // See DbiFlags enum.
- support::ulittle16_t MachineType; // See PDB_MachineType enum.
-
- support::ulittle32_t Reserved; // Pad to 64 bytes
- };
-
public:
DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream);
~DbiStream();
PDB_Machine getMachineType() const;
- enum { InvalidStreamIndex = 0xffff };
-
/// If the given stream type is present, returns its stream index. If it is
/// not present, returns InvalidStreamIndex.
uint32_t getDebugStreamIndex(DbgHeaderType Type) const;
std::unique_ptr<MappedBlockStream> FpoStream;
codeview::FixedStreamArray<object::FpoData> FpoRecords;
- const HeaderInfo *Header;
+ const DbiStreamHeader *Header;
};
}
}
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/StreamArray.h"
#include "llvm/DebugInfo/CodeView/StreamRef.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
#include "llvm/Support/Endian.h"
#include <cstdint>
#include <vector>
class ModInfo {
friend class DbiStreamBuilder;
-private:
- typedef support::ulittle16_t ulittle16_t;
- typedef support::ulittle32_t ulittle32_t;
- typedef support::little32_t little32_t;
-
- struct SCBytes {
- ulittle16_t Section;
- char Padding1[2];
- little32_t Offset;
- little32_t Size;
- ulittle32_t Characteristics;
- ulittle16_t ModuleIndex;
- char Padding2[2];
- ulittle32_t DataCrc;
- ulittle32_t RelocCrc;
- };
-
- // struct Flags {
- // uint16_t fWritten : 1; // True if ModInfo is dirty
- // uint16_t fECEnabled : 1; // Is EC symbolic info present? (What is EC?)
- // uint16_t unused : 6; // Reserved
- // uint16_t iTSM : 8; // Type Server Index for this module
- //};
- const uint16_t HasECFlagMask = 0x2;
-
- const uint16_t TypeServerIndexMask = 0xFF00;
- const uint16_t TypeServerIndexShift = 8;
-
- struct FileLayout {
- ulittle32_t Mod; // Currently opened module. This field is a
- // pointer in the reference implementation, but
- // that won't work on 64-bit systems, and anyway
- // it doesn't make sense to read a pointer from a
- // file. For now it is unused, so just ignore it.
- SCBytes SC; // First section contribution of this module.
- ulittle16_t Flags; // See Flags definition.
- ulittle16_t ModDiStream; // Stream Number of module debug info
- ulittle32_t SymBytes; // Size of local symbol debug info in above stream
- ulittle32_t LineBytes; // Size of line number debug info in above stream
- ulittle32_t C13Bytes; // Size of C13 line number info in above stream
- ulittle16_t NumFiles; // Number of files contributing to this module
- char Padding1[2]; // Padding so the next field is 4-byte aligned.
- ulittle32_t FileNameOffs; // array of [0..NumFiles) DBI name buffer offsets.
- // This field is a pointer in the reference
- // implementation, but as with `Mod`, we ignore it
- // for now since it is unused.
- ulittle32_t SrcFileNameNI; // Name Index for src file name
- ulittle32_t PdbFilePathNI; // Name Index for path to compiler PDB
- // Null terminated Module name
- // Null terminated Obj File Name
- };
-
public:
ModInfo();
ModInfo(const ModInfo &Info);
private:
StringRef ModuleName;
StringRef ObjFileName;
- const FileLayout *Layout;
+ const ModuleInfoHeader *Layout;
};
struct ModuleInfoEx {
namespace llvm {
namespace pdb {
+const uint16_t kInvalidStreamIndex = 0xFFFF;
+
enum PdbRaw_ImplVer : uint32_t {
PdbImplVC2 = 19941610,
PdbImplVC4 = 19950623,
support::ulittle32_t Offset;
};
+/// Some of the values are stored in bitfields. Since this needs to be portable
+/// across compilers and architectures (big / little endian in particular) we
+/// can't use the actual structures below, but must instead do the shifting
+/// and masking ourselves. The struct definitions are provided for reference.
+struct DbiFlags {
+ /// uint16_t IncrementalLinking : 1; // True if linked incrementally
+ /// uint16_t IsStripped : 1; // True if private symbols were
+ /// stripped.
+ /// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes.
+ /// uint16_t Reserved : 13;
+ static const uint16_t FlagIncrementalMask = 0x0001;
+ static const uint16_t FlagStrippedMask = 0x0002;
+ static const uint16_t FlagHasCTypesMask = 0x0004;
+};
+
+struct DbiBuildNo {
+ /// uint16_t MinorVersion : 8;
+ /// uint16_t MajorVersion : 7;
+ /// uint16_t NewVersionFormat : 1;
+ static const uint16_t BuildMinorMask = 0x00FF;
+ static const uint16_t BuildMinorShift = 0;
+
+ static const uint16_t BuildMajorMask = 0x7F00;
+ static const uint16_t BuildMajorShift = 8;
+};
+
+/// The fixed size header that appears at the beginning of the DBI Stream.
+struct DbiStreamHeader {
+ support::little32_t VersionSignature;
+ support::ulittle32_t VersionHeader;
+
+ /// How "old" is this DBI Stream. Should match the age of the PDB InfoStream.
+ support::ulittle32_t Age;
+
+ /// Global symbol stream #
+ support::ulittle16_t GlobalSymbolStreamIndex;
+
+ /// See DbiBuildNo structure.
+ support::ulittle16_t BuildNumber;
+
+ /// Public symbols stream #
+ support::ulittle16_t PublicSymbolStreamIndex;
+
+ /// version of mspdbNNN.dll
+ support::ulittle16_t PdbDllVersion;
+
+ /// Symbol records stream #
+ support::ulittle16_t SymRecordStreamIndex;
+
+ /// rbld number of mspdbNNN.dll
+ support::ulittle16_t PdbDllRbld;
+
+ /// Size of module info stream
+ support::little32_t ModiSubstreamSize;
+
+ /// Size of sec. contrib stream
+ support::little32_t SecContrSubstreamSize;
+
+ /// Size of sec. map substream
+ support::little32_t SectionMapSize;
+
+ /// Size of file info substream
+ support::little32_t FileInfoSize;
+
+ /// Size of type server map
+ support::little32_t TypeServerSize;
+
+ /// Index of MFC Type Server
+ support::ulittle32_t MFCTypeServerIndex;
+
+ /// Size of DbgHeader info
+ support::little32_t OptionalDbgHdrSize;
+
+ /// Size of EC stream (what is EC?)
+ support::little32_t ECSubstreamSize;
+
+ /// See DbiFlags enum.
+ support::ulittle16_t Flags;
+
+ /// See PDB_MachineType enum.
+ support::ulittle16_t MachineType;
+
+ /// Pad to 64 bytes
+ support::ulittle32_t Reserved;
+};
+static_assert(sizeof(DbiStreamHeader) == 64, "Invalid DbiStreamHeader size!");
+
+struct SectionContribEntry {
+ support::ulittle16_t Section;
+ char Padding1[2];
+ support::little32_t Offset;
+ support::little32_t Size;
+ support::ulittle32_t Characteristics;
+ support::ulittle16_t ModuleIndex;
+ char Padding2[2];
+ support::ulittle32_t DataCrc;
+ support::ulittle32_t RelocCrc;
+};
+
+/// The header preceeding the File Info Substream of the DBI stream.
+struct FileInfoSubstreamHeader {
+ /// Total # of modules, should match number of records in the ModuleInfo
+ /// substream.
+ support::ulittle16_t NumModules;
+
+ /// Total # of source files. This value is not accurate because PDB actually
+ /// supports more than 64k source files, so we ignore it and compute the value
+ /// from other stream fields.
+ support::ulittle16_t NumSourceFiles;
+
+ /// Following this header the File Info Substream is laid out as follows:
+ /// ulittle16_t ModIndices[NumModules];
+ /// ulittle16_t ModFileCounts[NumModules];
+ /// ulittle32_t FileNameOffsets[NumSourceFiles];
+ /// char Names[][NumSourceFiles];
+ /// with the caveat that `NumSourceFiles` cannot be trusted, so
+ /// it is computed by summing the `ModFileCounts` array.
+};
+
+struct ModInfoFlags {
+ /// uint16_t fWritten : 1; // True if ModInfo is dirty
+ /// uint16_t fECEnabled : 1; // Is EC symbolic info present? (What is EC?)
+ /// uint16_t unused : 6; // Reserved
+ /// uint16_t iTSM : 8; // Type Server Index for this module
+ static const uint16_t HasECFlagMask = 0x2;
+
+ static const uint16_t TypeServerIndexMask = 0xFF00;
+ static const uint16_t TypeServerIndexShift = 8;
+};
+
+/// The header preceeding each entry in the Module Info substream of the DBI
+/// stream.
+struct ModuleInfoHeader {
+ /// Currently opened module. This field is a pointer in the reference
+ /// implementation, but that won't work on 64-bit systems, and anyway it
+ /// doesn't make sense to read a pointer from a file. For now it is unused,
+ /// so just ignore it.
+ support::ulittle32_t Mod;
+
+ /// First section contribution of this module.
+ SectionContribEntry SC;
+
+ /// See ModInfoFlags definition.
+ support::ulittle16_t Flags;
+
+ /// Stream Number of module debug info
+ support::ulittle16_t ModDiStream;
+
+ /// Size of local symbol debug info in above stream
+ support::ulittle32_t SymBytes;
+
+ /// Size of line number debug info in above stream
+ support::ulittle32_t LineBytes;
+
+ /// Size of C13 line number info in above stream
+ support::ulittle32_t C13Bytes;
+
+ /// Number of files contributing to this module
+ support::ulittle16_t NumFiles;
+
+ /// Padding so the next field is 4-byte aligned.
+ char Padding1[2];
+
+ /// Array of [0..NumFiles) DBI name buffer offsets. This field is a pointer
+ /// in the reference implementation, but as with `Mod`, we ignore it for now
+ /// since it is unused.
+ support::ulittle32_t FileNameOffs;
+
+ /// Name Index for src file name
+ support::ulittle32_t SrcFileNameNI;
+
+ /// Name Index for path to compiler PDB
+ support::ulittle32_t PdbFilePathNI;
+
+ /// Following this header are two zero terminated strings.
+ /// char ModuleName[];
+ /// char ObjFileName[];
+};
+
} // namespace pdb
} // namespace llvm
using namespace llvm::pdb;
using namespace llvm::support;
-namespace {
-// Some of the values are stored in bitfields. Since this needs to be portable
-// across compilers and architectures (big / little endian in particular) we
-// can't use the actual structures below, but must instead do the shifting
-// and masking ourselves. The struct definitions are provided for reference.
-
-// struct DbiFlags {
-// uint16_t IncrementalLinking : 1; // True if linked incrementally
-// uint16_t IsStripped : 1; // True if private symbols were stripped.
-// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes.
-// uint16_t Reserved : 13;
-//};
-const uint16_t FlagIncrementalMask = 0x0001;
-const uint16_t FlagStrippedMask = 0x0002;
-const uint16_t FlagHasCTypesMask = 0x0004;
-
-// struct DbiBuildNo {
-// uint16_t MinorVersion : 8;
-// uint16_t MajorVersion : 7;
-// uint16_t NewVersionFormat : 1;
-//};
-const uint16_t BuildMinorMask = 0x00FF;
-const uint16_t BuildMinorShift = 0;
-
-const uint16_t BuildMajorMask = 0x7F00;
-const uint16_t BuildMajorShift = 8;
-
-struct FileInfoSubstreamHeader {
- ulittle16_t NumModules; // Total # of modules, should match number of
- // records in the ModuleInfo substream.
- ulittle16_t NumSourceFiles; // Total # of source files. This value is not
- // accurate because PDB actually supports more
- // than 64k source files, so we ignore it and
- // compute the value from other stream fields.
-};
-}
-
template <typename ContribType>
static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
StreamReader &Reader) {
DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
: Pdb(File), Stream(std::move(Stream)), Header(nullptr) {
- static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!");
}
DbiStream::~DbiStream() {}
Error DbiStream::reload() {
StreamReader Reader(*Stream);
- if (Stream->getLength() < sizeof(HeaderInfo))
+ if (Stream->getLength() < sizeof(DbiStreamHeader))
return make_error<RawError>(raw_error_code::corrupt_file,
"DBI Stream does not contain a header.");
if (auto EC = Reader.readObject(Header))
"DBI Age does not match PDB Age.");
if (Stream->getLength() !=
- sizeof(HeaderInfo) + Header->ModiSubstreamSize +
+ sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
Header->SecContrSubstreamSize + Header->SectionMapSize +
Header->FileInfoSize + Header->TypeServerSize +
Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
uint16_t DbiStream::getFlags() const { return Header->Flags; }
bool DbiStream::isIncrementallyLinked() const {
- return (Header->Flags & FlagIncrementalMask) != 0;
+ return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
}
bool DbiStream::hasCTypes() const {
- return (Header->Flags & FlagHasCTypesMask) != 0;
+ return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
}
bool DbiStream::isStripped() const {
- return (Header->Flags & FlagStrippedMask) != 0;
+ return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
}
uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
uint16_t DbiStream::getBuildMajorVersion() const {
- return (Header->BuildNumber & BuildMajorMask) >> BuildMajorShift;
+ return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
+ DbiBuildNo::BuildMajorShift;
}
uint16_t DbiStream::getBuildMinorVersion() const {
- return (Header->BuildNumber & BuildMinorMask) >> BuildMinorShift;
+ return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
+ DbiBuildNo::BuildMinorShift;
}
uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO);
// This means there is no FPO data.
- if (StreamNum == InvalidStreamIndex)
+ if (StreamNum == kInvalidStreamIndex)
return Error::success();
if (StreamNum >= Pdb.getNumStreams())
}
Error DbiStream::initializeFileInfo() {
- // The layout of the FileInfoSubstream is like this:
- // struct {
- // ulittle16_t NumModules;
- // ulittle16_t NumSourceFiles;
- // ulittle16_t ModIndices[NumModules];
- // ulittle16_t ModFileCounts[NumModules];
- // ulittle32_t FileNameOffsets[NumSourceFiles];
- // char Names[][NumSourceFiles];
- // };
- // with the caveat that `NumSourceFiles` cannot be trusted, so
- // it is computed by summing `ModFileCounts`.
- //
if (FileInfoSubstream.getLength() == 0)
return Error::success();
uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
uint16_t T = static_cast<uint16_t>(Type);
if (T >= DbgStreams.size())
- return DbiStream::InvalidStreamIndex;
+ return kInvalidStreamIndex;
return DbgStreams[T];
}
uint32_t DbiStreamBuilder::calculateSerializedLength() const {
// For now we only support serializing the header.
- return sizeof(DbiStream::HeaderInfo) + calculateFileInfoSubstreamSize() +
+ return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
calculateModiSubstreamSize();
}
uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
uint32_t Size = 0;
for (const auto &M : ModuleInfoList) {
- Size += sizeof(ModInfo::FileLayout);
+ Size += sizeof(ModuleInfoHeader);
Size += M->Mod.size() + 1;
Size += M->Obj.size() + 1;
}
}
uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
- // ulittle16_t NumModules;
- // ulittle16_t NumSourceFiles;
- // ulittle16_t ModIndices[NumModules];
- // ulittle16_t ModFileCounts[NumModules];
- // ulittle32_t FileNameOffsets[NumSourceFiles];
- // char Names[NumSourceFiles][];
uint32_t Size = 0;
Size += sizeof(ulittle16_t); // NumModules
Size += sizeof(ulittle16_t); // NumSourceFiles
StreamWriter ModiWriter(ModInfoBuffer);
for (const auto &M : ModuleInfoList) {
- ModInfo::FileLayout Layout = {};
- Layout.ModDiStream = DbiStream::InvalidStreamIndex;
+ ModuleInfoHeader Layout = {};
+ Layout.ModDiStream = kInvalidStreamIndex;
Layout.NumFiles = M->SourceFiles.size();
if (auto EC = ModiWriter.writeObject(Layout))
return EC;
if (!DbiS)
return DbiS.takeError();
auto DS = std::move(*DbiS);
- DbiStream::HeaderInfo *H =
- static_cast<DbiStream::HeaderInfo *>(DS->getAllocator().Allocate(
- sizeof(DbiStream::HeaderInfo),
- llvm::AlignOf<DbiStream::HeaderInfo>::Alignment));
+ DbiStreamHeader *H = DS->getAllocator().Allocate<DbiStreamHeader>(1);
if (auto EC = generateModiSubstream())
return std::move(EC);
H->SecContrSubstreamSize = 0;
H->SectionMapSize = 0;
H->TypeServerSize = 0;
- H->SymRecordStreamIndex = DbiStream::InvalidStreamIndex;
- H->PublicSymbolStreamIndex = DbiStream::InvalidStreamIndex;
- H->MFCTypeServerIndex = DbiStream::InvalidStreamIndex;
- H->GlobalSymbolStreamIndex = DbiStream::InvalidStreamIndex;
+ 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;
return Error::success();
}
-bool ModInfo::hasECInfo() const { return (Layout->Flags & HasECFlagMask) != 0; }
+bool ModInfo::hasECInfo() const {
+ return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0;
+}
uint16_t ModInfo::getTypeServerIndex() const {
- return (Layout->Flags & TypeServerIndexMask) >> TypeServerIndexShift;
+ return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >>
+ ModInfoFlags::TypeServerIndexShift;
}
uint16_t ModInfo::getModuleStreamIndex() const { return Layout->ModDiStream; }
uint32_t ModInfo::getRecordLength() const {
uint32_t M = ModuleName.str().size() + 1;
uint32_t O = ObjFileName.str().size() + 1;
- uint32_t Size = sizeof(FileLayout) + M + O;
+ uint32_t Size = sizeof(ModuleInfoHeader) + M + O;
Size = llvm::alignTo(Size, 4);
return Size;
}