Index: include/llvm/DebugInfo/PDB/Raw/DbiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/Raw/ByteStream.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/Support/Endian.h" @@ -54,6 +55,7 @@ MappedBlockStream Stream; std::vector ModuleInfos; + NameHashTable ECNames; ByteStream ModInfoSubstream; ByteStream SecContrSubstream; Index: include/llvm/DebugInfo/PDB/Raw/NameHashTable.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/Raw/NameHashTable.h @@ -0,0 +1,49 @@ +//===- NameHashTable.h - PDB Name Hash Table --------------------*- 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_NAMEHASHTABLE_H +#define LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/Raw/ByteStream.h" + +#include +#include + +namespace llvm { +namespace pdb { +class StreamReader; +class NameHashTable { +public: + NameHashTable(); + + std::error_code load(StreamReader &Stream); + + uint32_t getNameCount() const { return NameCount; } + uint32_t getHashVersion() const { return HashVersion; } + uint32_t getSignature() const { return Signature; } + + StringRef getStringForID(uint32_t ID) const; + uint32_t getIDForString(StringRef Str) const; + + ArrayRef name_ids() const; + +private: + ByteStream NamesBuffer; + std::vector IDs; + uint32_t Signature; + uint32_t HashVersion; + uint32_t NameCount; + uint32_t HashCount; +}; +} +} + +#endif Index: include/llvm/DebugInfo/PDB/Raw/StreamReader.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/StreamReader.h +++ include/llvm/DebugInfo/PDB/Raw/StreamReader.h @@ -34,6 +34,11 @@ return readBytes(Buffer); } + template std::error_code readArray(MutableArrayRef Array) { + MutableArrayRef Casted(reinterpret_cast(Array.data()), Array.size() * sizeof(T)); + return readBytes(Casted); + } + void setOffset(uint32_t Off) { Offset = Off; } uint32_t getOffset() const { return Offset; } uint32_t getLength() const { return Stream.getLength(); } Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -33,6 +33,7 @@ Raw/PDBFile.cpp Raw/DbiStream.cpp Raw/InfoStream.cpp + Raw/NameHashTable.cpp Raw/NameMap.cpp Raw/RawSession.cpp Raw/StreamReader.cpp) Index: lib/DebugInfo/PDB/Raw/DbiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" @@ -148,6 +149,9 @@ if (Reader.bytesRemaining() > 0) return std::make_error_code(std::errc::illegal_byte_sequence); + StreamReader ECReader(ECSubstream); + ECNames.load(ECReader); + return std::error_code(); } Index: lib/DebugInfo/PDB/Raw/NameHashTable.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/Raw/NameHashTable.cpp @@ -0,0 +1,137 @@ +//===- NameHashTable.cpp - PDB Name Hash Table ------------------*- 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/Raw/NameHashTable.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Raw/ByteStream.h" +#include "llvm/DebugInfo/PDB/Raw/StreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::pdb; + +typedef uint32_t *PUL; +typedef uint16_t *PUS; + +static inline uint32_t HashStringV1(StringRef Str) { + uint32_t Result = 0; + uint32_t Size = Str.size(); + + ArrayRef Longs(reinterpret_cast(Str.data()), + Size / 4); + + for (auto Value : Longs) + Result ^= Value; + + const uint8_t *Remainder = reinterpret_cast(Longs.end()); + uint32_t RemainderSize = Size - Longs.size() * 4; + + // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the + // possibly remaining 1 byte. + if (RemainderSize >= 2) { + Result ^= *reinterpret_cast(Remainder); + Remainder += 2; + RemainderSize -= 2; + } + + // hash possible odd byte + if (RemainderSize == 1) { + Result ^= *(Remainder++); + } + + const uint32_t toLowerMask = 0x20202020; + Result |= toLowerMask; + Result ^= (Result >> 11); + + return Result ^ (Result >> 16); +} + +static inline uint32_t HashStringV2(StringRef Str) { + uint32_t Hash = 0xb170a1bf; + + ArrayRef Buffer(Str.begin(), Str.end()); + + ArrayRef Items( + reinterpret_cast(Buffer.data()), + Buffer.size() / sizeof(ulittle32_t)); + for (ulittle32_t Item : Items) { + Hash += Item; + Hash += (Hash << 10); + Hash ^= (Hash >> 6); + } + Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t)); + for (uint8_t Item : Buffer) { + Hash += Item; + Hash += (Hash << 10); + Hash ^= (Hash >> 6); + } + + return Hash * 1664525L + 1013904223L; +} + +NameHashTable::NameHashTable() + : Signature(0), HashVersion(0), NameCount(0), HashCount(0) {} + +std::error_code NameHashTable::load(StreamReader &Stream) { + struct Header { + support::ulittle32_t Signature; + support::ulittle32_t HashVersion; + support::ulittle32_t ByteSize; + }; + + Header H; + Stream.readObject(&H); + if (H.Signature != 0xEFFEEFFE) + return std::make_error_code(std::errc::illegal_byte_sequence); + if (H.HashVersion != 1 && H.HashVersion != 2) + return std::make_error_code(std::errc::not_supported); + + Signature = H.Signature; + HashVersion = H.HashVersion; + NamesBuffer.initialize(Stream, H.ByteSize); + + Stream.readInteger(HashCount); + std::vector BucketArray(HashCount); + Stream.readArray(BucketArray); + IDs.assign(BucketArray.begin(), BucketArray.end()); + + if (Stream.bytesRemaining() < sizeof(support::ulittle32_t)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + Stream.readInteger(NameCount); + return std::error_code(); +} + +StringRef NameHashTable::getStringForID(uint32_t ID) const { + const uint8_t *Start = NamesBuffer.data().data(); + return StringRef(reinterpret_cast(Start + ID)); +} + +uint32_t NameHashTable::getIDForString(StringRef Str) const { + uint32_t Hash = (HashVersion == 1) ? HashStringV1(Str) : HashStringV2(Str); + size_t Count = IDs.size(); + uint32_t Start = Hash % Count; + for (size_t I = 0; I < Count; ++I) { + uint32_t Index = (Start + I) % Count; + if (Index >= IDs.size()) + continue; + + uint32_t NameIndex = IDs[Index]; + StringRef S = getStringForID(NameIndex); + if (S == Str) + return NameIndex; + } + return 0; // 0 is an invalid name index +} + +ArrayRef NameHashTable::name_ids() const { + return ArrayRef(IDs).slice(1, NameCount); +} Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -20,6 +20,11 @@ ; EMPTY: NameStream: 13 ; EMPTY-NEXT: NameStreamSignature: effeeffe ; EMPTY-NEXT: NameStreamVersion: 1 +; EMPTY-NEXT: Name Count: 4 +; EMPTY-NEXT: Name: d:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal) +; EMPTY-NEXT: Name: +; EMPTY-NEXT: Name: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp +; EMPTY-NEXT: Name: ; EMPTY: Dbi Version: 19990903 ; EMPTY-NEXT: Age: 1 @@ -76,6 +81,16 @@ BIG: NameStream: 13 BIG-NEXT: NameStreamSignature: effeeffe BIG-NEXT: NameStreamVersion: 1 +BIG-NEXT: Name Count: 92 +BIG-NEXT: Name: f:\dd\vctools\crt\vcruntime\inc\vcruntime_startup.h +BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\src\misc\checkcfg.c +BIG-NEXT: Name: f:\dd\vctools\langapi\include\isa_availability.h +BIG-NEXT: Name: +BIG-NEXT: Name: $T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = $esp $T1 4 + = +BIG-NEXT: Name: +BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl +BIG-NEXT: Name: $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $20 $T0 40 - ^ = $23 $T0 44 - ^ = $24 $T0 48 - ^ = +BIG-NEXT: Name: $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $23 $T0 16 - ^ = $24 $T0 20 - ^ = BIG: Dbi Version: 19990903 BIG-NEXT: Age: 1 Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -39,6 +39,7 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawSession.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" @@ -147,19 +148,6 @@ cl::cat(FilterCategory)); } - -static void reportError(StringRef Input, StringRef Message) { - if (Input == "-") - Input = ""; - errs() << Input << ": " << Message << "\n"; - errs().flush(); - exit(1); -} - -static void reportError(StringRef Input, std::error_code EC) { - reportError(Input, EC.message()); -} - static void dumpStructure(RawSession &RS) { PDBFile &File = RS.getPDBFile(); @@ -253,19 +241,15 @@ outs() << "NameStream: " << NameStreamIndex << '\n'; - // The name stream appears to start with a signature and version. - uint32_t NameStreamSignature; - Reader.readInteger(NameStreamSignature); + NameHashTable NameTable; + NameTable.load(Reader); outs() << "NameStreamSignature: "; - outs().write_hex(NameStreamSignature) << '\n'; - - uint32_t NameStreamVersion; - Reader.readInteger(NameStreamVersion); - outs() << "NameStreamVersion: " << NameStreamVersion << '\n'; - - // We only support this particular version of the name stream. - if (NameStreamSignature != 0xeffeeffe || NameStreamVersion != 1) - reportError("", std::make_error_code(std::errc::not_supported)); + outs().write_hex(NameTable.getSignature()) << '\n'; + outs() << "NameStreamVersion: " << NameTable.getHashVersion() << '\n'; + outs() << "Name Count: " << NameTable.getNameCount() << '\n'; + for (uint32_t ID : NameTable.name_ids()) { + outs() << "Name: " << NameTable.getStringForID(ID) << '\n'; + } } DbiStream &DS = File.getPDBDbiStream();