Parse module information from DBI stream.

This gets more data out of the DBI strema of the PDB.  In
particular it extracts the metadata for the list of modules
(compilands) that this PDB contains info about, and adds support
for dumping these fields to llvm-pdbdump.

Differential Revision: http://reviews.llvm.org/D19570
Reviewed By: ruiu

llvm-svn: 267818
This commit is contained in:
Zachary Turner 2016-04-27 23:41:42 +00:00
parent 12b69919a2
commit 1822af542f
7 changed files with 275 additions and 2 deletions

View File

@ -0,0 +1,62 @@
//===- ModInfo.h - PDB module information -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_RAW_MODINFO_H
#define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H
#include "llvm/ADT/StringRef.h"
#include <stdint.h>
namespace llvm {
class PDBFile;
class ModInfo {
private:
struct FileLayout;
public:
ModInfo(const uint8_t *Bytes);
~ModInfo();
bool hasECInfo() const;
uint16_t getTypeServerIndex() const;
uint16_t getModuleStreamIndex() const;
uint32_t getSymbolDebugInfoByteSize() const;
uint32_t getLineInfoByteSize() const;
uint32_t getC13LineInfoByteSize() const;
uint32_t getNumberOfFiles() const;
uint32_t getSourceFileNameIndex() const;
uint32_t getPdbFilePathNameIndex() const;
llvm::StringRef getModuleName() const;
llvm::StringRef getObjFileName() const;
private:
const FileLayout *Layout;
};
class ModInfoIterator {
public:
ModInfoIterator(const uint8_t *Stream);
ModInfoIterator(const ModInfoIterator &Other);
ModInfo operator*();
ModInfoIterator &operator++();
ModInfoIterator operator++(int);
bool operator==(const ModInfoIterator &Other);
bool operator!=(const ModInfoIterator &Other);
ModInfoIterator &operator=(const ModInfoIterator &Other);
private:
const uint8_t *Bytes;
};
}
#endif

View File

@ -11,6 +11,7 @@
#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H
#include "llvm/DebugInfo/PDB/PDBTypes.h"
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
#include "llvm/DebugInfo/PDB/Raw/PDBRawConstants.h"
#include "llvm/DebugInfo/PDB/Raw/PDBStream.h"
#include "llvm/Support/Endian.h"
@ -42,9 +43,13 @@ public:
PDB_Machine getMachineType() const;
llvm::iterator_range<ModInfoIterator> modules() const;
private:
PDBFile &Pdb;
PDBStream Stream;
std::vector<uint8_t> ModInfoSubstream;
std::unique_ptr<HeaderInfo> Header;
};
}

View File

