Index: include/llvm/DebugInfo/PDB/Raw/PDBFile.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -25,6 +25,7 @@ class DbiStream; class InfoStream; class PublicsStream; +class SymbolStream; class TpiStream; class PDBFile { @@ -64,6 +65,7 @@ Expected getPDBDbiStream(); Expected getPDBTpiStream(); Expected getPDBPublicsStream(); + Expected getPDBSymbolStream(); private: std::unique_ptr Context; @@ -71,6 +73,7 @@ std::unique_ptr Dbi; std::unique_ptr Tpi; std::unique_ptr Publics; + std::unique_ptr Symbols; }; } } Index: include/llvm/DebugInfo/PDB/Raw/PublicsStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/PublicsStream.h +++ include/llvm/DebugInfo/PDB/Raw/PublicsStream.h @@ -20,12 +20,13 @@ namespace llvm { namespace pdb { +class DbiStream; class PDBFile; class PublicsStream { - struct HeaderInfo; struct GSIHashHeader; - struct HRFile; + struct HashRecord; + struct HeaderInfo; public: PublicsStream(PDBFile &File, uint32_t StreamNum); @@ -36,15 +37,21 @@ uint32_t getSymHash() const; uint32_t getAddrMap() const; uint32_t getNumBuckets() const { return NumBuckets; } + std::vector getSymbols() const; ArrayRef getHashBuckets() const { return HashBuckets; } ArrayRef getAddressMap() const { return AddressMap; } ArrayRef getThunkMap() const { return ThunkMap; } ArrayRef getSectionOffsets() const { return SectionOffsets; } private: + Error readSymbols(); + + PDBFile &Pdb; + uint32_t StreamNum; MappedBlockStream Stream; uint32_t NumBuckets = 0; + std::vector HashRecords; std::vector HashBuckets; std::vector AddressMap; std::vector ThunkMap; Index: include/llvm/DebugInfo/PDB/Raw/SymbolStream.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -0,0 +1,39 @@ +//===- SymbolStream.cpp - PDB Symbol Stream Access --------------*- 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_PDBSYMBOLSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H + +#include "llvm/DebugInfo/CodeView/TypeStream.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/ByteStream.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class SymbolStream { +public: + SymbolStream(PDBFile &File, uint32_t StreamNum); + ~SymbolStream(); + Error reload(); + + Expected getSymbolName(uint32_t Offset) const; + +private: + MappedBlockStream Stream; +}; +} +} + +#endif Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -41,6 +41,7 @@ Raw/RawError.cpp Raw/RawSession.cpp Raw/StreamReader.cpp + Raw/SymbolStream.cpp Raw/TpiStream.cpp) list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") Index: lib/DebugInfo/PDB/Raw/PDBFile.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" #include "llvm/DebugInfo/PDB/Raw/TpiStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" @@ -307,3 +308,17 @@ } return *Publics; } + +Expected PDBFile::getPDBSymbolStream() { + if (!Symbols) { + auto DbiS = getPDBDbiStream(); + if (auto EC = DbiS.takeError()) + return std::move(EC); + uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); + + Symbols.reset(new SymbolStream(*this, SymbolStreamNum)); + if (auto EC = Symbols->reload()) + return std::move(EC); + } + return *Symbols; +} Index: lib/DebugInfo/PDB/Raw/PublicsStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ lib/DebugInfo/PDB/Raw/PublicsStream.cpp @@ -27,9 +27,11 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Endian.h" @@ -57,7 +59,7 @@ }; -// This is GSIHashHdr struct defined in +// This is GSIHashHdr. struct PublicsStream::GSIHashHeader { enum : unsigned { HdrSignature = ~0U, @@ -69,8 +71,9 @@ ulittle32_t NumBuckets; }; -struct PublicsStream::HRFile { - ulittle32_t Off; +// This is HRFile. +struct PublicsStream::HashRecord { + ulittle32_t Off; // Offset in the symbol record stream ulittle32_t CRef; }; @@ -84,7 +87,7 @@ } PublicsStream::PublicsStream(PDBFile &File, uint32_t StreamNum) - : StreamNum(StreamNum), Stream(StreamNum, File) {} + : Pdb(File), StreamNum(StreamNum), Stream(StreamNum, File) {} PublicsStream::~PublicsStream() {} @@ -114,12 +117,12 @@ return make_error(raw_error_code::corrupt_file, "Publics Stream does not contain a header."); - // An array of HRFile follows. Read them. - if (HashHdr->HrSize % sizeof(HRFile)) + // An array of HashRecord follows. Read them. + if (HashHdr->HrSize % sizeof(HashRecord)) return make_error(raw_error_code::corrupt_file, "Invalid HR array size."); - std::vector HRs(HashHdr->HrSize / sizeof(HRFile)); - if (auto EC = Reader.readArray(HRs)) + HashRecords.resize(HashHdr->HrSize / sizeof(HashRecord)); + if (auto EC = Reader.readArray(HashRecords)) return make_error(raw_error_code::corrupt_file, "Could not read an HR array"); @@ -178,3 +181,20 @@ "Corrupted publics stream."); return Error::success(); } + +std::vector PublicsStream::getSymbols() const { + auto SymbolS = Pdb.getPDBSymbolStream(); + if (SymbolS.takeError()) + return {}; + SymbolStream &SS = SymbolS.get(); + + std::vector Ret; + for (const HashRecord &HR : HashRecords) { + // For some reason, symbol offset is biased by one. + Expected Name = SS.getSymbolName(HR.Off - 1); + if (Name.takeError()) + return Ret; + Ret.push_back(std::move(Name.get())); + } + return Ret; +} Index: lib/DebugInfo/PDB/Raw/SymbolStream.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/Raw/SymbolStream.cpp @@ -0,0 +1,85 @@ +//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===// +// +// 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/SymbolStream.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Raw/StreamReader.h" + +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::pdb; + +// Symbol stream is an array of symbol records. Each record starts with +// length and type fields followed by type-specfic fields. +namespace { +struct SymbolHeader { + ulittle16_t Len; // Record length + ulittle16_t Type; +}; + +// For S_PUB32 symbol type. +struct DataSym32 { + ulittle32_t TypIndex; // Type index, or Metadata token if a managed symbol + ulittle32_t off; + ulittle16_t seg; + char name[1]; +}; + +// For S_PROCREF symbol type. +struct RefSym { + ulittle32_t SumName; // SUC of the name (?) + ulittle32_t SymOffset; // Offset of actual symbol in $$Symbols + ulittle16_t Mod; // Module containing the actual symbol + char name[1]; +}; +} + +SymbolStream::SymbolStream(PDBFile &File, uint32_t StreamNum) + : Stream(StreamNum, File) {} + +SymbolStream::~SymbolStream() {} + +Error SymbolStream::reload() { return Error::success(); } + +static StringRef makeStringRef(char *p) { return {p, strlen(p)}; } + +Expected SymbolStream::getSymbolName(uint32_t Off) const { + StreamReader Reader(Stream); + Reader.setOffset(Off); + + // Read length field. + SymbolHeader Hdr; + if (Reader.readObject(&Hdr)) + return make_error(raw_error_code::corrupt_file, + "Corrupted symbol stream."); + + // Read the entire record. + std::vector Buf(Hdr.Len - sizeof(Hdr.Type)); + if (Reader.readBytes(Buf)) + return make_error(raw_error_code::corrupt_file, + "Corrupted symbol stream."); + + switch (Hdr.Type) { + case codeview::S_PUB32: + return makeStringRef(reinterpret_cast(Buf.data())->name); + case codeview::S_PROCREF: + return makeStringRef(reinterpret_cast(Buf.data())->name); + default: + return make_error(raw_error_code::corrupt_file, + "Unknown symbol type"); + } + return Error::success(); +} Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -317,6 +317,7 @@ ; EMPTY-NEXT: Address Map: [36, 0] ; EMPTY-NEXT: Thunk Map: [4112] ; EMPTY-NEXT: Section Offsets: [4096, 1] +; EMPTY-NEXT: Symbols: [?__purecall@@3PAXA, _main] ; EMPTY-NEXT: } ; BIG: FileHeaders { Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -415,6 +415,7 @@ P.printList("Address Map", Publics.getAddressMap()); P.printList("Thunk Map", Publics.getThunkMap()); P.printList("Section Offsets", Publics.getSectionOffsets()); + P.printList("Symbols", Publics.getSymbols()); return Error::success(); }