mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
[codeview,pdb] Try really hard to conserve memory when reading.
PDBs can be extremely large. We're already mapping the entire PDB into the process's address space, but to make matters worse the blocks of the PDB are not arranged contiguously. So, when we have something like an array or a string embedded into the stream, we have to make a copy. Since it's convenient to use traditional data structures to iterate and manipulate these records, we need the memory to be contiguous. As a result of this, we were using roughly twice as much memory as the file size of the PDB, because every stream was copied out and re-stitched together contiguously. This patch addresses this by improving the MappedBlockStream to allocate from a BumpPtrAllocator only when a read requires a discontiguous read. Furthermore, it introduces some data structures backed by a stream which can iterate over both fixed and variable length records of a PDB. Since everything is backed by a stream and not a buffer, we can read almost everything from the PDB with zero copies. Differential Revision: http://reviews.llvm.org/D20654 Reviewed By: ruiu llvm-svn: 270951
This commit is contained in:
parent
ddc9000626
commit
f070dd590e
@ -24,20 +24,18 @@ class StreamReader;
|
||||
class ByteStream : public StreamInterface {
|
||||
public:
|
||||
ByteStream();
|
||||
explicit ByteStream(MutableArrayRef<uint8_t> Bytes);
|
||||
explicit ByteStream(uint32_t Length);
|
||||
explicit ByteStream(MutableArrayRef<uint8_t> Data);
|
||||
~ByteStream() override;
|
||||
|
||||
void reset();
|
||||
void initialize(MutableArrayRef<uint8_t> Bytes);
|
||||
void initialize(uint32_t Length);
|
||||
Error initialize(StreamReader &Reader, uint32_t Length);
|
||||
|
||||
void load(uint32_t Length);
|
||||
Error load(StreamReader &Reader, uint32_t Length);
|
||||
|
||||
Error readBytes(uint32_t Offset,
|
||||
MutableArrayRef<uint8_t> Buffer) const override;
|
||||
|
||||
Error getArrayRef(uint32_t Offset, ArrayRef<uint8_t> &Buffer,
|
||||
uint32_t Length) const override;
|
||||
Error readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const override;
|
||||
|
||||
uint32_t getLength() const override;
|
||||
|
||||
|
188
include/llvm/DebugInfo/CodeView/StreamArray.h
Normal file
188
include/llvm/DebugInfo/CodeView/StreamArray.h
Normal file
@ -0,0 +1,188 @@
|
||||
//===- StreamArray.h - Array backed by an arbitrary stream ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
/// VarStreamArray represents an array of variable length records backed by a
|
||||
/// stream. This could be a contiguous sequence of bytes in memory, it could
|
||||
/// be a file on disk, or it could be a PDB stream where bytes are stored as
|
||||
/// discontiguous blocks in a file. Usually it is desirable to treat arrays
|
||||
/// as contiguous blocks of memory, but doing so with large PDB files, for
|
||||
/// example, could mean allocating huge amounts of memory just to allow
|
||||
/// re-ordering of stream data to be contiguous before iterating over it. By
|
||||
/// abstracting this out, we need not duplicate this memory, and we can
|
||||
/// iterate over arrays in arbitrarily formatted streams.
|
||||
class VarStreamArrayIterator;
|
||||
|
||||
class VarStreamArray {
|
||||
friend class VarStreamArrayIterator;
|
||||
typedef std::function<uint32_t(const StreamInterface &)> LengthFuncType;
|
||||
|
||||
public:
|
||||
template <typename LengthFunc>
|
||||
VarStreamArray(StreamRef Stream, const LengthFunc &Len)
|
||||
: Stream(Stream), Len(Len) {}
|
||||
|
||||
VarStreamArrayIterator begin() const;
|
||||
VarStreamArrayIterator end() const;
|
||||
|
||||
private:
|
||||
StreamRef Stream;
|
||||
LengthFuncType Len; // Function used to calculate legth of a record
|
||||
};
|
||||
|
||||
class VarStreamArrayIterator {
|
||||
public:
|
||||
VarStreamArrayIterator(const VarStreamArray &Array)
|
||||
: Array(&Array), IterRef(Array.Stream) {
|
||||
ThisLen = Array.Len(IterRef);
|
||||
}
|
||||
VarStreamArrayIterator() : Array(nullptr), IterRef() {}
|
||||
bool operator==(const VarStreamArrayIterator &R) const {
|
||||
if (Array && R.Array) {
|
||||
// Both have a valid array, make sure they're same.
|
||||
assert(Array == R.Array);
|
||||
return IterRef == R.IterRef;
|
||||
}
|
||||
|
||||
// Both iterators are at the end.
|
||||
if (!Array && !R.Array)
|
||||
return true;
|
||||
|
||||
// One is not at the end and one is.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const VarStreamArrayIterator &R) { return !(*this == R); }
|
||||
|
||||
StreamRef operator*() const {
|
||||
ArrayRef<uint8_t> Result;
|
||||
return IterRef.keep_front(ThisLen);
|
||||
}
|
||||
|
||||
VarStreamArrayIterator &operator++() {
|
||||
if (!Array || IterRef.getLength() == 0)
|
||||
return *this;
|
||||
IterRef = IterRef.drop_front(ThisLen);
|
||||
if (IterRef.getLength() == 0) {
|
||||
Array = nullptr;
|
||||
ThisLen = 0;
|
||||
} else {
|
||||
ThisLen = Array->Len(IterRef);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
VarStreamArrayIterator operator++(int) {
|
||||
VarStreamArrayIterator Original = *this;
|
||||
++*this;
|
||||
return Original;
|
||||
}
|
||||
|
||||
private:
|
||||
const VarStreamArray *Array;
|
||||
uint32_t ThisLen;
|
||||
StreamRef IterRef;
|
||||
};
|
||||
|
||||
inline VarStreamArrayIterator VarStreamArray::begin() const {
|
||||
return VarStreamArrayIterator(*this);
|
||||
}
|
||||
inline VarStreamArrayIterator VarStreamArray::end() const {
|
||||
return VarStreamArrayIterator();
|
||||
}
|
||||
|
||||
template <typename T> class FixedStreamArrayIterator;
|
||||
|
||||
template <typename T> class FixedStreamArray {
|
||||
friend class FixedStreamArrayIterator<T>;
|
||||
static_assert(std::is_trivially_constructible<T>::value,
|
||||
"FixedStreamArray must be used with trivial types");
|
||||
|
||||
public:
|
||||
FixedStreamArray() : Stream() {}
|
||||
FixedStreamArray(StreamRef Stream) : Stream(Stream) {
|
||||
assert(Stream.getLength() % sizeof(T) == 0);
|
||||
}
|
||||
|
||||
const T &operator[](uint32_t Index) const {
|
||||
assert(Index < size());
|
||||
uint32_t Off = Index * sizeof(T);
|
||||
ArrayRef<uint8_t> Data;
|
||||
if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) {
|
||||
assert(false && "Unexpected failure reading from stream");
|
||||
// This should never happen since we asserted that the stream length was
|
||||
// an exact multiple of the element size.
|
||||
consumeError(std::move(EC));
|
||||
}
|
||||
return *reinterpret_cast<const T *>(Data.data());
|
||||
}
|
||||
|
||||
uint32_t size() const { return Stream.getLength() / sizeof(T); }
|
||||
|
||||
FixedStreamArrayIterator<T> begin() const {
|
||||
return FixedStreamArrayIterator<T>(*this, 0);
|
||||
}
|
||||
FixedStreamArrayIterator<T> end() const {
|
||||
return FixedStreamArrayIterator<T>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamRef Stream;
|
||||
};
|
||||
|
||||
template <typename T> class FixedStreamArrayIterator {
|
||||
public:
|
||||
FixedStreamArrayIterator(const FixedStreamArray<T> &Array)
|
||||
: Array(Array), Index(uint32_t(-1)) {}
|
||||
FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
|
||||
: Array(Array), Index(Index) {}
|
||||
|
||||
bool operator==(const FixedStreamArrayIterator<T> &R) {
|
||||
assert(&Array == &R.Array);
|
||||
return Index == R.Index;
|
||||
}
|
||||
|
||||
bool operator!=(const FixedStreamArrayIterator<T> &R) {
|
||||
return !(*this == R);
|
||||
}
|
||||
|
||||
const T &operator*() const { return Array[Index]; }
|
||||
|
||||
FixedStreamArrayIterator<T> &operator++() {
|
||||
if (Index == uint32_t(-1))
|
||||
return *this;
|
||||
if (++Index >= Array.size())
|
||||
Index = uint32_t(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedStreamArrayIterator<T> operator++(int) {
|
||||
FixedStreamArrayIterator<T> Original = *this;
|
||||
++*this;
|
||||
return Original;
|
||||
}
|
||||
|
||||
private:
|
||||
const FixedStreamArray<T> &Array;
|
||||
uint32_t Index;
|
||||
};
|
||||
|
||||
} // namespace codeview
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H
|
@ -17,14 +17,21 @@
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
/// StreamInterface abstracts the notion of a data stream. This way, an
|
||||
/// implementation could implement trivial reading from a contiguous memory
|
||||
/// buffer or, as in the case of PDB files, reading from a set of possibly
|
||||
/// discontiguous blocks. The implementation is required to return references
|
||||
/// to stable memory, so if this is not possible (for example in the case of
|
||||
/// a PDB file with discontiguous blocks, it must keep its own pool of temp
|
||||
/// storage.
|
||||
class StreamInterface {
|
||||
public:
|
||||
virtual ~StreamInterface() {}
|
||||
|
||||
virtual Error readBytes(uint32_t Offset,
|
||||
MutableArrayRef<uint8_t> Buffer) const = 0;
|
||||
virtual Error getArrayRef(uint32_t Offset, ArrayRef<uint8_t> &Buffer,
|
||||
uint32_t Length) const = 0;
|
||||
virtual Error readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const = 0;
|
||||
|
||||
virtual uint32_t getLength() const = 0;
|
||||
};
|
||||
|
@ -11,6 +11,8 @@
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamArray.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamInterface.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
@ -20,18 +22,42 @@
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class StreamRef;
|
||||
|
||||
class StreamReader {
|
||||
public:
|
||||
StreamReader(const StreamInterface &S);
|
||||
|
||||
Error readBytes(uint32_t Size, ArrayRef<uint8_t> &Buffer);
|
||||
Error readBytes(MutableArrayRef<uint8_t> Buffer);
|
||||
Error readInteger(uint16_t &Dest);
|
||||
Error readInteger(uint32_t &Dest);
|
||||
Error readZeroString(std::string &Dest);
|
||||
Error readZeroString(StringRef &Dest);
|
||||
Error readFixedString(StringRef &Dest, uint32_t Length);
|
||||
Error readStreamRef(StreamRef &Ref);
|
||||
Error readStreamRef(StreamRef &Ref, uint32_t Length);
|
||||
|
||||
template <typename T> Error readObject(T *Dest) {
|
||||
MutableArrayRef<uint8_t> Buffer(reinterpret_cast<uint8_t *>(Dest),
|
||||
sizeof(T));
|
||||
return readBytes(Buffer);
|
||||
template <typename T> Error readObject(const T *&Dest) {
|
||||
ArrayRef<uint8_t> Buffer;
|
||||
if (auto EC = readBytes(sizeof(T), Buffer))
|
||||
return EC;
|
||||
Dest = reinterpret_cast<const T *>(Buffer.data());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
|
||||
if (NumItems == 0) {
|
||||
Array = FixedStreamArray<T>();
|
||||
return Error::success();
|
||||
}
|
||||
uint32_t Length = NumItems * sizeof(T);
|
||||
if (Offset + Length > Stream.getLength())
|
||||
return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
|
||||
StreamRef View(Stream, Offset, Length);
|
||||
Array = FixedStreamArray<T>(View);
|
||||
Offset += Length;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
template <typename T> Error readArray(MutableArrayRef<T> Array) {
|
||||
@ -40,8 +66,6 @@ public:
|
||||
return readBytes(Casted);
|
||||
}
|
||||
|
||||
Error getArrayRef(ArrayRef<uint8_t> &Array, uint32_t Length);
|
||||
|
||||
void setOffset(uint32_t Off) { Offset = Off; }
|
||||
uint32_t getOffset() const { return Offset; }
|
||||
uint32_t getLength() const { return Stream.getLength(); }
|
||||
|
82
include/llvm/DebugInfo/CodeView/StreamRef.h
Normal file
82
include/llvm/DebugInfo/CodeView/StreamRef.h
Normal file
@ -0,0 +1,82 @@
|
||||
//===- StreamRef.h - A copyable reference to a stream -----------*- 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_CODEVIEW_STREAMREF_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/StreamInterface.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class StreamRef : public StreamInterface {
|
||||
public:
|
||||
StreamRef() : Stream(nullptr), ViewOffset(0), Length(0) {}
|
||||
StreamRef(const StreamInterface &Stream)
|
||||
: Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {}
|
||||
StreamRef(const StreamInterface &Stream, uint32_t Offset, uint32_t Length)
|
||||
: Stream(&Stream), ViewOffset(Offset), Length(Length) {}
|
||||
StreamRef(const StreamRef &Other)
|
||||
: Stream(Other.Stream), ViewOffset(Other.ViewOffset),
|
||||
Length(Other.Length) {}
|
||||
|
||||
Error readBytes(uint32_t Offset,
|
||||
MutableArrayRef<uint8_t> Buffer) const override {
|
||||
return Stream->readBytes(ViewOffset + Offset, Buffer);
|
||||
}
|
||||
|
||||
Error readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const override {
|
||||
return Stream->readBytes(ViewOffset + Offset, Size, Buffer);
|
||||
}
|
||||
|
||||
uint32_t getLength() const override { return Length; }
|
||||
StreamRef drop_front(uint32_t N) const {
|
||||
if (!Stream)
|
||||
return StreamRef();
|
||||
|
||||
N = std::min(N, Length);
|
||||
return StreamRef(*Stream, ViewOffset + N, Length - N);
|
||||
}
|
||||
|
||||
StreamRef keep_front(uint32_t N) const {
|
||||
if (!Stream)
|
||||
return StreamRef();
|
||||
N = std::min(N, Length);
|
||||
return StreamRef(*Stream, ViewOffset, N);
|
||||
}
|
||||
|
||||
bool operator==(const StreamRef &Other) const {
|
||||
if (Stream != Other.Stream)
|
||||
return false;
|
||||
if (ViewOffset != Other.ViewOffset)
|
||||
return false;
|
||||
if (Length != Other.Length)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const StreamRef &Other) const { return !(*this == Other); }
|
||||
|
||||
StreamRef &operator=(const StreamRef &Other) {
|
||||
Stream = Other.Stream;
|
||||
ViewOffset = Other.ViewOffset;
|
||||
Length = Other.Length;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const StreamInterface *Stream;
|
||||
uint32_t ViewOffset;
|
||||
uint32_t Length;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H
|
@ -11,6 +11,8 @@
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/ByteStream.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamArray.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
|
||||
@ -62,15 +64,16 @@ private:
|
||||
std::vector<ModuleInfoEx> ModuleInfos;
|
||||
NameHashTable ECNames;
|
||||
|
||||
codeview::ByteStream ModInfoSubstream;
|
||||
codeview::ByteStream SecContrSubstream;
|
||||
codeview::ByteStream SecMapSubstream;
|
||||
codeview::ByteStream FileInfoSubstream;
|
||||
codeview::ByteStream TypeServerMapSubstream;
|
||||
codeview::ByteStream ECSubstream;
|
||||
codeview::ByteStream DbgHeader;
|
||||
codeview::StreamRef ModInfoSubstream;
|
||||
codeview::StreamRef SecContrSubstream;
|
||||
codeview::StreamRef SecMapSubstream;
|
||||
codeview::StreamRef FileInfoSubstream;
|
||||
codeview::StreamRef TypeServerMapSubstream;
|
||||
codeview::StreamRef ECSubstream;
|
||||
|
||||
std::unique_ptr<HeaderInfo> Header;
|
||||
codeview::FixedStreamArray<support::ulittle16_t> DbgStreams;
|
||||
|
||||
const HeaderInfo *Header;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,9 @@
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamInterface.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
@ -27,14 +29,19 @@ public:
|
||||
|
||||
Error readBytes(uint32_t Offset,
|
||||
MutableArrayRef<uint8_t> Buffer) const override;
|
||||
Error getArrayRef(uint32_t Offset, ArrayRef<uint8_t> &Buffer,
|
||||
uint32_t Length) const override;
|
||||
Error readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const override;
|
||||
|
||||
uint32_t getLength() const override { return StreamLength; }
|
||||
|
||||
private:
|
||||
bool tryReadContiguously(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const;
|
||||
|
||||
uint32_t StreamLength;
|
||||
std::vector<uint32_t> BlockList;
|
||||
mutable llvm::BumpPtrAllocator Pool;
|
||||
mutable DenseMap<uint32_t, uint8_t *> CacheMap;
|
||||
const PDBFile &Pdb;
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@ -22,7 +23,8 @@ private:
|
||||
struct FileLayout;
|
||||
|
||||
public:
|
||||
ModInfo(const uint8_t *Bytes);
|
||||
ModInfo(codeview::StreamRef Stream);
|
||||
ModInfo(const ModInfo &Info);
|
||||
~ModInfo();
|
||||
|
||||
bool hasECInfo() const;
|
||||
@ -38,32 +40,26 @@ public:
|
||||
StringRef getModuleName() const;
|
||||
StringRef getObjFileName() const;
|
||||
|
||||
uint32_t getRecordLength() const;
|
||||
|
||||
private:
|
||||
StringRef ModuleName;
|
||||
StringRef ObjFileName;
|
||||
const FileLayout *Layout;
|
||||
};
|
||||
|
||||
struct ModuleInfoEx {
|
||||
ModuleInfoEx(ModInfo Module) : Info(Module) {}
|
||||
ModuleInfoEx(codeview::StreamRef Stream) : Info(Stream) {}
|
||||
ModuleInfoEx(const ModuleInfoEx &Ex)
|
||||
: Info(Ex.Info), SourceFiles(Ex.SourceFiles) {}
|
||||
|
||||
ModInfo Info;
|
||||
std::vector<StringRef> SourceFiles;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
inline uint32_t ModInfoRecordLength(const codeview::StreamInterface &Stream) {
|
||||
return ModInfo(Stream).getRecordLength();
|
||||
}
|
||||
|
||||
} // end namespace pdb
|
||||
} // end namespace llvm
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/CodeView/ByteStream.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
@ -36,9 +37,9 @@ private:
|
||||
MappedBlockStream Stream;
|
||||
|
||||
codeview::ByteStream SymbolsSubstream;
|
||||
codeview::ByteStream LinesSubstream;
|
||||
codeview::ByteStream C13LinesSubstream;
|
||||
codeview::ByteStream GlobalRefsSubstream;
|
||||
codeview::StreamRef LinesSubstream;
|
||||
codeview::StreamRef C13LinesSubstream;
|
||||
codeview::StreamRef GlobalRefsSubstream;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/ByteStream.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
@ -39,7 +39,7 @@ public:
|
||||
ArrayRef<uint32_t> name_ids() const;
|
||||
|
||||
private:
|
||||
codeview::ByteStream NamesBuffer;
|
||||
codeview::StreamRef NamesBuffer;
|
||||
std::vector<uint32_t> IDs;
|
||||
uint32_t Signature;
|
||||
uint32_t HashVersion;
|
||||
|
@ -57,8 +57,8 @@ private:
|
||||
std::vector<uint32_t> ThunkMap;
|
||||
std::vector<uint32_t> SectionOffsets;
|
||||
|
||||
std::unique_ptr<HeaderInfo> Header;
|
||||
std::unique_ptr<GSIHashHeader> HashHdr;
|
||||
const HeaderInfo *Header;
|
||||
const GSIHashHeader *HashHdr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/ByteStream.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeStream.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
||||
@ -48,11 +49,11 @@ private:
|
||||
HashFunctionType HashFunction;
|
||||
|
||||
codeview::ByteStream RecordsBuffer;
|
||||
codeview::ByteStream TypeIndexOffsetBuffer;
|
||||
codeview::ByteStream HashValuesBuffer;
|
||||
codeview::ByteStream HashAdjBuffer;
|
||||
codeview::StreamRef TypeIndexOffsetBuffer;
|
||||
codeview::StreamRef HashValuesBuffer;
|
||||
codeview::StreamRef HashAdjBuffer;
|
||||
|
||||
std::unique_ptr<HeaderInfo> Header;
|
||||
const HeaderInfo *Header;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -17,31 +17,24 @@ using namespace llvm::codeview;
|
||||
|
||||
ByteStream::ByteStream() {}
|
||||
|
||||
ByteStream::ByteStream(MutableArrayRef<uint8_t> Bytes) { initialize(Bytes); }
|
||||
ByteStream::ByteStream(MutableArrayRef<uint8_t> Data) : Data(Data) {}
|
||||
|
||||
ByteStream::ByteStream(uint32_t Length) { initialize(Length); }
|
||||
|
||||
ByteStream::~ByteStream() { reset(); }
|
||||
ByteStream::~ByteStream() {}
|
||||
|
||||
void ByteStream::reset() {
|
||||
Ownership.reset();
|
||||
Data = MutableArrayRef<uint8_t>();
|
||||
}
|
||||
|
||||
void ByteStream::initialize(MutableArrayRef<uint8_t> Bytes) {
|
||||
reset();
|
||||
Data = Bytes;
|
||||
}
|
||||
|
||||
void ByteStream::initialize(uint32_t Length) {
|
||||
void ByteStream::load(uint32_t Length) {
|
||||
reset();
|
||||
if (Length > 0)
|
||||
Data = MutableArrayRef<uint8_t>(new uint8_t[Length], Length);
|
||||
Ownership.reset(Data.data());
|
||||
}
|
||||
|
||||
Error ByteStream::initialize(StreamReader &Reader, uint32_t Length) {
|
||||
initialize(Length);
|
||||
Error ByteStream::load(StreamReader &Reader, uint32_t Length) {
|
||||
load(Length);
|
||||
auto EC = Reader.readBytes(Data);
|
||||
if (EC)
|
||||
reset();
|
||||
@ -52,15 +45,15 @@ Error ByteStream::readBytes(uint32_t Offset,
|
||||
MutableArrayRef<uint8_t> Buffer) const {
|
||||
if (Data.size() < Buffer.size() + Offset)
|
||||
return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
|
||||
::memcpy(Buffer.data(), Data.data() + Offset, Buffer.size());
|
||||
::memcpy(Buffer.data() + Offset, Data.data(), Buffer.size());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error ByteStream::getArrayRef(uint32_t Offset, ArrayRef<uint8_t> &Buffer,
|
||||
uint32_t Length) const {
|
||||
if (Data.size() < Length + Offset)
|
||||
Error ByteStream::readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const {
|
||||
if (Data.size() < Buffer.size() + Offset)
|
||||
return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
|
||||
Buffer = Data.slice(Offset, Length);
|
||||
Buffer = Data.slice(Offset, Size);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,20 @@
|
||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
StreamReader::StreamReader(const StreamInterface &S) : Stream(S), Offset(0) {}
|
||||
|
||||
Error StreamReader::readBytes(uint32_t Size, ArrayRef<uint8_t> &Buffer) {
|
||||
if (auto EC = Stream.readBytes(Offset, Size, Buffer))
|
||||
return EC;
|
||||
Offset += Size;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error StreamReader::readBytes(MutableArrayRef<uint8_t> Buffer) {
|
||||
if (auto EC = Stream.readBytes(Offset, Buffer))
|
||||
return EC;
|
||||
@ -23,29 +31,63 @@ Error StreamReader::readBytes(MutableArrayRef<uint8_t> Buffer) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error StreamReader::readInteger(uint16_t &Dest) {
|
||||
const support::ulittle16_t *P;
|
||||
if (auto EC = readObject(P))
|
||||
return EC;
|
||||
Dest = *P;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error StreamReader::readInteger(uint32_t &Dest) {
|
||||
support::ulittle32_t P;
|
||||
if (auto EC = readObject(&P))
|
||||
const support::ulittle32_t *P;
|
||||
if (auto EC = readObject(P))
|
||||
return EC;
|
||||
Dest = P;
|
||||
Dest = *P;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error StreamReader::readZeroString(std::string &Dest) {
|
||||
Dest.clear();
|
||||
char C;
|
||||
Error StreamReader::readZeroString(StringRef &Dest) {
|
||||
uint32_t Length = 0;
|
||||
// First compute the length of the string by reading 1 byte at a time.
|
||||
uint32_t OriginalOffset = getOffset();
|
||||
const char *C;
|
||||
do {
|
||||
if (auto EC = readObject(&C))
|
||||
if (auto EC = readObject(C))
|
||||
return EC;
|
||||
if (C != '\0')
|
||||
Dest.push_back(C);
|
||||
} while (C != '\0');
|
||||
if (*C != '\0')
|
||||
++Length;
|
||||
} while (*C != '\0');
|
||||
// Now go back and request a reference for that many bytes.
|
||||
uint32_t NewOffset = getOffset();
|
||||
setOffset(OriginalOffset);
|
||||
|
||||
ArrayRef<uint8_t> Data;
|
||||
if (auto EC = readBytes(Length, Data))
|
||||
return EC;
|
||||
Dest = StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size());
|
||||
|
||||
// Now set the offset back to where it was after we calculated the length.
|
||||
setOffset(NewOffset);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error StreamReader::getArrayRef(ArrayRef<uint8_t> &Array, uint32_t Length) {
|
||||
if (auto EC = Stream.getArrayRef(Offset, Array, Length))
|
||||
Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
|
||||
ArrayRef<uint8_t> Bytes;
|
||||
if (auto EC = readBytes(Length, Bytes))
|
||||
return EC;
|
||||
Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error StreamReader::readStreamRef(StreamRef &Ref) {
|
||||
return readStreamRef(Ref, bytesRemaining());
|
||||
}
|
||||
|
||||
Error StreamReader::readStreamRef(StreamRef &Ref, uint32_t Length) {
|
||||
if (bytesRemaining() < Length)
|
||||
return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
|
||||
Ref = StreamRef(Stream, Offset, Length);
|
||||
Offset += Length;
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ add_pdb_impl_folder(Raw
|
||||
Raw/SymbolStream.cpp
|
||||
Raw/TpiStream.cpp)
|
||||
|
||||
list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Raw")
|
||||
list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB")
|
||||
|
||||
add_llvm_library(LLVMDebugInfoPDB
|
||||
|
@ -6,9 +6,9 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/StreamArray.h"
|
||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
|
||||
@ -73,7 +73,8 @@ struct DbiStream::HeaderInfo {
|
||||
ulittle32_t Reserved; // Pad to 64 bytes
|
||||
};
|
||||
|
||||
DbiStream::DbiStream(PDBFile &File) : Pdb(File), Stream(StreamDBI, File) {
|
||||
DbiStream::DbiStream(PDBFile &File)
|
||||
: Pdb(File), Stream(StreamDBI, File), Header(nullptr) {
|
||||
static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!");
|
||||
}
|
||||
|
||||
@ -82,12 +83,10 @@ DbiStream::~DbiStream() {}
|
||||
Error DbiStream::reload() {
|
||||
codeview::StreamReader Reader(Stream);
|
||||
|
||||
Header.reset(new HeaderInfo());
|
||||
|
||||
if (Stream.getLength() < sizeof(HeaderInfo))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI Stream does not contain a header.");
|
||||
if (auto EC = Reader.readObject(Header.get()))
|
||||
if (auto EC = Reader.readObject(Header))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI Stream does not contain a header.");
|
||||
|
||||
@ -137,30 +136,31 @@ Error DbiStream::reload() {
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI type server substream not aligned.");
|
||||
|
||||
if (auto EC = ModInfoSubstream.initialize(Reader, Header->ModiSubstreamSize))
|
||||
if (auto EC =
|
||||
Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize))
|
||||
return EC;
|
||||
|
||||
// Since each ModInfo in the stream is a variable length, we have to iterate
|
||||
// them to know how many there actually are.
|
||||
auto Range =
|
||||
llvm::make_range(ModInfoIterator(&ModInfoSubstream.data().front()),
|
||||
ModInfoIterator(&ModInfoSubstream.data().back() + 1));
|
||||
for (auto Info : Range)
|
||||
ModuleInfos.push_back(ModuleInfoEx(Info));
|
||||
codeview::VarStreamArray ModInfoArray(ModInfoSubstream, ModInfoRecordLength);
|
||||
for (auto Info : ModInfoArray) {
|
||||
ModuleInfos.emplace_back(Info);
|
||||
}
|
||||
|
||||
if (auto EC =
|
||||
SecContrSubstream.initialize(Reader, Header->SecContrSubstreamSize))
|
||||
if (auto EC = Reader.readStreamRef(SecContrSubstream,
|
||||
Header->SecContrSubstreamSize))
|
||||
return EC;
|
||||
if (auto EC = SecMapSubstream.initialize(Reader, Header->SectionMapSize))
|
||||
if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize))
|
||||
return EC;
|
||||
if (auto EC = FileInfoSubstream.initialize(Reader, Header->FileInfoSize))
|
||||
if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize))
|
||||
return EC;
|
||||
if (auto EC =
|
||||
TypeServerMapSubstream.initialize(Reader, Header->TypeServerSize))
|
||||
Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize))
|
||||
return EC;
|
||||
if (auto EC = ECSubstream.initialize(Reader, Header->ECSubstreamSize))
|
||||
if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize))
|
||||
return EC;
|
||||
if (auto EC = DbgHeader.initialize(Reader, Header->OptionalDbgHdrSize))
|
||||
if (auto EC = Reader.readArray(DbgStreams, Header->OptionalDbgHdrSize /
|
||||
sizeof(ulittle16_t)))
|
||||
return EC;
|
||||
|
||||
if (auto EC = initializeFileInfo())
|
||||
@ -247,25 +247,30 @@ Error DbiStream::initializeFileInfo() {
|
||||
// with the caveat that `NumSourceFiles` cannot be trusted, so
|
||||
// it is computed by summing `ModFileCounts`.
|
||||
//
|
||||
const uint8_t *Buf = &FileInfoSubstream.data().front();
|
||||
auto FI = reinterpret_cast<const FileInfoSubstreamHeader *>(Buf);
|
||||
Buf += sizeof(FileInfoSubstreamHeader);
|
||||
const FileInfoSubstreamHeader *FH;
|
||||
codeview::StreamReader FISR(FileInfoSubstream);
|
||||
if (auto EC = FISR.readObject(FH))
|
||||
return EC;
|
||||
|
||||
// The number of modules in the stream should be the same as reported by
|
||||
// the FileInfoSubstreamHeader.
|
||||
if (FI->NumModules != ModuleInfos.size())
|
||||
if (FH->NumModules != ModuleInfos.size())
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"FileInfo substream count doesn't match DBI.");
|
||||
|
||||
codeview::FixedStreamArray<ulittle16_t> ModIndexArray;
|
||||
codeview::FixedStreamArray<ulittle16_t> ModFileCountArray;
|
||||
codeview::FixedStreamArray<little32_t> FileNameOffsets;
|
||||
|
||||
// First is an array of `NumModules` module indices. This is not used for the
|
||||
// same reason that `NumSourceFiles` is not used. It's an array of uint16's,
|
||||
// but it's possible there are more than 64k source files, which would imply
|
||||
// more than 64k modules (e.g. object files) as well. So we ignore this
|
||||
// field.
|
||||
llvm::ArrayRef<ulittle16_t> ModIndexArray(
|
||||
reinterpret_cast<const ulittle16_t *>(Buf), ModuleInfos.size());
|
||||
|
||||
llvm::ArrayRef<ulittle16_t> ModFileCountArray(ModIndexArray.end(),
|
||||
ModuleInfos.size());
|
||||
if (auto EC = FISR.readArray(ModIndexArray, ModuleInfos.size()))
|
||||
return EC;
|
||||
if (auto EC = FISR.readArray(ModFileCountArray, ModuleInfos.size()))
|
||||
return EC;
|
||||
|
||||
// Compute the real number of source files.
|
||||
uint32_t NumSourceFiles = 0;
|
||||
@ -280,11 +285,13 @@ Error DbiStream::initializeFileInfo() {
|
||||
// them in `ModuleInfoEx`. The value written to and read from the file is
|
||||
// not used anyway, it is only there as a way to store the offsets for the
|
||||
// purposes of later accessing the names at runtime.
|
||||
llvm::ArrayRef<little32_t> FileNameOffsets(
|
||||
reinterpret_cast<const little32_t *>(ModFileCountArray.end()),
|
||||
NumSourceFiles);
|
||||
if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
|
||||
return EC;
|
||||
|
||||
const char *Names = reinterpret_cast<const char *>(FileNameOffsets.end());
|
||||
codeview::StreamRef NamesBufferRef;
|
||||
if (auto EC = FISR.readStreamRef(NamesBufferRef))
|
||||
return EC;
|
||||
codeview::StreamReader Names(NamesBufferRef);
|
||||
|
||||
// We go through each ModuleInfo, determine the number N of source files for
|
||||
// that module, and then get the next N offsets from the Offsets array, using
|
||||
@ -295,8 +302,10 @@ Error DbiStream::initializeFileInfo() {
|
||||
uint32_t NumFiles = ModFileCountArray[I];
|
||||
ModuleInfos[I].SourceFiles.resize(NumFiles);
|
||||
for (size_t J = 0; J < NumFiles; ++J, ++NextFileIndex) {
|
||||
uint32_t FileIndex = FileNameOffsets[NextFileIndex];
|
||||
ModuleInfos[I].SourceFiles[J] = StringRef(Names + FileIndex);
|
||||
uint32_t FileOffset = FileNameOffsets[NextFileIndex];
|
||||
Names.setOffset(FileOffset);
|
||||
if (auto EC = Names.readZeroString(ModuleInfos[I].SourceFiles[J]))
|
||||
return EC;
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,13 +313,5 @@ Error DbiStream::initializeFileInfo() {
|
||||
}
|
||||
|
||||
uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
|
||||
ArrayRef<uint8_t> DbgData;
|
||||
if (auto EC = DbgHeader.getArrayRef(0, DbgData, DbgHeader.getLength())) {
|
||||
consumeError(std::move(EC));
|
||||
return uint32_t(-1);
|
||||
}
|
||||
ArrayRef<ulittle16_t> DebugStreams(
|
||||
reinterpret_cast<const ulittle16_t *>(DbgData.data()),
|
||||
DbgData.size() / sizeof(ulittle16_t));
|
||||
return DebugStreams[static_cast<uint16_t>(Type)];
|
||||
return DbgStreams[static_cast<uint16_t>(Type)];
|
||||
}
|
||||
|
@ -29,19 +29,19 @@ Error InfoStream::reload() {
|
||||
PDB_UniqueId Guid;
|
||||
};
|
||||
|
||||
Header H;
|
||||
if (auto EC = Reader.readObject(&H))
|
||||
const Header *H;
|
||||
if (auto EC = Reader.readObject(H))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"PDB Stream does not contain a header.");
|
||||
|
||||
if (H.Version < PdbRaw_ImplVer::PdbImplVC70)
|
||||
if (H->Version < PdbRaw_ImplVer::PdbImplVC70)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Unsupported PDB stream version.");
|
||||
|
||||
Version = H.Version;
|
||||
Signature = H.Signature;
|
||||
Age = H.Age;
|
||||
Guid = H.Guid;
|
||||
Version = H->Version;
|
||||
Signature = H->Signature;
|
||||
Age = H->Age;
|
||||
Guid = H->Guid;
|
||||
|
||||
return NamedStreams.load(Reader);
|
||||
}
|
||||
|
@ -23,6 +23,69 @@ MappedBlockStream::MappedBlockStream(uint32_t StreamIdx, const PDBFile &File) :
|
||||
}
|
||||
}
|
||||
|
||||
Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const {
|
||||
// Make sure we aren't trying to read beyond the end of the stream.
|
||||
if (Buffer.size() > StreamLength)
|
||||
return make_error<RawError>(raw_error_code::insufficient_buffer);
|
||||
if (Offset > StreamLength - Buffer.size())
|
||||
return make_error<RawError>(raw_error_code::insufficient_buffer);
|
||||
|
||||
if (tryReadContiguously(Offset, Size, Buffer))
|
||||
return Error::success();
|
||||
|
||||
auto CacheIter = CacheMap.find(Offset);
|
||||
if (CacheIter != CacheMap.end()) {
|
||||
// In a more general solution, we would need to guarantee that the
|
||||
// cached allocation is at least the requested size. In practice, since
|
||||
// these are CodeView / PDB records, we know they are always formatted
|
||||
// the same way and never change, so we should never be requesting two
|
||||
// allocations from the same address with different sizes.
|
||||
Buffer = ArrayRef<uint8_t>(CacheIter->second, Size);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Otherwise allocate a large enough buffer in the pool, memcpy the data
|
||||
// into it, and return an ArrayRef to that.
|
||||
uint8_t *WriteBuffer = Pool.Allocate<uint8_t>(Size);
|
||||
|
||||
if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size)))
|
||||
return EC;
|
||||
CacheMap.insert(std::make_pair(Offset, WriteBuffer));
|
||||
Buffer = ArrayRef<uint8_t>(WriteBuffer, Size);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size,
|
||||
ArrayRef<uint8_t> &Buffer) const {
|
||||
// Attempt to fulfill the request with a reference directly into the stream.
|
||||
// This can work even if the request crosses a block boundary, provided that
|
||||
// all subsequent blocks are contiguous. For example, a 10k read with a 4k
|
||||
// block size can be filled with a reference if, from the starting offset,
|
||||
// 3 blocks in a row are contiguous.
|
||||
uint32_t BlockNum = Offset / Pdb.getBlockSize();
|
||||
uint32_t OffsetInBlock = Offset % Pdb.getBlockSize();
|
||||
uint32_t BytesFromFirstBlock =
|
||||
std::min(Size, Pdb.getBlockSize() - OffsetInBlock);
|
||||
uint32_t NumAdditionalBlocks =
|
||||
llvm::alignTo(Size - BytesFromFirstBlock, Pdb.getBlockSize()) /
|
||||
Pdb.getBlockSize();
|
||||
|
||||
uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1;
|
||||
uint32_t E = BlockList[BlockNum];
|
||||
for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) {
|
||||
if (BlockList[I + BlockNum] != E)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t FirstBlockAddr = BlockList[BlockNum];
|
||||
StringRef Str = Pdb.getBlockData(FirstBlockAddr, Pdb.getBlockSize());
|
||||
Str = Str.drop_front(OffsetInBlock);
|
||||
Buffer =
|
||||
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Str.data()), Size);
|
||||
return true;
|
||||
}
|
||||
|
||||
Error MappedBlockStream::readBytes(uint32_t Offset,
|
||||
MutableArrayRef<uint8_t> Buffer) const {
|
||||
uint32_t BlockNum = Offset / Pdb.getBlockSize();
|
||||
@ -54,27 +117,5 @@ Error MappedBlockStream::readBytes(uint32_t Offset,
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MappedBlockStream::getArrayRef(uint32_t Offset, ArrayRef<uint8_t> &Buffer,
|
||||
uint32_t Length) const {
|
||||
uint32_t BlockNum = Offset / Pdb.getBlockSize();
|
||||
uint32_t OffsetInBlock = Offset % Pdb.getBlockSize();
|
||||
uint32_t BytesAvailableInBlock = Pdb.getBlockSize() - OffsetInBlock;
|
||||
|
||||
// If this is the last block in the stream, not all of the data is valid.
|
||||
if (BlockNum == BlockList.size() - 1) {
|
||||
uint32_t AllocatedBytesInBlock = StreamLength % Pdb.getBlockSize();
|
||||
if (AllocatedBytesInBlock < BytesAvailableInBlock)
|
||||
BytesAvailableInBlock = AllocatedBytesInBlock;
|
||||
}
|
||||
if (BytesAvailableInBlock < Length)
|
||||
return make_error<RawError>(raw_error_code::feature_unsupported);
|
||||
|
||||
uint32_t StreamBlockAddr = BlockList[BlockNum];
|
||||
StringRef Data = Pdb.getBlockData(StreamBlockAddr, Pdb.getBlockSize());
|
||||
Data = Data.substr(OffsetInBlock, Length);
|
||||
|
||||
Buffer = ArrayRef<uint8_t>(Data.bytes_begin(), Data.bytes_end());
|
||||
return Error::success();
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
@ -16,6 +18,7 @@ using namespace llvm::pdb;
|
||||
using namespace llvm::support;
|
||||
|
||||
namespace {
|
||||
|
||||
struct SCBytes {
|
||||
ulittle16_t Section;
|
||||
char Padding1[2];
|
||||
@ -60,17 +63,29 @@ struct ModInfo::FileLayout {
|
||||
// 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);
|
||||
}
|
||||
// Null terminated Module name
|
||||
// Null terminated Obj File Name
|
||||
};
|
||||
|
||||
ModInfo::ModInfo(const uint8_t *Bytes)
|
||||
: Layout(reinterpret_cast<const FileLayout *>(Bytes)) {}
|
||||
ModInfo::ModInfo(codeview::StreamRef Stream) : Layout(nullptr) {
|
||||
codeview::StreamReader Reader(Stream);
|
||||
if (auto EC = Reader.readObject(Layout)) {
|
||||
consumeError(std::move(EC));
|
||||
return;
|
||||
}
|
||||
if (auto EC = Reader.readZeroString(ModuleName)) {
|
||||
consumeError(std::move(EC));
|
||||
return;
|
||||
}
|
||||
if (auto EC = Reader.readZeroString(ObjFileName)) {
|
||||
consumeError(std::move(EC));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ModInfo::ModInfo(const ModInfo &Info)
|
||||
: ModuleName(Info.ModuleName), ObjFileName(Info.ObjFileName),
|
||||
Layout(Info.Layout) {}
|
||||
|
||||
ModInfo::~ModInfo() {}
|
||||
|
||||
@ -100,44 +115,14 @@ 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;
|
||||
StringRef ModInfo::getModuleName() const { return ModuleName; }
|
||||
|
||||
StringRef ModInfo::getObjFileName() const { return ObjFileName; }
|
||||
|
||||
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;
|
||||
Size = llvm::alignTo(Size, 4);
|
||||
return Size;
|
||||
}
|
||||
|
@ -32,17 +32,17 @@ Error ModStream::reload() {
|
||||
return llvm::make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Module has both C11 and C13 line info");
|
||||
|
||||
if (auto EC = SymbolsSubstream.initialize(Reader, SymbolSize))
|
||||
if (auto EC = SymbolsSubstream.load(Reader, SymbolSize))
|
||||
return EC;
|
||||
if (auto EC = LinesSubstream.initialize(Reader, C11Size))
|
||||
if (auto EC = Reader.readStreamRef(LinesSubstream, C11Size))
|
||||
return EC;
|
||||
if (auto EC = C13LinesSubstream.initialize(Reader, C13Size))
|
||||
if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size))
|
||||
return EC;
|
||||
|
||||
uint32_t GlobalRefsSize;
|
||||
if (auto EC = Reader.readInteger(GlobalRefsSize))
|
||||
return EC;
|
||||
if (auto EC = GlobalRefsSubstream.initialize(Reader, GlobalRefsSize))
|
||||
if (auto EC = Reader.readStreamRef(GlobalRefsSubstream, GlobalRefsSize))
|
||||
return EC;
|
||||
if (Reader.bytesRemaining() > 0)
|
||||
return llvm::make_error<RawError>(raw_error_code::corrupt_file,
|
||||
|
@ -84,28 +84,28 @@ Error NameHashTable::load(codeview::StreamReader &Stream) {
|
||||
support::ulittle32_t ByteSize;
|
||||
};
|
||||
|
||||
Header H;
|
||||
if (auto EC = Stream.readObject(&H))
|
||||
const Header *H;
|
||||
if (auto EC = Stream.readObject(H))
|
||||
return EC;
|
||||
|
||||
if (H.Signature != 0xEFFEEFFE)
|
||||
if (H->Signature != 0xEFFEEFFE)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid hash table signature");
|
||||
if (H.HashVersion != 1 && H.HashVersion != 2)
|
||||
if (H->HashVersion != 1 && H->HashVersion != 2)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Unsupported hash version");
|
||||
|
||||
Signature = H.Signature;
|
||||
HashVersion = H.HashVersion;
|
||||
if (auto EC = NamesBuffer.initialize(Stream, H.ByteSize))
|
||||
Signature = H->Signature;
|
||||
HashVersion = H->HashVersion;
|
||||
if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid hash table byte length");
|
||||
|
||||
support::ulittle32_t HashCount;
|
||||
if (auto EC = Stream.readObject(&HashCount))
|
||||
const support::ulittle32_t *HashCount;
|
||||
if (auto EC = Stream.readObject(HashCount))
|
||||
return EC;
|
||||
|
||||
std::vector<support::ulittle32_t> BucketArray(HashCount);
|
||||
std::vector<support::ulittle32_t> BucketArray(*HashCount);
|
||||
if (auto EC = Stream.readArray<support::ulittle32_t>(BucketArray))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Could not read bucket array");
|
||||
@ -124,7 +124,15 @@ StringRef NameHashTable::getStringForID(uint32_t ID) const {
|
||||
if (ID == IDs[0])
|
||||
return StringRef();
|
||||
|
||||
return StringRef(NamesBuffer.str().begin() + ID);
|
||||
// NamesBuffer is a buffer of null terminated strings back to back. ID is
|
||||
// the starting offset of the string we're looking for. So just seek into
|
||||
// the desired offset and a read a null terminated stream from that offset.
|
||||
StringRef Result;
|
||||
codeview::StreamReader NameReader(NamesBuffer);
|
||||
NameReader.setOffset(ID);
|
||||
if (auto EC = NameReader.readZeroString(Result))
|
||||
consumeError(std::move(EC));
|
||||
return Result;
|
||||
}
|
||||
|
||||
uint32_t NameHashTable::getIDForString(StringRef Str) const {
|
||||
|
@ -113,7 +113,7 @@ Error NameMap::load(codeview::StreamReader &Stream) {
|
||||
uint32_t StringOffset = StringsOffset + NameOffset;
|
||||
uint32_t OldOffset = Stream.getOffset();
|
||||
// Pump out our c-string from the stream.
|
||||
std::string Str;
|
||||
StringRef Str;
|
||||
Stream.setOffset(StringOffset);
|
||||
if (Stream.readZeroString(Str))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
|
@ -107,12 +107,11 @@ Error PublicsStream::reload() {
|
||||
"Publics Stream does not contain a header.");
|
||||
|
||||
// Read PSGSIHDR and GSIHashHdr structs.
|
||||
Header.reset(new HeaderInfo());
|
||||
if (Reader.readObject(Header.get()))
|
||||
if (Reader.readObject(Header))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Publics Stream does not contain a header.");
|
||||
HashHdr.reset(new GSIHashHeader());
|
||||
if (Reader.readObject(HashHdr.get()))
|
||||
|
||||
if (Reader.readObject(HashHdr))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Publics Stream does not contain a header.");
|
||||
|
||||
|
@ -30,7 +30,7 @@ SymbolStream::~SymbolStream() {}
|
||||
Error SymbolStream::reload() {
|
||||
codeview::StreamReader Reader(MappedStream);
|
||||
|
||||
if (Stream.initialize(Reader, MappedStream.getLength()))
|
||||
if (Stream.load(Reader, MappedStream.getLength()))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Could not load symbol stream.");
|
||||
|
||||
@ -40,7 +40,7 @@ Error SymbolStream::reload() {
|
||||
iterator_range<codeview::SymbolIterator> SymbolStream::getSymbols() const {
|
||||
using codeview::SymbolIterator;
|
||||
ArrayRef<uint8_t> Data;
|
||||
if (auto Error = Stream.getArrayRef(0, Data, Stream.getLength())) {
|
||||
if (auto Error = Stream.readBytes(0, Stream.getLength(), Data)) {
|
||||
consumeError(std::move(Error));
|
||||
return iterator_range<SymbolIterator>(SymbolIterator(), SymbolIterator());
|
||||
}
|
||||
|
@ -68,8 +68,7 @@ Error TpiStream::reload() {
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"TPI Stream does not contain a header.");
|
||||
|
||||
Header.reset(new HeaderInfo());
|
||||
if (Reader.readObject(Header.get()))
|
||||
if (Reader.readObject(Header))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"TPI Stream does not contain a header.");
|
||||
|
||||
@ -93,7 +92,7 @@ Error TpiStream::reload() {
|
||||
HashFunction = HashBufferV8;
|
||||
|
||||
// The actual type records themselves come from this stream
|
||||
if (auto EC = RecordsBuffer.initialize(Reader, Header->TypeRecordBytes))
|
||||
if (auto EC = RecordsBuffer.load(Reader, Header->TypeRecordBytes))
|
||||
return EC;
|
||||
|
||||
// Hash indices, hash values, etc come from the hash stream.
|
||||
@ -101,16 +100,16 @@ Error TpiStream::reload() {
|
||||
codeview::StreamReader HSR(HS);
|
||||
HSR.setOffset(Header->HashValueBuffer.Off);
|
||||
if (auto EC =
|
||||
HashValuesBuffer.initialize(HSR, Header->HashValueBuffer.Length))
|
||||
HSR.readStreamRef(HashValuesBuffer, Header->HashValueBuffer.Length))
|
||||
return EC;
|
||||
|
||||
HSR.setOffset(Header->HashAdjBuffer.Off);
|
||||
if (auto EC = HashAdjBuffer.initialize(HSR, Header->HashAdjBuffer.Length))
|
||||
if (auto EC = HSR.readStreamRef(HashAdjBuffer, Header->HashAdjBuffer.Length))
|
||||
return EC;
|
||||
|
||||
HSR.setOffset(Header->IndexOffsetBuffer.Off);
|
||||
if (auto EC = TypeIndexOffsetBuffer.initialize(
|
||||
HSR, Header->IndexOffsetBuffer.Length))
|
||||
if (auto EC = HSR.readStreamRef(TypeIndexOffsetBuffer,
|
||||
Header->IndexOffsetBuffer.Length))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
|
@ -305,7 +305,7 @@ static Error dumpStreamSummary(ScopedPrinter &P, PDBFile &File) {
|
||||
auto NSIter = NamedStreams.find(StreamIdx);
|
||||
if (ModIter != ModStreams.end()) {
|
||||
Value = "Module \"";
|
||||
Value += ModIter->second->Info.getModuleName();
|
||||
Value += ModIter->second->Info.getModuleName().str();
|
||||
Value += "\"";
|
||||
} else if (NSIter != NamedStreams.end()) {
|
||||
Value = "Named Stream \"";
|
||||
@ -354,7 +354,7 @@ static Error dumpStreamData(ScopedPrinter &P, PDBFile &File) {
|
||||
ArrayRef<uint8_t> Data;
|
||||
uint32_t BytesToReadInBlock = std::min(
|
||||
R.bytesRemaining(), static_cast<uint32_t>(File.getBlockSize()));
|
||||
if (auto EC = R.getArrayRef(Data, BytesToReadInBlock))
|
||||
if (auto EC = R.readBytes(BytesToReadInBlock, Data))
|
||||
return EC;
|
||||
P.printBinaryBlock(
|
||||
"Data",
|
||||
@ -455,9 +455,9 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
|
||||
ListScope L(P, "Modules");
|
||||
for (auto &Modi : DS.modules()) {
|
||||
DictScope DD(P);
|
||||
P.printString("Name", Modi.Info.getModuleName());
|
||||
P.printString("Name", Modi.Info.getModuleName().str());
|
||||
P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex());
|
||||
P.printString("Object File Name", Modi.Info.getObjFileName());
|
||||
P.printString("Object File Name", Modi.Info.getObjFileName().str());
|
||||
P.printNumber("Num Files", Modi.Info.getNumberOfFiles());
|
||||
P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex());
|
||||
P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex());
|
||||
@ -472,7 +472,7 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
|
||||
to_string(Modi.SourceFiles.size()) + " Contributing Source Files";
|
||||
ListScope LL(P, FileListName);
|
||||
for (auto File : Modi.SourceFiles)
|
||||
P.printString(File);
|
||||
P.printString(File.str());
|
||||
}
|
||||
bool HasModuleDI =
|
||||
(Modi.Info.getModuleStreamIndex() < File.getNumStreams());
|
||||
|
Loading…
Reference in New Issue
Block a user