@ -27,6 +27,7 @@ if(HAVE_DIA_SDK)
endif()
add_pdb_impl_folder(Raw
Raw/ModInfo.cpp
Raw/PDBFile.cpp
Raw/PDBDbiStream.cpp
Raw/PDBInfoStream.cpp

View File

@ -0,0 +1,142 @@
//===- ModInfo.cpp - PDB module information -------------------------------===//
//
// 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/ModInfo.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::support;
namespace {
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 ModInfo::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
char VarInfo[1]; // Module name followed by Obj File Name
StringRef getModuleName() const { return StringRef(VarInfo); }
StringRef getObjectFileName() const {
return StringRef(getModuleName().end() + 1);
}
};
ModInfo::ModInfo(const uint8_t *Bytes)
: Layout(reinterpret_cast<const FileLayout *>(Bytes)) {}
ModInfo::~ModInfo() {}
bool ModInfo::hasECInfo() const { return (Layout->Flags & HasECFlagMask) != 0; }
uint16_t ModInfo::getTypeServerIndex() const {
return (Layout->Flags & TypeServerIndexMask) >> TypeServerIndexShift;
}
uint16_t ModInfo::getModuleStreamIndex() const { return Layout->ModDiStream; }
uint32_t ModInfo::getSymbolDebugInfoByteSize() const {
return Layout->SymBytes;
}
uint32_t ModInfo::getLineInfoByteSize() const { return Layout->LineBytes; }
uint32_t ModInfo::getC13LineInfoByteSize() const { return Layout->C13Bytes; }
uint32_t ModInfo::getNumberOfFiles() const { return Layout->NumFiles; }
uint32_t ModInfo::getSourceFileNameIndex() const {
return Layout->SrcFileNameNI;
}
uint32_t ModInfo::getPdbFilePathNameIndex() const {
return Layout->PdbFilePathNI;
}
llvm::StringRef ModInfo::getModuleName() const {
return Layout->getModuleName();
}
llvm::StringRef ModInfo::getObjFileName() const {
return Layout->getObjectFileName();
}
ModInfoIterator::ModInfoIterator(const uint8_t *Stream) : Bytes(Stream) {}
ModInfoIterator::ModInfoIterator(const ModInfoIterator &Other)
: Bytes(Other.Bytes) {}
ModInfo ModInfoIterator::operator*() { return ModInfo(Bytes); }
ModInfoIterator &ModInfoIterator::operator++() {
StringRef Obj = ModInfo(Bytes).getObjFileName();
Bytes = Obj.bytes_end() + 1;
Bytes = reinterpret_cast<const uint8_t *>(llvm::alignAddr(Bytes, 4));
return *this;
}
ModInfoIterator ModInfoIterator::operator++(int) {
ModInfoIterator Copy(*this);
++(*this);
return Copy;
}
bool ModInfoIterator::operator==(const ModInfoIterator &Other) {
return Bytes == Other.Bytes;
}
bool ModInfoIterator::operator!=(const ModInfoIterator &Other) {
return !(*this == Other);
}
ModInfoIterator &ModInfoIterator::operator=(const ModInfoIterator &Other) {
Bytes = Other.Bytes;
return *this;
}

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Raw/PDBDbiStream.h"
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/DebugInfo/PDB/Raw/PDBInfoStream.h"
#include "llvm/DebugInfo/PDB/Raw/PDBRawConstants.h"
@ -84,8 +85,10 @@ std::error_code PDBDbiStream::reload() {
if (Header->VersionSignature != -1)
return std::make_error_code(std::errc::illegal_byte_sequence);
// Prior to VC50 an old style header was used. We don't support this.
if (Header->VersionHeader < PdbDbiV50)
// Require at least version 7, which should be present in all PDBs
// produced in the last decade and allows us to avoid having to
// special case all kinds of complicated arcane formats.
if (Header->VersionHeader < PdbDbiV70)
return std::make_error_code(std::errc::not_supported);
if (Header->Age != Pdb.getPDBInfoStream().getAge())
@ -98,6 +101,14 @@ std::error_code PDBDbiStream::reload() {
Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
return std::make_error_code(std::errc::illegal_byte_sequence);
if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
return std::make_error_code(std::errc::illegal_byte_sequence);
ModInfoSubstream.resize(Header->ModiSubstreamSize);
if (auto EC =
Stream.readBytes(&ModInfoSubstream[0], Header->ModiSubstreamSize))
return EC;
return std::error_code();
}
@ -138,3 +149,8 @@ PDB_Machine PDBDbiStream::getMachineType() const {
uint16_t Machine = Header->MachineType;
return static_cast<PDB_Machine>(Machine);
}
llvm::iterator_range<ModInfoIterator> PDBDbiStream::modules() const {
return llvm::make_range(ModInfoIterator(&ModInfoSubstream.front()),
ModInfoIterator(&ModInfoSubstream.back() + 1));
}

View File

@ -28,3 +28,27 @@
; CHECK-NEXT: Number of Symbols: 8
; CHECK-NEXT: Toolchain Version: 12.0
; CHECK-NEXT: mspdb120.dll version: 12.0.31101
; CHECK: Modules:
; CHECK-NEXT: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj
; CHECK-NEXT: Debug Stream Index: 12
; CHECK-NEXT: Object File: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj
; CHECK-NEXT: Num Files: 1
; CHECK-NEXT: Source File Name Idx: 0
; CHECK-NEXT: Pdb File Name Idx: 0
; CHECK-NEXT: Line Info Byte Size: 0
; CHECK-NEXT: C13 Line Info Byte Size: 88
; CHECK-NEXT: Symbol Byte Size: 208
; CHECK-NEXT: Type Server Index: 0
; CHECK-NEXT: Has EC Info: 0
; CHECK-NEXT: * Linker *
; CHECK-NEXT: Debug Stream Index: 14
; CHECK-NEXT: Object File:
; CHECK-NEXT: Num Files: 0
; CHECK-NEXT: Source File Name Idx: 0
; CHECK-NEXT: Pdb File Name Idx: 1
; CHECK-NEXT: Line Info Byte Size: 0
; CHECK-NEXT: C13 Line Info Byte Size: 0
; CHECK-NEXT: Symbol Byte Size: 516
; CHECK-NEXT: Type Server Index: 0
; CHECK-NEXT: Has EC Info: 0

View File

@ -35,6 +35,7 @@
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
#include "llvm/DebugInfo/PDB/Raw/PDBDbiStream.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/DebugInfo/PDB/Raw/PDBInfoStream.h"
@ -278,6 +279,28 @@ static void dumpStructure(RawSession &RS) {
outs() << "Toolchain Version: " << Major << "." << Minor << '\n';
outs() << "mspdb" << Major << Minor << ".dll version: " << Major << "."
<< Minor << "." << DbiStream.getPdbDllVersion() << '\n';
outs() << "Modules: \n";
for (auto Modi : DbiStream.modules()) {
outs() << Modi.getModuleName() << '\n';
outs().indent(4) << "Debug Stream Index: " << Modi.getModuleStreamIndex()
<< '\n';
outs().indent(4) << "Object File: " << Modi.getObjFileName() << '\n';
outs().indent(4) << "Num Files: " << Modi.getNumberOfFiles() << '\n';
outs().indent(4) << "Source File Name Idx: "
<< Modi.getSourceFileNameIndex() << '\n';
outs().indent(4) << "Pdb File Name Idx: " << Modi.getPdbFilePathNameIndex()
<< '\n';
outs().indent(4) << "Line Info Byte Size: " << Modi.getLineInfoByteSize()
<< '\n';
outs().indent(4) << "C13 Line Info Byte Size: "
<< Modi.getC13LineInfoByteSize() << '\n';
outs().indent(4) << "Symbol Byte Size: "
<< Modi.getSymbolDebugInfoByteSize() << '\n';
outs().indent(4) << "Type Server Index: " << Modi.getTypeServerIndex()
<< '\n';
outs().indent(4) << "Has EC Info: " << Modi.hasECInfo() << '\n';
}
}
static void dumpInput(StringRef Path) {