diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo')
32 files changed, 1990 insertions, 675 deletions
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp index 0e20bcb27ec9..fc6008ba66de 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp @@ -245,20 +245,20 @@ static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = { }; static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = { - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, None), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput), - CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, None), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, Symbols), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, Lines), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, StringTable), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FileChecksums), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FrameData), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, InlineeLines), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CrossScopeImports), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CrossScopeExports), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, ILLines), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FuncMDTokenMap), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, TypeMDTokenMap), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, MergedAssemblyInput), + CV_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CoffSymbolRVA), }; static const EnumEntry<uint16_t> ExportSymFlagNames[] = { diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp new file mode 100644 index 000000000000..42f0afc3e2d7 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp @@ -0,0 +1,107 @@ +//===- ModuleDebugFileChecksumFragment.cpp ----------------------*- 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/CodeView/ModuleDebugFileChecksumFragment.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StringTable.h" +#include "llvm/Support/BinaryStreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; + +struct FileChecksumEntryHeader { + using ulittle32_t = support::ulittle32_t; + + ulittle32_t FileNameOffset; // Byte offset of filename in global string table. + uint8_t ChecksumSize; // Number of bytes of checksum. + uint8_t ChecksumKind; // FileChecksumKind + // Checksum bytes follow. +}; + +Error llvm::VarStreamArrayExtractor<FileChecksumEntry>::extract( + BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) { + BinaryStreamReader Reader(Stream); + + const FileChecksumEntryHeader *Header; + if (auto EC = Reader.readObject(Header)) + return EC; + + Item.FileNameOffset = Header->FileNameOffset; + Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind); + if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize)) + return EC; + + Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4); + return Error::success(); +} + +Error ModuleDebugFileChecksumFragmentRef::initialize( + BinaryStreamReader Reader) { + if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) + return EC; + + return Error::success(); +} + +ModuleDebugFileChecksumFragment::ModuleDebugFileChecksumFragment( + StringTable &Strings) + : ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums), + Strings(Strings) {} + +void ModuleDebugFileChecksumFragment::addChecksum(StringRef FileName, + FileChecksumKind Kind, + ArrayRef<uint8_t> Bytes) { + FileChecksumEntry Entry; + if (!Bytes.empty()) { + uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size()); + ::memcpy(Copy, Bytes.data(), Bytes.size()); + Entry.Checksum = makeArrayRef(Copy, Bytes.size()); + } + + Entry.FileNameOffset = Strings.insert(FileName); + Entry.Kind = Kind; + Checksums.push_back(Entry); + + // This maps the offset of this string in the string table to the offset + // of this checksum entry in the checksum buffer. + OffsetMap[Entry.FileNameOffset] = SerializedSize; + assert(SerializedSize % 4 == 0); + + uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4); + SerializedSize += Len; +} + +uint32_t ModuleDebugFileChecksumFragment::calculateSerializedLength() { + return SerializedSize; +} + +Error ModuleDebugFileChecksumFragment::commit(BinaryStreamWriter &Writer) { + for (const auto &FC : Checksums) { + FileChecksumEntryHeader Header; + Header.ChecksumKind = uint8_t(FC.Kind); + Header.ChecksumSize = FC.Checksum.size(); + Header.FileNameOffset = FC.FileNameOffset; + if (auto EC = Writer.writeObject(Header)) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum))) + return EC; + if (auto EC = Writer.padToAlignment(4)) + return EC; + } + return Error::success(); +} + +uint32_t +ModuleDebugFileChecksumFragment::mapChecksumOffset(StringRef FileName) const { + uint32_t Offset = Strings.getStringId(FileName); + auto Iter = OffsetMap.find(Offset); + assert(Iter != OffsetMap.end()); + return Iter->second; +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp new file mode 100644 index 000000000000..2af1917413da --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp @@ -0,0 +1,16 @@ +//===- ModuleDebugFragment.cpp -----------------------------------*- 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/CodeView/ModuleDebugFragment.h" + +using namespace llvm::codeview; + +ModuleDebugFragmentRef::~ModuleDebugFragmentRef() {} + +ModuleDebugFragment::~ModuleDebugFragment() {} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp new file mode 100644 index 000000000000..b2543de78069 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp @@ -0,0 +1,84 @@ +//===- ModuleDebugFragmentRecord.cpp -----------------------------*- 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/CodeView/ModuleDebugFragmentRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h" + +#include "llvm/Support/BinaryStreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; + +ModuleDebugFragmentRecord::ModuleDebugFragmentRecord() + : Kind(ModuleDebugFragmentKind::None) {} + +ModuleDebugFragmentRecord::ModuleDebugFragmentRecord( + ModuleDebugFragmentKind Kind, BinaryStreamRef Data) + : Kind(Kind), Data(Data) {} + +Error ModuleDebugFragmentRecord::initialize(BinaryStreamRef Stream, + ModuleDebugFragmentRecord &Info) { + const ModuleDebugFragmentHeader *Header; + BinaryStreamReader Reader(Stream); + if (auto EC = Reader.readObject(Header)) + return EC; + + ModuleDebugFragmentKind Kind = + static_cast<ModuleDebugFragmentKind>(uint32_t(Header->Kind)); + switch (Kind) { + case ModuleDebugFragmentKind::FileChecksums: + case ModuleDebugFragmentKind::Lines: + case ModuleDebugFragmentKind::InlineeLines: + break; + default: + llvm_unreachable("Unexpected debug fragment kind!"); + } + if (auto EC = Reader.readStreamRef(Info.Data, Header->Length)) + return EC; + Info.Kind = Kind; + return Error::success(); +} + +uint32_t ModuleDebugFragmentRecord::getRecordLength() const { + uint32_t Result = sizeof(ModuleDebugFragmentHeader) + Data.getLength(); + assert(Result % 4 == 0); + return Result; +} + +ModuleDebugFragmentKind ModuleDebugFragmentRecord::kind() const { return Kind; } + +BinaryStreamRef ModuleDebugFragmentRecord::getRecordData() const { + return Data; +} + +ModuleDebugFragmentRecordBuilder::ModuleDebugFragmentRecordBuilder( + ModuleDebugFragmentKind Kind, ModuleDebugFragment &Frag) + : Kind(Kind), Frag(Frag) {} + +uint32_t ModuleDebugFragmentRecordBuilder::calculateSerializedLength() { + uint32_t Size = sizeof(ModuleDebugFragmentHeader) + + alignTo(Frag.calculateSerializedLength(), 4); + return Size; +} + +Error ModuleDebugFragmentRecordBuilder::commit(BinaryStreamWriter &Writer) { + ModuleDebugFragmentHeader Header; + Header.Kind = uint32_t(Kind); + Header.Length = + calculateSerializedLength() - sizeof(ModuleDebugFragmentHeader); + + if (auto EC = Writer.writeObject(Header)) + return EC; + if (auto EC = Frag.commit(Writer)) + return EC; + if (auto EC = Writer.padToAlignment(4)) + return EC; + + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp new file mode 100644 index 000000000000..dc591f3990e2 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp @@ -0,0 +1,52 @@ +//===- ModuleDebugFragmentVisitor.cpp ---------------------------*- 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/CodeView/ModuleDebugFragmentVisitor.h" + +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error llvm::codeview::visitModuleDebugFragment( + const ModuleDebugFragmentRecord &R, ModuleDebugFragmentVisitor &V) { + BinaryStreamReader Reader(R.getRecordData()); + switch (R.kind()) { + case ModuleDebugFragmentKind::Lines: { + ModuleDebugLineFragmentRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + + return V.visitLines(Fragment); + } + case ModuleDebugFragmentKind::FileChecksums: { + ModuleDebugFileChecksumFragmentRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + + return V.visitFileChecksums(Fragment); + } + case ModuleDebugFragmentKind::InlineeLines: { + ModuleDebugInlineeLineFragmentRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + return V.visitInlineeLines(Fragment); + } + default: { + ModuleDebugUnknownFragmentRef Fragment(R.kind(), R.getRecordData()); + return V.visitUnknown(Fragment); + } + } +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp new file mode 100644 index 000000000000..cb6a8478797f --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp @@ -0,0 +1,123 @@ +//===- ModuleDebugInlineeLineFragment.cpp ------------------------*- 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/CodeView/ModuleDebugInlineeLinesFragment.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h" +#include "llvm/DebugInfo/CodeView/StringTable.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error VarStreamArrayExtractor<InlineeSourceLine>::extract( + BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item, + bool HasExtraFiles) { + BinaryStreamReader Reader(Stream); + + if (auto EC = Reader.readObject(Item.Header)) + return EC; + + if (HasExtraFiles) { + uint32_t ExtraFileCount; + if (auto EC = Reader.readInteger(ExtraFileCount)) + return EC; + if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount)) + return EC; + } + + Len = Reader.getOffset(); + return Error::success(); +} + +ModuleDebugInlineeLineFragmentRef::ModuleDebugInlineeLineFragmentRef() + : ModuleDebugFragmentRef(ModuleDebugFragmentKind::InlineeLines) {} + +Error ModuleDebugInlineeLineFragmentRef::initialize(BinaryStreamReader Reader) { + if (auto EC = Reader.readEnum(Signature)) + return EC; + + if (auto EC = + Reader.readArray(Lines, Reader.bytesRemaining(), hasExtraFiles())) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +bool ModuleDebugInlineeLineFragmentRef::hasExtraFiles() const { + return Signature == InlineeLinesSignature::ExtraFiles; +} + +ModuleDebugInlineeLineFragment::ModuleDebugInlineeLineFragment( + ModuleDebugFileChecksumFragment &Checksums, bool HasExtraFiles) + : ModuleDebugFragment(ModuleDebugFragmentKind::InlineeLines), + Checksums(Checksums), HasExtraFiles(HasExtraFiles) {} + +uint32_t ModuleDebugInlineeLineFragment::calculateSerializedLength() { + // 4 bytes for the signature + uint32_t Size = sizeof(InlineeLinesSignature); + + // one header for each entry. + Size += Entries.size() * sizeof(InlineeSourceLineHeader); + if (HasExtraFiles) { + // If extra files are enabled, one count for each entry. + Size += Entries.size() * sizeof(uint32_t); + + // And one file id for each file. + Size += ExtraFileCount * sizeof(uint32_t); + } + assert(Size % 4 == 0); + return Size; +} + +Error ModuleDebugInlineeLineFragment::commit(BinaryStreamWriter &Writer) { + InlineeLinesSignature Sig = InlineeLinesSignature::Normal; + if (HasExtraFiles) + Sig = InlineeLinesSignature::ExtraFiles; + + if (auto EC = Writer.writeEnum(Sig)) + return EC; + + for (const auto &E : Entries) { + if (auto EC = Writer.writeObject(E.Header)) + return EC; + + if (!HasExtraFiles) + continue; + + if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size())) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles))) + return EC; + } + + return Error::success(); +} + +void ModuleDebugInlineeLineFragment::addExtraFile(StringRef FileName) { + uint32_t Offset = Checksums.mapChecksumOffset(FileName); + + auto &Entry = Entries.back(); + Entry.ExtraFiles.push_back(ulittle32_t(Offset)); + ++ExtraFileCount; +} + +void ModuleDebugInlineeLineFragment::addInlineSite(TypeIndex FuncId, + StringRef FileName, + uint32_t SourceLine) { + uint32_t Offset = Checksums.mapChecksumOffset(FileName); + + Entries.emplace_back(); + auto &Entry = Entries.back(); + Entry.Header.FileID = Offset; + Entry.Header.SourceLineNum = SourceLine; + Entry.Header.Inlinee = FuncId; +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp new file mode 100644 index 000000000000..e0ee934709ba --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp @@ -0,0 +1,161 @@ +//===- ModuleDebugLineFragment.cpp -------------------------------*- 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/CodeView/ModuleDebugLineFragment.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h" +#include "llvm/DebugInfo/CodeView/StringTable.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error LineColumnExtractor::extract(BinaryStreamRef Stream, uint32_t &Len, + LineColumnEntry &Item, + const LineFragmentHeader *Header) { + using namespace codeview; + const LineBlockFragmentHeader *BlockHeader; + BinaryStreamReader Reader(Stream); + if (auto EC = Reader.readObject(BlockHeader)) + return EC; + bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns); + uint32_t LineInfoSize = + BlockHeader->NumLines * + (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); + if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader)) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid line block record size"); + uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader); + if (LineInfoSize > Size) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid line block record size"); + // The value recorded in BlockHeader->BlockSize includes the size of + // LineBlockFragmentHeader. + Len = BlockHeader->BlockSize; + Item.NameIndex = BlockHeader->NameIndex; + if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) + return EC; + if (HasColumn) { + if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) + return EC; + } + return Error::success(); +} + +ModuleDebugLineFragmentRef::ModuleDebugLineFragmentRef() + : ModuleDebugFragmentRef(ModuleDebugFragmentKind::Lines) {} + +Error ModuleDebugLineFragmentRef::initialize(BinaryStreamReader Reader) { + if (auto EC = Reader.readObject(Header)) + return EC; + + if (auto EC = + Reader.readArray(LinesAndColumns, Reader.bytesRemaining(), Header)) + return EC; + + return Error::success(); +} + +bool ModuleDebugLineFragmentRef::hasColumnInfo() const { + return !!(Header->Flags & LF_HaveColumns); +} + +ModuleDebugLineFragment::ModuleDebugLineFragment( + ModuleDebugFileChecksumFragment &Checksums, StringTable &Strings) + : ModuleDebugFragment(ModuleDebugFragmentKind::Lines), + Checksums(Checksums) {} + +void ModuleDebugLineFragment::createBlock(StringRef FileName) { + uint32_t Offset = Checksums.mapChecksumOffset(FileName); + + Blocks.emplace_back(Offset); +} + +void ModuleDebugLineFragment::addLineInfo(uint32_t Offset, + const LineInfo &Line) { + Block &B = Blocks.back(); + LineNumberEntry LNE; + LNE.Flags = Line.getRawData(); + LNE.Offset = Offset; + B.Lines.push_back(LNE); +} + +void ModuleDebugLineFragment::addLineAndColumnInfo(uint32_t Offset, + const LineInfo &Line, + uint32_t ColStart, + uint32_t ColEnd) { + Block &B = Blocks.back(); + assert(B.Lines.size() == B.Columns.size()); + + addLineInfo(Offset, Line); + ColumnNumberEntry CNE; + CNE.StartColumn = ColStart; + CNE.EndColumn = ColEnd; + B.Columns.push_back(CNE); +} + +Error ModuleDebugLineFragment::commit(BinaryStreamWriter &Writer) { + LineFragmentHeader Header; + Header.CodeSize = CodeSize; + Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0; + Header.RelocOffset = RelocOffset; + Header.RelocSegment = RelocSegment; + + if (auto EC = Writer.writeObject(Header)) + return EC; + + for (const auto &B : Blocks) { + LineBlockFragmentHeader BlockHeader; + assert(B.Lines.size() == B.Columns.size() || B.Columns.empty()); + + BlockHeader.NumLines = B.Lines.size(); + BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader); + BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry); + if (hasColumnInfo()) + BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry); + BlockHeader.NameIndex = B.ChecksumBufferOffset; + if (auto EC = Writer.writeObject(BlockHeader)) + return EC; + + if (auto EC = Writer.writeArray(makeArrayRef(B.Lines))) + return EC; + + if (hasColumnInfo()) { + if (auto EC = Writer.writeArray(makeArrayRef(B.Columns))) + return EC; + } + } + return Error::success(); +} + +uint32_t ModuleDebugLineFragment::calculateSerializedLength() { + uint32_t Size = sizeof(LineFragmentHeader); + for (const auto &B : Blocks) { + Size += sizeof(LineBlockFragmentHeader); + Size += B.Lines.size() * sizeof(LineNumberEntry); + if (hasColumnInfo()) + Size += B.Columns.size() * sizeof(ColumnNumberEntry); + } + return Size; +} + +void ModuleDebugLineFragment::setRelocationAddress(uint16_t Segment, + uint16_t Offset) { + RelocOffset = Offset; + RelocSegment = Segment; +} + +void ModuleDebugLineFragment::setCodeSize(uint32_t Size) { CodeSize = Size; } + +void ModuleDebugLineFragment::setFlags(LineFlags Flags) { this->Flags = Flags; } + +bool ModuleDebugLineFragment::hasColumnInfo() const { + return Flags & LF_HaveColumns; +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugUnknownFragment.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugUnknownFragment.cpp new file mode 100644 index 000000000000..9fd2cb8ed3e8 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleDebugUnknownFragment.cpp @@ -0,0 +1,10 @@ +//===- ModuleDebugUnknownFragment.cpp ---------------------------*- 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/CodeView/ModuleDebugUnknownFragment.h"
\ No newline at end of file diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp deleted file mode 100644 index 69a7c59116cf..000000000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//===- ModuleSubstream.cpp --------------------------------------*- 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/CodeView/ModuleSubstream.h" - -#include "llvm/Support/BinaryStreamReader.h" - -using namespace llvm; -using namespace llvm::codeview; - -ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {} - -ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, BinaryStreamRef Data) - : Kind(Kind), Data(Data) {} - -Error ModuleSubstream::initialize(BinaryStreamRef Stream, - ModuleSubstream &Info) { - const ModuleSubsectionHeader *Header; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readObject(Header)) - return EC; - - ModuleSubstreamKind Kind = - static_cast<ModuleSubstreamKind>(uint32_t(Header->Kind)); - if (auto EC = Reader.readStreamRef(Info.Data, Header->Length)) - return EC; - Info.Kind = Kind; - return Error::success(); -} - -uint32_t ModuleSubstream::getRecordLength() const { - return sizeof(ModuleSubsectionHeader) + Data.getLength(); -} - -ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; } - -BinaryStreamRef ModuleSubstream::getRecordData() const { return Data; } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp deleted file mode 100644 index e490a78cadbc..000000000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp +++ /dev/null @@ -1,106 +0,0 @@ -//===- ModuleSubstreamVisitor.cpp -------------------------------*- 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/CodeView/ModuleSubstreamVisitor.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamRef.h" - -using namespace llvm; -using namespace llvm::codeview; - -Error IModuleSubstreamVisitor::visitSymbols(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::Symbols, Data); -} -Error IModuleSubstreamVisitor::visitLines(BinaryStreamRef Data, - const LineSubstreamHeader *Header, - const LineInfoArray &Lines) { - return visitUnknown(ModuleSubstreamKind::Lines, Data); -} -Error IModuleSubstreamVisitor::visitStringTable(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::StringTable, Data); -} -Error IModuleSubstreamVisitor::visitFileChecksums( - BinaryStreamRef Data, const FileChecksumArray &Checksums) { - return visitUnknown(ModuleSubstreamKind::FileChecksums, Data); -} -Error IModuleSubstreamVisitor::visitFrameData(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::FrameData, Data); -} -Error IModuleSubstreamVisitor::visitInlineeLines(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::InlineeLines, Data); -} -Error IModuleSubstreamVisitor::visitCrossScopeImports(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data); -} -Error IModuleSubstreamVisitor::visitCrossScopeExports(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data); -} -Error IModuleSubstreamVisitor::visitILLines(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::ILLines, Data); -} -Error IModuleSubstreamVisitor::visitFuncMDTokenMap(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data); -} -Error IModuleSubstreamVisitor::visitTypeMDTokenMap(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data); -} -Error IModuleSubstreamVisitor::visitMergedAssemblyInput(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data); -} -Error IModuleSubstreamVisitor::visitCoffSymbolRVA(BinaryStreamRef Data) { - return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data); -} - -Error llvm::codeview::visitModuleSubstream(const ModuleSubstream &R, - IModuleSubstreamVisitor &V) { - switch (R.getSubstreamKind()) { - case ModuleSubstreamKind::Symbols: - return V.visitSymbols(R.getRecordData()); - case ModuleSubstreamKind::Lines: { - BinaryStreamReader Reader(R.getRecordData()); - const LineSubstreamHeader *Header; - if (auto EC = Reader.readObject(Header)) - return EC; - VarStreamArrayExtractor<LineColumnEntry> E(Header); - LineInfoArray LineInfos(E); - if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining())) - return EC; - return V.visitLines(R.getRecordData(), Header, LineInfos); - } - case ModuleSubstreamKind::StringTable: - return V.visitStringTable(R.getRecordData()); - case ModuleSubstreamKind::FileChecksums: { - BinaryStreamReader Reader(R.getRecordData()); - FileChecksumArray Checksums; - if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) - return EC; - return V.visitFileChecksums(R.getRecordData(), Checksums); - } - case ModuleSubstreamKind::FrameData: - return V.visitFrameData(R.getRecordData()); - case ModuleSubstreamKind::InlineeLines: - return V.visitInlineeLines(R.getRecordData()); - case ModuleSubstreamKind::CrossScopeImports: - return V.visitCrossScopeImports(R.getRecordData()); - case ModuleSubstreamKind::CrossScopeExports: - return V.visitCrossScopeExports(R.getRecordData()); - case ModuleSubstreamKind::ILLines: - return V.visitILLines(R.getRecordData()); - case ModuleSubstreamKind::FuncMDTokenMap: - return V.visitFuncMDTokenMap(R.getRecordData()); - case ModuleSubstreamKind::TypeMDTokenMap: - return V.visitTypeMDTokenMap(R.getRecordData()); - case ModuleSubstreamKind::MergedAssemblyInput: - return V.visitMergedAssemblyInput(R.getRecordData()); - case ModuleSubstreamKind::CoffSymbolRVA: - return V.visitCoffSymbolRVA(R.getRecordData()); - default: - return V.visitUnknown(R.getSubstreamKind(), R.getRecordData()); - } -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/StringTable.cpp b/contrib/llvm/lib/DebugInfo/CodeView/StringTable.cpp new file mode 100644 index 000000000000..21f11204686b --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/StringTable.cpp @@ -0,0 +1,71 @@ +//===- StringTable.cpp - CodeView String Table Reader/Writer ----*- 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/CodeView/StringTable.h" + +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; + +StringTableRef::StringTableRef() {} + +Error StringTableRef::initialize(BinaryStreamRef Contents) { + Stream = Contents; + return Error::success(); +} + +Expected<StringRef> StringTableRef::getString(uint32_t Offset) const { + BinaryStreamReader Reader(Stream); + Reader.setOffset(Offset); + StringRef Result; + if (auto EC = Reader.readCString(Result)) + return std::move(EC); + return Result; +} + +uint32_t StringTable::insert(StringRef S) { + auto P = Strings.insert({S, StringSize}); + + // If a given string didn't exist in the string table, we want to increment + // the string table size. + if (P.second) + StringSize += S.size() + 1; // +1 for '\0' + return P.first->second; +} + +uint32_t StringTable::calculateSerializedSize() const { return StringSize; } + +Error StringTable::commit(BinaryStreamWriter &Writer) const { + assert(Writer.bytesRemaining() == StringSize); + uint32_t MaxOffset = 1; + + for (auto &Pair : Strings) { + StringRef S = Pair.getKey(); + uint32_t Offset = Pair.getValue(); + Writer.setOffset(Offset); + if (auto EC = Writer.writeCString(S)) + return EC; + MaxOffset = std::max<uint32_t>(MaxOffset, Offset + S.size() + 1); + } + + Writer.setOffset(MaxOffset); + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +uint32_t StringTable::size() const { return Strings.size(); } + +uint32_t StringTable::getStringId(StringRef S) const { + auto P = Strings.find(S); + assert(P != Strings.end()); + return P->second; +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp index 134471e81cac..5395e4349b28 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/StringTable.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -369,14 +370,14 @@ Error CVSymbolDumperImpl::visitKnownRecord( DictScope S(W, "DefRangeSubfield"); if (ObjDelegate) { - StringRef StringTable = ObjDelegate->getStringTable(); - auto ProgramStringTableOffset = DefRangeSubfield.Program; - if (ProgramStringTableOffset >= StringTable.size()) + StringTableRef Strings = ObjDelegate->getStringTable(); + auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program); + if (!ExpectedProgram) { + consumeError(ExpectedProgram.takeError()); return llvm::make_error<CodeViewError>( "String table offset outside of bounds of String Table!"); - StringRef Program = - StringTable.drop_front(ProgramStringTableOffset).split('\0').first; - W.printString("Program", Program); + } + W.printString("Program", *ExpectedProgram); } W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent); printLocalVariableAddrRange(DefRangeSubfield.Range, @@ -390,14 +391,14 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DictScope S(W, "DefRange"); if (ObjDelegate) { - StringRef StringTable = ObjDelegate->getStringTable(); - auto ProgramStringTableOffset = DefRange.Program; - if (ProgramStringTableOffset >= StringTable.size()) + StringTableRef Strings = ObjDelegate->getStringTable(); + auto ExpectedProgram = Strings.getString(DefRange.Program); + if (!ExpectedProgram) { + consumeError(ExpectedProgram.takeError()); return llvm::make_error<CodeViewError>( "String table offset outside of bounds of String Table!"); - StringRef Program = - StringTable.drop_front(ProgramStringTableOffset).split('\0').first; - W.printString("Program", Program); + } + W.printString("Program", *ExpectedProgram); } printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset()); printLocalVariableAddrGap(DefRange.Gaps); diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp index f9ded6ce2a86..efaba4646ffe 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp @@ -110,6 +110,10 @@ const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const { return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex]; } +CVType &TypeDatabase::getTypeRecord(TypeIndex Index) { + return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex]; +} + bool TypeDatabase::containsTypeIndex(TypeIndex Index) const { uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; return I < CVUDTNames.size(); diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 7e8d04672c03..573d37d77fee 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -7,17 +7,17 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" @@ -29,6 +29,7 @@ #include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" #include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" @@ -42,6 +43,8 @@ #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdint> +#include <map> +#include <set> #include <string> #include <utility> #include <vector> @@ -284,6 +287,268 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, getStringSection(), isLittleEndian()); } +DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) { + parseCompileUnits(); + if (auto *CU = CUs.getUnitForOffset(Offset)) + return CU->getDIEForOffset(Offset); + return DWARFDie(); +} + +namespace { + +class Verifier { + raw_ostream &OS; + DWARFContext &DCtx; +public: + Verifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {} + + bool HandleDebugInfo() { + bool Success = true; + // A map that tracks all references (converted absolute references) so we + // can verify each reference points to a valid DIE and not an offset that + // lies between to valid DIEs. + std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets; + + OS << "Verifying .debug_info...\n"; + for (const auto &CU : DCtx.compile_units()) { + unsigned NumDies = CU->getNumDIEs(); + for (unsigned I = 0; I < NumDies; ++I) { + auto Die = CU->getDIEAtIndex(I); + const auto Tag = Die.getTag(); + if (Tag == DW_TAG_null) + continue; + for (auto AttrValue : Die.attributes()) { + const auto Attr = AttrValue.Attr; + const auto Form = AttrValue.Value.getForm(); + switch (Attr) { + case DW_AT_ranges: + // Make sure the offset in the DW_AT_ranges attribute is valid. + if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { + if (*SectionOffset >= DCtx.getRangeSection().Data.size()) { + Success = false; + OS << "error: DW_AT_ranges offset is beyond .debug_ranges " + "bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + } else { + Success = false; + OS << "error: DIE has invalid DW_AT_ranges encoding:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + case DW_AT_stmt_list: + // Make sure the offset in the DW_AT_stmt_list attribute is valid. + if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { + if (*SectionOffset >= DCtx.getLineSection().Data.size()) { + Success = false; + OS << "error: DW_AT_stmt_list offset is beyond .debug_line " + "bounds: " + << format("0x%08" PRIx32, *SectionOffset) << "\n"; + CU->getUnitDIE().dump(OS, 0); + OS << "\n"; + } + } else { + Success = false; + OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + + default: + break; + } + switch (Form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: { + // Verify all CU relative references are valid CU offsets. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + auto DieCU = Die.getDwarfUnit(); + auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); + auto CUOffset = AttrValue.Value.getRawUValue(); + if (CUOffset >= CUSize) { + Success = false; + OS << "error: " << FormEncodingString(Form) << " CU offset " + << format("0x%08" PRIx32, CUOffset) + << " is invalid (must be less than CU size of " + << format("0x%08" PRIx32, CUSize) << "):\n"; + Die.dump(OS, 0); + OS << "\n"; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_ref_addr: { + // Verify all absolute DIE references have valid offsets in the + // .debug_info section. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + if(*RefVal >= DCtx.getInfoSection().Data.size()) { + Success = false; + OS << "error: DW_FORM_ref_addr offset beyond .debug_info " + "bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_strp: { + auto SecOffset = AttrValue.Value.getAsSectionOffset(); + assert(SecOffset); // DW_FORM_strp is a section offset. + if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) { + Success = false; + OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + } + default: + break; + } + } + } + } + + // Take all references and make sure they point to an actual DIE by + // getting the DIE by offset and emitting an error + OS << "Verifying .debug_info references...\n"; + for (auto Pair: ReferenceToDIEOffsets) { + auto Die = DCtx.getDIEForOffset(Pair.first); + if (Die) + continue; + Success = false; + OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first) + << ". Offset is in between DIEs:\n"; + for (auto Offset: Pair.second) { + auto ReferencingDie = DCtx.getDIEForOffset(Offset); + ReferencingDie.dump(OS, 0); + OS << "\n"; + } + OS << "\n"; + } + return Success; + } + + bool HandleDebugLine() { + std::map<uint64_t, DWARFDie> StmtListToDie; + bool Success = true; + OS << "Verifying .debug_line...\n"; + for (const auto &CU : DCtx.compile_units()) { + uint32_t LineTableOffset = 0; + auto CUDie = CU->getUnitDIE(); + auto StmtFormValue = CUDie.find(DW_AT_stmt_list); + if (!StmtFormValue) { + // No line table for this compile unit. + continue; + } + // Get the attribute value as a section offset. No need to produce an + // error here if the encoding isn't correct because we validate this in + // the .debug_info verifier. + if (auto StmtSectionOffset = toSectionOffset(StmtFormValue)) { + LineTableOffset = *StmtSectionOffset; + if (LineTableOffset >= DCtx.getLineSection().Data.size()) { + // Make sure we don't get a valid line table back if the offset + // is wrong. + assert(DCtx.getLineTableForUnit(CU.get()) == nullptr); + // Skip this line table as it isn't valid. No need to create an error + // here because we validate this in the .debug_info verifier. + continue; + } else { + auto Iter = StmtListToDie.find(LineTableOffset); + if (Iter != StmtListToDie.end()) { + Success = false; + OS << "error: two compile unit DIEs, " + << format("0x%08" PRIx32, Iter->second.getOffset()) << " and " + << format("0x%08" PRIx32, CUDie.getOffset()) + << ", have the same DW_AT_stmt_list section offset:\n"; + Iter->second.dump(OS, 0); + CUDie.dump(OS, 0); + OS << '\n'; + // Already verified this line table before, no need to do it again. + continue; + } + StmtListToDie[LineTableOffset] = CUDie; + } + } + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + if (!LineTable) { + Success = false; + OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) + << "] was not able to be parsed for CU:\n"; + CUDie.dump(OS, 0); + OS << '\n'; + continue; + } + uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size(); + uint64_t PrevAddress = 0; + uint32_t RowIndex = 0; + for (const auto &Row : LineTable->Rows) { + if (Row.Address < PrevAddress) { + Success = false; + OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) + << "] row[" << RowIndex + << "] decreases in address from previous row:\n"; + + DWARFDebugLine::Row::dumpTableHeader(OS); + if (RowIndex > 0) + LineTable->Rows[RowIndex - 1].dump(OS); + Row.dump(OS); + OS << '\n'; + } + + if (Row.File > MaxFileIndex) { + Success = false; + OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) + << "][" << RowIndex << "] has invalid file index " << Row.File + << " (valid values are [1," << MaxFileIndex << "]):\n"; + DWARFDebugLine::Row::dumpTableHeader(OS); + Row.dump(OS); + OS << '\n'; + } + if (Row.EndSequence) + PrevAddress = 0; + else + PrevAddress = Row.Address; + ++RowIndex; + } + } + return Success; + } +}; + +} // anonymous namespace + +bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { + bool Success = true; + DWARFVerifier verifier(OS, *this); + if (DumpType == DIDT_All || DumpType == DIDT_Info) { + if (!verifier.handleDebugInfo()) + Success = false; + } + if (DumpType == DIDT_All || DumpType == DIDT_Line) { + if (!verifier.handleDebugLine()) + Success = false; + } + return Success; +} const DWARFUnitIndex &DWARFContext::getCUIndex() { if (CUIndex) return *CUIndex; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index ff6ed9c6741d..f32e8fe76357 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -7,9 +7,10 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" @@ -26,11 +27,19 @@ using namespace llvm; using namespace dwarf; typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; +namespace { +struct ContentDescriptor { + dwarf::LineNumberEntryFormat Type; + dwarf::Form Form; +}; +typedef SmallVector<ContentDescriptor, 4> ContentDescriptors; +} // end anonmyous namespace DWARFDebugLine::Prologue::Prologue() { clear(); } void DWARFDebugLine::Prologue::clear() { TotalLength = Version = PrologueLength = 0; + AddressSize = SegSelectorSize = 0; MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; OpcodeBase = 0; IsDWARF64 = false; @@ -43,6 +52,8 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { OS << "Line table prologue:\n" << format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength) << format(" version: %u\n", Version) + << format(Version >= 5 ? " address_size: %u\n" : "", AddressSize) + << format(Version >= 5 ? " seg_select_size: %u\n" : "", SegSelectorSize) << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength) << format(" min_inst_length: %u\n", MinInstLength) << format(Version >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) @@ -51,95 +62,210 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { << format(" line_range: %u\n", LineRange) << format(" opcode_base: %u\n", OpcodeBase); - for (uint32_t i = 0; i < StandardOpcodeLengths.size(); ++i) + for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I) OS << format("standard_opcode_lengths[%s] = %u\n", - LNStandardString(i + 1).data(), StandardOpcodeLengths[i]); + LNStandardString(I + 1).data(), StandardOpcodeLengths[I]); if (!IncludeDirectories.empty()) - for (uint32_t i = 0; i < IncludeDirectories.size(); ++i) - OS << format("include_directories[%3u] = '", i + 1) - << IncludeDirectories[i] << "'\n"; + for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) + OS << format("include_directories[%3u] = '", I + 1) + << IncludeDirectories[I] << "'\n"; if (!FileNames.empty()) { OS << " Dir Mod Time File Len File Name\n" << " ---- ---------- ---------- -----------" "----------------\n"; - for (uint32_t i = 0; i < FileNames.size(); ++i) { - const FileNameEntry &fileEntry = FileNames[i]; - OS << format("file_names[%3u] %4" PRIu64 " ", i + 1, fileEntry.DirIdx) - << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ", fileEntry.ModTime, - fileEntry.Length) - << fileEntry.Name << '\n'; + for (uint32_t I = 0; I != FileNames.size(); ++I) { + const FileNameEntry &FileEntry = FileNames[I]; + OS << format("file_names[%3u] %4" PRIu64 " ", I + 1, FileEntry.DirIdx) + << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ", FileEntry.ModTime, + FileEntry.Length) + << FileEntry.Name << '\n'; } } } -bool DWARFDebugLine::Prologue::parse(DataExtractor debug_line_data, - uint32_t *offset_ptr) { - const uint64_t prologue_offset = *offset_ptr; +// Parse v2-v4 directory and file tables. +static void +parseV2DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr, + uint64_t EndPrologueOffset, + std::vector<StringRef> &IncludeDirectories, + std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { + while (*OffsetPtr < EndPrologueOffset) { + StringRef S = DebugLineData.getCStrRef(OffsetPtr); + if (S.empty()) + break; + IncludeDirectories.push_back(S); + } + + while (*OffsetPtr < EndPrologueOffset) { + StringRef Name = DebugLineData.getCStrRef(OffsetPtr); + if (Name.empty()) + break; + DWARFDebugLine::FileNameEntry FileEntry; + FileEntry.Name = Name; + FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr); + FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); + FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); + FileNames.push_back(FileEntry); + } +} + +// Parse v5 directory/file entry content descriptions. +// Returns the descriptors, or an empty vector if we did not find a path or +// ran off the end of the prologue. +static ContentDescriptors +parseV5EntryFormat(DataExtractor DebugLineData, uint32_t *OffsetPtr, + uint64_t EndPrologueOffset) { + ContentDescriptors Descriptors; + int FormatCount = DebugLineData.getU8(OffsetPtr); + bool HasPath = false; + for (int I = 0; I != FormatCount; ++I) { + if (*OffsetPtr >= EndPrologueOffset) + return ContentDescriptors(); + ContentDescriptor Descriptor; + Descriptor.Type = + dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr)); + Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr)); + if (Descriptor.Type == dwarf::DW_LNCT_path) + HasPath = true; + Descriptors.push_back(Descriptor); + } + return HasPath ? Descriptors : ContentDescriptors(); +} + +static bool +parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr, + uint64_t EndPrologueOffset, + std::vector<StringRef> &IncludeDirectories, + std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { + // Get the directory entry description. + ContentDescriptors DirDescriptors = + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); + if (DirDescriptors.empty()) + return false; + + // Get the directory entries, according to the format described above. + int DirEntryCount = DebugLineData.getU8(OffsetPtr); + for (int I = 0; I != DirEntryCount; ++I) { + if (*OffsetPtr >= EndPrologueOffset) + return false; + for (auto Descriptor : DirDescriptors) { + DWARFFormValue Value(Descriptor.Form); + switch (Descriptor.Type) { + case DW_LNCT_path: + if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + return false; + IncludeDirectories.push_back(Value.getAsCString().getValue()); + break; + default: + if (!Value.skipValue(DebugLineData, OffsetPtr, nullptr)) + return false; + } + } + } + + // Get the file entry description. + ContentDescriptors FileDescriptors = + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); + if (FileDescriptors.empty()) + return false; + + // Get the file entries, according to the format described above. + int FileEntryCount = DebugLineData.getU8(OffsetPtr); + for (int I = 0; I != FileEntryCount; ++I) { + if (*OffsetPtr >= EndPrologueOffset) + return false; + DWARFDebugLine::FileNameEntry FileEntry; + for (auto Descriptor : FileDescriptors) { + DWARFFormValue Value(Descriptor.Form); + if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + return false; + switch (Descriptor.Type) { + case DW_LNCT_path: + FileEntry.Name = Value.getAsCString().getValue(); + break; + case DW_LNCT_directory_index: + FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_timestamp: + FileEntry.ModTime = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_size: + FileEntry.Length = Value.getAsUnsignedConstant().getValue(); + break; + // FIXME: Add MD5 + default: + break; + } + } + FileNames.push_back(FileEntry); + } + return true; +} + +bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData, + uint32_t *OffsetPtr) { + const uint64_t PrologueOffset = *OffsetPtr; clear(); - TotalLength = debug_line_data.getU32(offset_ptr); + TotalLength = DebugLineData.getU32(OffsetPtr); if (TotalLength == UINT32_MAX) { IsDWARF64 = true; - TotalLength = debug_line_data.getU64(offset_ptr); + TotalLength = DebugLineData.getU64(OffsetPtr); } else if (TotalLength > 0xffffff00) { return false; } - Version = debug_line_data.getU16(offset_ptr); + Version = DebugLineData.getU16(OffsetPtr); if (Version < 2) return false; - PrologueLength = - debug_line_data.getUnsigned(offset_ptr, sizeofPrologueLength()); - const uint64_t end_prologue_offset = PrologueLength + *offset_ptr; - MinInstLength = debug_line_data.getU8(offset_ptr); + if (Version >= 5) { + AddressSize = DebugLineData.getU8(OffsetPtr); + SegSelectorSize = DebugLineData.getU8(OffsetPtr); + } + + PrologueLength = DebugLineData.getUnsigned(OffsetPtr, sizeofPrologueLength()); + const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr; + MinInstLength = DebugLineData.getU8(OffsetPtr); if (Version >= 4) - MaxOpsPerInst = debug_line_data.getU8(offset_ptr); - DefaultIsStmt = debug_line_data.getU8(offset_ptr); - LineBase = debug_line_data.getU8(offset_ptr); - LineRange = debug_line_data.getU8(offset_ptr); - OpcodeBase = debug_line_data.getU8(offset_ptr); + MaxOpsPerInst = DebugLineData.getU8(OffsetPtr); + DefaultIsStmt = DebugLineData.getU8(OffsetPtr); + LineBase = DebugLineData.getU8(OffsetPtr); + LineRange = DebugLineData.getU8(OffsetPtr); + OpcodeBase = DebugLineData.getU8(OffsetPtr); StandardOpcodeLengths.reserve(OpcodeBase - 1); - for (uint32_t i = 1; i < OpcodeBase; ++i) { - uint8_t op_len = debug_line_data.getU8(offset_ptr); - StandardOpcodeLengths.push_back(op_len); - } - - while (*offset_ptr < end_prologue_offset) { - const char *s = debug_line_data.getCStr(offset_ptr); - if (s && s[0]) - IncludeDirectories.push_back(s); - else - break; + for (uint32_t I = 1; I < OpcodeBase; ++I) { + uint8_t OpLen = DebugLineData.getU8(OffsetPtr); + StandardOpcodeLengths.push_back(OpLen); } - while (*offset_ptr < end_prologue_offset) { - const char *name = debug_line_data.getCStr(offset_ptr); - if (name && name[0]) { - FileNameEntry fileEntry; - fileEntry.Name = name; - fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr); - fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr); - fileEntry.Length = debug_line_data.getULEB128(offset_ptr); - FileNames.push_back(fileEntry); - } else { - break; + if (Version >= 5) { + if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, + IncludeDirectories, FileNames)) { + fprintf(stderr, + "warning: parsing line table prologue at 0x%8.8" PRIx64 + " found an invalid directory or file table description at" + " 0x%8.8" PRIx64 "\n", PrologueOffset, (uint64_t)*OffsetPtr); + return false; } - } - - if (*offset_ptr != end_prologue_offset) { - fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 - " should have ended at 0x%8.8" PRIx64 - " but it ended at 0x%8.8" PRIx64 "\n", - prologue_offset, end_prologue_offset, (uint64_t)*offset_ptr); + } else + parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, + IncludeDirectories, FileNames); + + if (*OffsetPtr != EndPrologueOffset) { + fprintf(stderr, + "warning: parsing line table prologue at 0x%8.8" PRIx64 + " should have ended at 0x%8.8" PRIx64 + " but it ended at 0x%8.8" PRIx64 "\n", + PrologueOffset, EndPrologueOffset, (uint64_t)*OffsetPtr); return false; } return true; } -DWARFDebugLine::Row::Row(bool default_is_stmt) { reset(default_is_stmt); } +DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); } void DWARFDebugLine::Row::postAppend() { BasicBlock = false; @@ -147,20 +273,26 @@ void DWARFDebugLine::Row::postAppend() { EpilogueBegin = false; } -void DWARFDebugLine::Row::reset(bool default_is_stmt) { +void DWARFDebugLine::Row::reset(bool DefaultIsStmt) { Address = 0; Line = 1; Column = 0; File = 1; Isa = 0; Discriminator = 0; - IsStmt = default_is_stmt; + IsStmt = DefaultIsStmt; BasicBlock = false; EndSequence = false; PrologueEnd = false; EpilogueBegin = false; } +void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) { + OS << "Address Line Column File ISA Discriminator Flags\n" + << "------------------ ------ ------ ------ --- ------------- " + "-------------\n"; +} + void DWARFDebugLine::Row::dump(raw_ostream &OS) const { OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column) << format(" %6u %3u %13u ", File, Isa, Discriminator) @@ -187,9 +319,7 @@ void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const { OS << '\n'; if (!Rows.empty()) { - OS << "Address Line Column File ISA Discriminator Flags\n" - << "------------------ ------ ------ ------ --- ------------- " - "-------------\n"; + Row::dumpTableHeader(OS); for (const Row &R : Rows) { R.dump(OS); } @@ -212,7 +342,7 @@ void DWARFDebugLine::ParsingState::resetRowAndSequence() { Sequence.reset(); } -void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) { +void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t Offset) { if (Sequence.Empty) { // Record the beginning of instruction sequence. Sequence.Empty = false; @@ -233,56 +363,56 @@ void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) { } const DWARFDebugLine::LineTable * -DWARFDebugLine::getLineTable(uint32_t offset) const { - LineTableConstIter pos = LineTableMap.find(offset); - if (pos != LineTableMap.end()) - return &pos->second; +DWARFDebugLine::getLineTable(uint32_t Offset) const { + LineTableConstIter Pos = LineTableMap.find(Offset); + if (Pos != LineTableMap.end()) + return &Pos->second; return nullptr; } const DWARFDebugLine::LineTable * -DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data, - uint32_t offset) { - std::pair<LineTableIter, bool> pos = - LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable())); - LineTable *LT = &pos.first->second; - if (pos.second) { - if (!LT->parse(debug_line_data, RelocMap, &offset)) +DWARFDebugLine::getOrParseLineTable(DataExtractor DebugLineData, + uint32_t Offset) { + std::pair<LineTableIter, bool> Pos = + LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); + LineTable *LT = &Pos.first->second; + if (Pos.second) { + if (!LT->parse(DebugLineData, RelocMap, &Offset)) return nullptr; } return LT; } -bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, +bool DWARFDebugLine::LineTable::parse(DataExtractor DebugLineData, const RelocAddrMap *RMap, - uint32_t *offset_ptr) { - const uint32_t debug_line_offset = *offset_ptr; + uint32_t *OffsetPtr) { + const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(debug_line_data, offset_ptr)) { + if (!Prologue.parse(DebugLineData, OffsetPtr)) { // Restore our offset and return false to indicate failure! - *offset_ptr = debug_line_offset; + *OffsetPtr = DebugLineOffset; return false; } - const uint32_t end_offset = - debug_line_offset + Prologue.TotalLength + Prologue.sizeofTotalLength(); + const uint32_t EndOffset = + DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength(); ParsingState State(this); - while (*offset_ptr < end_offset) { - uint8_t opcode = debug_line_data.getU8(offset_ptr); + while (*OffsetPtr < EndOffset) { + uint8_t Opcode = DebugLineData.getU8(OffsetPtr); - if (opcode == 0) { + if (Opcode == 0) { // Extended Opcodes always start with a zero opcode followed by // a uleb128 length so you can skip ones you don't know about - uint32_t ext_offset = *offset_ptr; - uint64_t len = debug_line_data.getULEB128(offset_ptr); - uint32_t arg_size = len - (*offset_ptr - ext_offset); + uint32_t ExtOffset = *OffsetPtr; + uint64_t Len = DebugLineData.getULEB128(OffsetPtr); + uint32_t ArgSize = Len - (*OffsetPtr - ExtOffset); - uint8_t sub_opcode = debug_line_data.getU8(offset_ptr); - switch (sub_opcode) { + uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr); + switch (SubOpcode) { case DW_LNE_end_sequence: // Set the end_sequence register of the state machine to true and // append a row to the matrix using the current values of the @@ -292,7 +422,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // address is that of the byte after the last target machine instruction // of the sequence. State.Row.EndSequence = true; - State.appendRowToMatrix(*offset_ptr); + State.appendRowToMatrix(*OffsetPtr); State.resetRowAndSequence(); break; @@ -303,9 +433,8 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // relocatable address. All of the other statement program opcodes // that affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. - State.Row.Address = - getRelocatedValue(debug_line_data, debug_line_data.getAddressSize(), - offset_ptr, RMap); + State.Row.Address = getRelocatedValue( + DebugLineData, DebugLineData.getAddressSize(), OffsetPtr, RMap); break; case DW_LNE_define_file: @@ -330,33 +459,33 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // the DW_LNE_define_file instruction. These numbers are used in the // the file register of the state machine. { - FileNameEntry fileEntry; - fileEntry.Name = debug_line_data.getCStr(offset_ptr); - fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr); - fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr); - fileEntry.Length = debug_line_data.getULEB128(offset_ptr); - Prologue.FileNames.push_back(fileEntry); + FileNameEntry FileEntry; + FileEntry.Name = DebugLineData.getCStr(OffsetPtr); + FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr); + FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); + FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); + Prologue.FileNames.push_back(FileEntry); } break; case DW_LNE_set_discriminator: - State.Row.Discriminator = debug_line_data.getULEB128(offset_ptr); + State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr); break; default: // Length doesn't include the zero opcode byte or the length itself, but // it does include the sub_opcode, so we have to adjust for that below - (*offset_ptr) += arg_size; + (*OffsetPtr) += ArgSize; break; } - } else if (opcode < Prologue.OpcodeBase) { - switch (opcode) { + } else if (Opcode < Prologue.OpcodeBase) { + switch (Opcode) { // Standard Opcodes case DW_LNS_copy: // Takes no arguments. Append a row to the matrix using the // current values of the state-machine registers. Then set // the basic_block register to false. - State.appendRowToMatrix(*offset_ptr); + State.appendRowToMatrix(*OffsetPtr); break; case DW_LNS_advance_pc: @@ -364,25 +493,25 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // min_inst_length field of the prologue, and adds the // result to the address register of the state machine. State.Row.Address += - debug_line_data.getULEB128(offset_ptr) * Prologue.MinInstLength; + DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; break; case DW_LNS_advance_line: // Takes a single signed LEB128 operand and adds that value to // the line register of the state machine. - State.Row.Line += debug_line_data.getSLEB128(offset_ptr); + State.Row.Line += DebugLineData.getSLEB128(OffsetPtr); break; case DW_LNS_set_file: // Takes a single unsigned LEB128 operand and stores it in the file // register of the state machine. - State.Row.File = debug_line_data.getULEB128(offset_ptr); + State.Row.File = DebugLineData.getULEB128(OffsetPtr); break; case DW_LNS_set_column: // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. - State.Row.Column = debug_line_data.getULEB128(offset_ptr); + State.Row.Column = DebugLineData.getULEB128(OffsetPtr); break; case DW_LNS_negate_stmt: @@ -410,10 +539,10 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // than twice that range will it need to use both DW_LNS_advance_pc // and a special opcode, requiring three or more bytes. { - uint8_t adjust_opcode = 255 - Prologue.OpcodeBase; - uint64_t addr_offset = - (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength; - State.Row.Address += addr_offset; + uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase; + uint64_t AddrOffset = + (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; + State.Row.Address += AddrOffset; } break; @@ -427,7 +556,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // judge when the computation of a special opcode overflows and // requires the use of DW_LNS_advance_pc. Such assemblers, however, // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. - State.Row.Address += debug_line_data.getU16(offset_ptr); + State.Row.Address += DebugLineData.getU16(OffsetPtr); break; case DW_LNS_set_prologue_end: @@ -445,7 +574,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, case DW_LNS_set_isa: // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. - State.Row.Isa = debug_line_data.getULEB128(offset_ptr); + State.Row.Isa = DebugLineData.getULEB128(OffsetPtr); break; default: @@ -453,10 +582,10 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // of such opcodes because they are specified in the prologue // as a multiple of LEB128 operands for each opcode. { - assert(opcode - 1U < Prologue.StandardOpcodeLengths.size()); - uint8_t opcode_length = Prologue.StandardOpcodeLengths[opcode - 1]; - for (uint8_t i = 0; i < opcode_length; ++i) - debug_line_data.getULEB128(offset_ptr); + assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size()); + uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; + for (uint8_t I = 0; I < OpcodeLength; ++I) + DebugLineData.getULEB128(OffsetPtr); } break; } @@ -494,14 +623,14 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // // line increment = line_base + (adjusted opcode % line_range) - uint8_t adjust_opcode = opcode - Prologue.OpcodeBase; - uint64_t addr_offset = - (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength; - int32_t line_offset = - Prologue.LineBase + (adjust_opcode % Prologue.LineRange); - State.Row.Line += line_offset; - State.Row.Address += addr_offset; - State.appendRowToMatrix(*offset_ptr); + uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase; + uint64_t AddrOffset = + (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; + int32_t LineOffset = + Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); + State.Row.Line += LineOffset; + State.Row.Address += AddrOffset; + State.appendRowToMatrix(*OffsetPtr); // Reset discriminator to 0. State.Row.Discriminator = 0; } @@ -523,124 +652,122 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // rudimentary sequences for address ranges [0x0, 0xsomething). } - return end_offset; + return EndOffset; } uint32_t -DWARFDebugLine::LineTable::findRowInSeq(const DWARFDebugLine::Sequence &seq, - uint64_t address) const { - if (!seq.containsPC(address)) +DWARFDebugLine::LineTable::findRowInSeq(const DWARFDebugLine::Sequence &Seq, + uint64_t Address) const { + if (!Seq.containsPC(Address)) return UnknownRowIndex; // Search for instruction address in the rows describing the sequence. // Rows are stored in a vector, so we may use arithmetical operations with // iterators. - DWARFDebugLine::Row row; - row.Address = address; - RowIter first_row = Rows.begin() + seq.FirstRowIndex; - RowIter last_row = Rows.begin() + seq.LastRowIndex; - LineTable::RowIter row_pos = std::lower_bound( - first_row, last_row, row, DWARFDebugLine::Row::orderByAddress); - if (row_pos == last_row) { - return seq.LastRowIndex - 1; + DWARFDebugLine::Row Row; + Row.Address = Address; + RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex; + RowIter LastRow = Rows.begin() + Seq.LastRowIndex; + LineTable::RowIter RowPos = std::lower_bound( + FirstRow, LastRow, Row, DWARFDebugLine::Row::orderByAddress); + if (RowPos == LastRow) { + return Seq.LastRowIndex - 1; } - uint32_t index = seq.FirstRowIndex + (row_pos - first_row); - if (row_pos->Address > address) { - if (row_pos == first_row) + uint32_t Index = Seq.FirstRowIndex + (RowPos - FirstRow); + if (RowPos->Address > Address) { + if (RowPos == FirstRow) return UnknownRowIndex; else - index--; + Index--; } - return index; + return Index; } -uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const { +uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t Address) const { if (Sequences.empty()) return UnknownRowIndex; // First, find an instruction sequence containing the given address. - DWARFDebugLine::Sequence sequence; - sequence.LowPC = address; - SequenceIter first_seq = Sequences.begin(); - SequenceIter last_seq = Sequences.end(); - SequenceIter seq_pos = std::lower_bound( - first_seq, last_seq, sequence, DWARFDebugLine::Sequence::orderByLowPC); - DWARFDebugLine::Sequence found_seq; - if (seq_pos == last_seq) { - found_seq = Sequences.back(); - } else if (seq_pos->LowPC == address) { - found_seq = *seq_pos; + DWARFDebugLine::Sequence Sequence; + Sequence.LowPC = Address; + SequenceIter FirstSeq = Sequences.begin(); + SequenceIter LastSeq = Sequences.end(); + SequenceIter SeqPos = std::lower_bound( + FirstSeq, LastSeq, Sequence, DWARFDebugLine::Sequence::orderByLowPC); + DWARFDebugLine::Sequence FoundSeq; + if (SeqPos == LastSeq) { + FoundSeq = Sequences.back(); + } else if (SeqPos->LowPC == Address) { + FoundSeq = *SeqPos; } else { - if (seq_pos == first_seq) + if (SeqPos == FirstSeq) return UnknownRowIndex; - found_seq = *(seq_pos - 1); + FoundSeq = *(SeqPos - 1); } - return findRowInSeq(found_seq, address); + return findRowInSeq(FoundSeq, Address); } bool DWARFDebugLine::LineTable::lookupAddressRange( - uint64_t address, uint64_t size, std::vector<uint32_t> &result) const { + uint64_t Address, uint64_t Size, std::vector<uint32_t> &Result) const { if (Sequences.empty()) return false; - uint64_t end_addr = address + size; + uint64_t EndAddr = Address + Size; // First, find an instruction sequence containing the given address. - DWARFDebugLine::Sequence sequence; - sequence.LowPC = address; - SequenceIter first_seq = Sequences.begin(); - SequenceIter last_seq = Sequences.end(); - SequenceIter seq_pos = std::lower_bound( - first_seq, last_seq, sequence, DWARFDebugLine::Sequence::orderByLowPC); - if (seq_pos == last_seq || seq_pos->LowPC != address) { - if (seq_pos == first_seq) + DWARFDebugLine::Sequence Sequence; + Sequence.LowPC = Address; + SequenceIter FirstSeq = Sequences.begin(); + SequenceIter LastSeq = Sequences.end(); + SequenceIter SeqPos = std::lower_bound( + FirstSeq, LastSeq, Sequence, DWARFDebugLine::Sequence::orderByLowPC); + if (SeqPos == LastSeq || SeqPos->LowPC != Address) { + if (SeqPos == FirstSeq) return false; - seq_pos--; + SeqPos--; } - if (!seq_pos->containsPC(address)) + if (!SeqPos->containsPC(Address)) return false; - SequenceIter start_pos = seq_pos; + SequenceIter StartPos = SeqPos; // Add the rows from the first sequence to the vector, starting with the // index we just calculated - while (seq_pos != last_seq && seq_pos->LowPC < end_addr) { - const DWARFDebugLine::Sequence &cur_seq = *seq_pos; + while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) { + const DWARFDebugLine::Sequence &CurSeq = *SeqPos; // For the first sequence, we need to find which row in the sequence is the // first in our range. - uint32_t first_row_index = cur_seq.FirstRowIndex; - if (seq_pos == start_pos) - first_row_index = findRowInSeq(cur_seq, address); + uint32_t FirstRowIndex = CurSeq.FirstRowIndex; + if (SeqPos == StartPos) + FirstRowIndex = findRowInSeq(CurSeq, Address); // Figure out the last row in the range. - uint32_t last_row_index = findRowInSeq(cur_seq, end_addr - 1); - if (last_row_index == UnknownRowIndex) - last_row_index = cur_seq.LastRowIndex - 1; + uint32_t LastRowIndex = findRowInSeq(CurSeq, EndAddr - 1); + if (LastRowIndex == UnknownRowIndex) + LastRowIndex = CurSeq.LastRowIndex - 1; - assert(first_row_index != UnknownRowIndex); - assert(last_row_index != UnknownRowIndex); + assert(FirstRowIndex != UnknownRowIndex); + assert(LastRowIndex != UnknownRowIndex); - for (uint32_t i = first_row_index; i <= last_row_index; ++i) { - result.push_back(i); + for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) { + Result.push_back(I); } - ++seq_pos; + ++SeqPos; } return true; } -bool -DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const { +bool DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const { return FileIndex != 0 && FileIndex <= Prologue.FileNames.size(); } -bool -DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, - const char *CompDir, - FileLineInfoKind Kind, - std::string &Result) const { +bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, + const char *CompDir, + FileLineInfoKind Kind, + std::string &Result) const { if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) return false; const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1]; - const char *FileName = Entry.Name; + StringRef FileName = Entry.Name; if (Kind != FileLineInfoKind::AbsoluteFilePath || sys::path::is_absolute(FileName)) { Result = FileName; @@ -649,7 +776,7 @@ DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, SmallString<16> FilePath; uint64_t IncludeDirIndex = Entry.DirIdx; - const char *IncludeDir = ""; + StringRef IncludeDir; // Be defensive about the contents of Entry. if (IncludeDirIndex > 0 && IncludeDirIndex <= Prologue.IncludeDirectories.size()) diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp index 662e53d9d7e6..daded255f8c7 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -45,7 +45,7 @@ DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian, } void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const { - OS << "\n." << Name << " contents: a\n"; + OS << "\n." << Name << " contents:\n"; for (const Set &S : Sets) { OS << "length = " << format("0x%08x", S.Length); OS << " version = " << format("0x%04x", S.Version); diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 28592e4dfb65..7f827de89240 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -309,8 +309,10 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { } // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset. // Don't check for DWARF version here, as some producers may still do this - // by mistake. - return (Form == DW_FORM_data4 || Form == DW_FORM_data8) && + // by mistake. Also accept DW_FORM_strp since this is .debug_str section + // offset. + return (Form == DW_FORM_data4 || Form == DW_FORM_data8 || + Form == DW_FORM_strp) && FC == FC_SectionOffset; } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp index 76354a9b1ddb..0625d01097c9 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp @@ -39,8 +39,9 @@ void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const { << '\n'; for (const AddressEntry &Addr : AddressArea) OS << format( - " Low address = 0x%llx, High address = 0x%llx, CU index = %d\n", - Addr.LowAddress, Addr.HighAddress, Addr.CuIndex); + " Low/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n", + Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress, + Addr.CuIndex); } void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const { diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp new file mode 100644 index 000000000000..9494e876da15 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -0,0 +1,277 @@ +//===- DWARFVerifier.cpp --------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/Support/raw_ostream.h" +#include <map> +#include <set> +#include <vector> + +using namespace llvm; +using namespace dwarf; +using namespace object; + +void DWARFVerifier::verifyDebugInfoAttribute(DWARFDie &Die, + DWARFAttribute &AttrValue) { + const auto Attr = AttrValue.Attr; + switch (Attr) { + case DW_AT_ranges: + // Make sure the offset in the DW_AT_ranges attribute is valid. + if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { + if (*SectionOffset >= DCtx.getRangeSection().Data.size()) { + ++NumDebugInfoErrors; + OS << "error: DW_AT_ranges offset is beyond .debug_ranges " + "bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + } else { + ++NumDebugInfoErrors; + OS << "error: DIE has invalid DW_AT_ranges encoding:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + case DW_AT_stmt_list: + // Make sure the offset in the DW_AT_stmt_list attribute is valid. + if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { + if (*SectionOffset >= DCtx.getLineSection().Data.size()) { + ++NumDebugInfoErrors; + OS << "error: DW_AT_stmt_list offset is beyond .debug_line " + "bounds: " + << format("0x%08" PRIx32, *SectionOffset) << "\n"; + Die.dump(OS, 0); + OS << "\n"; + } + } else { + ++NumDebugInfoErrors; + OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + + default: + break; + } +} + +void DWARFVerifier::verifyDebugInfoForm(DWARFDie &Die, + DWARFAttribute &AttrValue) { + const auto Form = AttrValue.Value.getForm(); + switch (Form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: { + // Verify all CU relative references are valid CU offsets. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + auto DieCU = Die.getDwarfUnit(); + auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); + auto CUOffset = AttrValue.Value.getRawUValue(); + if (CUOffset >= CUSize) { + ++NumDebugInfoErrors; + OS << "error: " << FormEncodingString(Form) << " CU offset " + << format("0x%08" PRIx32, CUOffset) + << " is invalid (must be less than CU size of " + << format("0x%08" PRIx32, CUSize) << "):\n"; + Die.dump(OS, 0); + OS << "\n"; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_ref_addr: { + // Verify all absolute DIE references have valid offsets in the + // .debug_info section. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + if (*RefVal >= DCtx.getInfoSection().Data.size()) { + ++NumDebugInfoErrors; + OS << "error: DW_FORM_ref_addr offset beyond .debug_info " + "bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_strp: { + auto SecOffset = AttrValue.Value.getAsSectionOffset(); + assert(SecOffset); // DW_FORM_strp is a section offset. + if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) { + ++NumDebugInfoErrors; + OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + } + default: + break; + } +} + +void DWARFVerifier::veifyDebugInfoReferences() { + // Take all references and make sure they point to an actual DIE by + // getting the DIE by offset and emitting an error + OS << "Verifying .debug_info references...\n"; + for (auto Pair : ReferenceToDIEOffsets) { + auto Die = DCtx.getDIEForOffset(Pair.first); + if (Die) + continue; + ++NumDebugInfoErrors; + OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first) + << ". Offset is in between DIEs:\n"; + for (auto Offset : Pair.second) { + auto ReferencingDie = DCtx.getDIEForOffset(Offset); + ReferencingDie.dump(OS, 0); + OS << "\n"; + } + OS << "\n"; + } +} + +bool DWARFVerifier::handleDebugInfo() { + NumDebugInfoErrors = 0; + OS << "Verifying .debug_info...\n"; + for (const auto &CU : DCtx.compile_units()) { + unsigned NumDies = CU->getNumDIEs(); + for (unsigned I = 0; I < NumDies; ++I) { + auto Die = CU->getDIEAtIndex(I); + const auto Tag = Die.getTag(); + if (Tag == DW_TAG_null) + continue; + for (auto AttrValue : Die.attributes()) { + verifyDebugInfoAttribute(Die, AttrValue); + verifyDebugInfoForm(Die, AttrValue); + } + } + } + veifyDebugInfoReferences(); + return NumDebugInfoErrors == 0; +} + +void DWARFVerifier::verifyDebugLineStmtOffsets() { + std::map<uint64_t, DWARFDie> StmtListToDie; + for (const auto &CU : DCtx.compile_units()) { + auto Die = CU->getUnitDIE(); + // Get the attribute value as a section offset. No need to produce an + // error here if the encoding isn't correct because we validate this in + // the .debug_info verifier. + auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); + if (!StmtSectionOffset) + continue; + const uint32_t LineTableOffset = *StmtSectionOffset; + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + if (LineTableOffset < DCtx.getLineSection().Data.size()) { + if (!LineTable) { + ++NumDebugLineErrors; + OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) + << "] was not able to be parsed for CU:\n"; + Die.dump(OS, 0); + OS << '\n'; + continue; + } + } else { + // Make sure we don't get a valid line table back if the offset is wrong. + assert(LineTable == nullptr); + // Skip this line table as it isn't valid. No need to create an error + // here because we validate this in the .debug_info verifier. + continue; + } + auto Iter = StmtListToDie.find(LineTableOffset); + if (Iter != StmtListToDie.end()) { + ++NumDebugLineErrors; + OS << "error: two compile unit DIEs, " + << format("0x%08" PRIx32, Iter->second.getOffset()) << " and " + << format("0x%08" PRIx32, Die.getOffset()) + << ", have the same DW_AT_stmt_list section offset:\n"; + Iter->second.dump(OS, 0); + Die.dump(OS, 0); + OS << '\n'; + // Already verified this line table before, no need to do it again. + continue; + } + StmtListToDie[LineTableOffset] = Die; + } +} + +void DWARFVerifier::verifyDebugLineRows() { + for (const auto &CU : DCtx.compile_units()) { + auto Die = CU->getUnitDIE(); + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + // If there is no line table we will have created an error in the + // .debug_info verifier or in verifyDebugLineStmtOffsets(). + if (!LineTable) + continue; + uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size(); + uint64_t PrevAddress = 0; + uint32_t RowIndex = 0; + for (const auto &Row : LineTable->Rows) { + if (Row.Address < PrevAddress) { + ++NumDebugLineErrors; + OS << "error: .debug_line[" + << format("0x%08" PRIx32, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "] row[" << RowIndex + << "] decreases in address from previous row:\n"; + + DWARFDebugLine::Row::dumpTableHeader(OS); + if (RowIndex > 0) + LineTable->Rows[RowIndex - 1].dump(OS); + Row.dump(OS); + OS << '\n'; + } + + if (Row.File > MaxFileIndex) { + ++NumDebugLineErrors; + OS << "error: .debug_line[" + << format("0x%08" PRIx32, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "][" << RowIndex << "] has invalid file index " << Row.File + << " (valid values are [1," << MaxFileIndex << "]):\n"; + DWARFDebugLine::Row::dumpTableHeader(OS); + Row.dump(OS); + OS << '\n'; + } + if (Row.EndSequence) + PrevAddress = 0; + else + PrevAddress = Row.Address; + ++RowIndex; + } + } +} + +bool DWARFVerifier::handleDebugLine() { + NumDebugLineErrors = 0; + OS << "Verifying .debug_line...\n"; + verifyDebugLineStmtOffsets(); + verifyDebugLineRows(); + return NumDebugLineErrors == 0; +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/ModInfo.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp index 1405286fd088..dabcc3447ee5 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/ModInfo.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp @@ -1,4 +1,4 @@ -//===- ModInfo.cpp - PDB module information -------------------------------===// +//===- DbiModuleDescriptor.cpp - PDB module information -------------------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" @@ -19,13 +19,15 @@ using namespace llvm; using namespace llvm::pdb; using namespace llvm::support; -ModInfo::ModInfo() = default; +DbiModuleDescriptor::DbiModuleDescriptor() = default; -ModInfo::ModInfo(const ModInfo &Info) = default; +DbiModuleDescriptor::DbiModuleDescriptor(const DbiModuleDescriptor &Info) = + default; -ModInfo::~ModInfo() = default; +DbiModuleDescriptor::~DbiModuleDescriptor() = default; -Error ModInfo::initialize(BinaryStreamRef Stream, ModInfo &Info) { +Error DbiModuleDescriptor::initialize(BinaryStreamRef Stream, + DbiModuleDescriptor &Info) { BinaryStreamReader Reader(Stream); if (auto EC = Reader.readObject(Info.Layout)) return EC; @@ -38,40 +40,48 @@ Error ModInfo::initialize(BinaryStreamRef Stream, ModInfo &Info) { return Error::success(); } -bool ModInfo::hasECInfo() const { +bool DbiModuleDescriptor::hasECInfo() const { return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0; } -uint16_t ModInfo::getTypeServerIndex() const { +uint16_t DbiModuleDescriptor::getTypeServerIndex() const { return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >> ModInfoFlags::TypeServerIndexShift; } -uint16_t ModInfo::getModuleStreamIndex() const { return Layout->ModDiStream; } +uint16_t DbiModuleDescriptor::getModuleStreamIndex() const { + return Layout->ModDiStream; +} -uint32_t ModInfo::getSymbolDebugInfoByteSize() const { +uint32_t DbiModuleDescriptor::getSymbolDebugInfoByteSize() const { return Layout->SymBytes; } -uint32_t ModInfo::getLineInfoByteSize() const { return Layout->LineBytes; } +uint32_t DbiModuleDescriptor::getC11LineInfoByteSize() const { + return Layout->C11Bytes; +} -uint32_t ModInfo::getC13LineInfoByteSize() const { return Layout->C13Bytes; } +uint32_t DbiModuleDescriptor::getC13LineInfoByteSize() const { + return Layout->C13Bytes; +} -uint32_t ModInfo::getNumberOfFiles() const { return Layout->NumFiles; } +uint32_t DbiModuleDescriptor::getNumberOfFiles() const { + return Layout->NumFiles; +} -uint32_t ModInfo::getSourceFileNameIndex() const { +uint32_t DbiModuleDescriptor::getSourceFileNameIndex() const { return Layout->SrcFileNameNI; } -uint32_t ModInfo::getPdbFilePathNameIndex() const { +uint32_t DbiModuleDescriptor::getPdbFilePathNameIndex() const { return Layout->PdbFilePathNI; } -StringRef ModInfo::getModuleName() const { return ModuleName; } +StringRef DbiModuleDescriptor::getModuleName() const { return ModuleName; } -StringRef ModInfo::getObjFileName() const { return ObjFileName; } +StringRef DbiModuleDescriptor::getObjFileName() const { return ObjFileName; } -uint32_t ModInfo::getRecordLength() const { +uint32_t DbiModuleDescriptor::getRecordLength() const { uint32_t M = ModuleName.str().size() + 1; uint32_t O = ObjFileName.str().size() + 1; uint32_t Size = sizeof(ModuleInfoHeader) + M + O; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 73c45a953520..867864e47dce 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -1,4 +1,4 @@ -//===- ModInfoBuilder.cpp - PDB Module Info Stream Creation -----*- C++ -*-===// +//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/BinaryItemStream.h" @@ -35,47 +36,72 @@ template <> struct BinaryItemTraits<CVSymbol> { }; } -static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) { +static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize, + uint32_t C13Size) { uint32_t Size = sizeof(uint32_t); // Signature Size += SymbolByteSize; // Symbol Data - Size += 0; // TODO: Layout.LineBytes - Size += 0; // TODO: Layout.C13Bytes + Size += 0; // TODO: Layout.C11Bytes + Size += C13Size; // C13 Debug Info Size Size += sizeof(uint32_t); // GlobalRefs substream size (always 0) Size += 0; // GlobalRefs substream bytes return Size; } -ModInfoBuilder::ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex, - msf::MSFBuilder &Msf) +DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName, + uint32_t ModIndex, + msf::MSFBuilder &Msf) : MSF(Msf), ModuleName(ModuleName) { Layout.Mod = ModIndex; } -uint16_t ModInfoBuilder::getStreamIndex() const { return Layout.ModDiStream; } +DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {} -void ModInfoBuilder::setObjFileName(StringRef Name) { ObjFileName = Name; } +uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const { + return Layout.ModDiStream; +} + +void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) { + ObjFileName = Name; +} -void ModInfoBuilder::addSymbol(CVSymbol Symbol) { +void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { Symbols.push_back(Symbol); SymbolByteSize += Symbol.data().size(); } -void ModInfoBuilder::addSourceFile(StringRef Path) { +void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) { SourceFiles.push_back(Path); } -uint32_t ModInfoBuilder::calculateSerializedLength() const { +uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const { + uint32_t Result = 0; + for (const auto &Builder : C13Builders) { + assert(Builder && "Empty C13 Fragment Builder!"); + Result += Builder->calculateSerializedLength(); + } + return Result; +} + +uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { uint32_t L = sizeof(Layout); uint32_t M = ModuleName.size() + 1; uint32_t O = ObjFileName.size() + 1; return alignTo(L + M + O, sizeof(uint32_t)); } -void ModInfoBuilder::finalize() { - Layout.C13Bytes = 0; +template <typename T> struct Foo { + explicit Foo(T &&Answer) : Answer(Answer) {} + + T Answer; +}; + +template <typename T> Foo<T> makeFoo(T &&t) { return Foo<T>(std::move(t)); } + +void DbiModuleDescriptorBuilder::finalize() { Layout.FileNameOffs = 0; // TODO: Fix this Layout.Flags = 0; // TODO: Fix this - Layout.LineBytes = 0; + Layout.C11Bytes = 0; + Layout.C13Bytes = calculateC13DebugInfoSize(); (void)Layout.Mod; // Set in constructor (void)Layout.ModDiStream; // Set in finalizeMsfLayout Layout.NumFiles = SourceFiles.size(); @@ -87,18 +113,20 @@ void ModInfoBuilder::finalize() { Layout.SymBytes = SymbolByteSize + sizeof(uint32_t); } -Error ModInfoBuilder::finalizeMsfLayout() { +Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { this->Layout.ModDiStream = kInvalidStreamIndex; - auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize)); + uint32_t C13Size = calculateC13DebugInfoSize(); + auto ExpectedSN = + MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); if (!ExpectedSN) return ExpectedSN.takeError(); Layout.ModDiStream = *ExpectedSN; return Error::success(); } -Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter, - const msf::MSFLayout &MsfLayout, - WritableBinaryStreamRef MsfBuffer) { +Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, + const msf::MSFLayout &MsfLayout, + WritableBinaryStreamRef MsfBuffer) { // We write the Modi record to the `ModiWriter`, but we additionally write its // symbol stream to a brand new stream. if (auto EC = ModiWriter.writeObject(Layout)) @@ -125,7 +153,13 @@ Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter, if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) return EC; // TODO: Write C11 Line data - // TODO: Write C13 Line data + + for (const auto &Builder : C13Builders) { + assert(Builder && "Empty C13 Fragment Builder!"); + if (auto EC = Builder->commit(SymbolWriter)) + return EC; + } + // TODO: Figure out what GlobalRefs substream actually is and populate it. if (auto EC = SymbolWriter.writeInteger<uint32_t>(0)) return EC; @@ -134,3 +168,43 @@ Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter, } return Error::success(); } + +void DbiModuleDescriptorBuilder::addC13Fragment( + std::unique_ptr<ModuleDebugLineFragment> Lines) { + ModuleDebugLineFragment &Frag = *Lines; + + // File Checksums have to come first, so push an empty entry on if this + // is the first. + if (C13Builders.empty()) + C13Builders.push_back(nullptr); + + this->LineInfo.push_back(std::move(Lines)); + C13Builders.push_back( + llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag)); +} + +void DbiModuleDescriptorBuilder::addC13Fragment( + std::unique_ptr<codeview::ModuleDebugInlineeLineFragment> Inlinees) { + ModuleDebugInlineeLineFragment &Frag = *Inlinees; + + // File Checksums have to come first, so push an empty entry on if this + // is the first. + if (C13Builders.empty()) + C13Builders.push_back(nullptr); + + this->Inlinees.push_back(std::move(Inlinees)); + C13Builders.push_back( + llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag)); +} + +void DbiModuleDescriptorBuilder::setC13FileChecksums( + std::unique_ptr<ModuleDebugFileChecksumFragment> Checksums) { + assert(!ChecksumInfo && "Can't have more than one checksum info!"); + + if (C13Builders.empty()) + C13Builders.push_back(nullptr); + + ChecksumInfo = std::move(Checksums); + C13Builders[0] = llvm::make_unique<ModuleDebugFragmentRecordBuilder>( + ChecksumInfo->kind(), *ChecksumInfo); +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp index b9f53578d326..db703809f7c9 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -10,9 +10,9 @@ #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/ModInfo.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" @@ -146,7 +146,7 @@ Error DbiStream::reload() { if (ECSubstream.getLength() > 0) { BinaryStreamReader ECReader(ECSubstream); - if (auto EC = ECNames.load(ECReader)) + if (auto EC = ECNames.reload(ECReader)) return EC; } @@ -252,11 +252,12 @@ Error DbiStream::initializeModInfoArray() { if (ModInfoSubstream.getLength() == 0) return Error::success(); - // Since each ModInfo in the stream is a variable length, we have to iterate + // Since each DbiModuleDescriptor in the stream is a variable length, we have + // to iterate // them to know how many there actually are. BinaryStreamReader Reader(ModInfoSubstream); - VarStreamArray<ModInfo> ModInfoArray; + VarStreamArray<DbiModuleDescriptor> ModInfoArray; if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength())) return EC; for (auto &Info : ModInfoArray) { @@ -371,10 +372,12 @@ Error DbiStream::initializeFileInfo() { NumSourceFiles += Count; // This is the array that in the reference implementation corresponds to - // `ModInfo::FileLayout::FileNameOffs`, which is commented there as being a + // `DbiModuleDescriptor::FileLayout::FileNameOffs`, which is commented there + // as being a // pointer. Due to the mentioned problems of pointers causing difficulty // when reading from the file on 64-bit systems, we continue to ignore that - // field in `ModInfo`, and instead build a vector of StringRefs and stores + // field in `DbiModuleDescriptor`, and instead build a vector of StringRefs + // and stores // 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. diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index a203aea60fe7..c19a2f0d3110 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -12,8 +12,8 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryStreamWriter.h" @@ -74,10 +74,11 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const { calculateSectionMapStreamSize() + calculateDbgStreamsSize(); } -Expected<ModInfoBuilder &> +Expected<DbiModuleDescriptorBuilder &> DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { uint32_t Index = ModiList.size(); - auto MIB = llvm::make_unique<ModInfoBuilder>(ModuleName, Index, Msf); + auto MIB = + llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf); auto M = MIB.get(); auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB))); @@ -100,6 +101,14 @@ Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { return Error::success(); } +Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) { + auto NameIter = SourceFileNames.find(File); + if (NameIter == SourceFileNames.end()) + return make_error<RawError>(raw_error_code::no_entry, + "The specified source file was not found"); + return NameIter->getValue(); +} + uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { uint32_t Size = 0; for (const auto &M : ModiList) diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/ModStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp index e87e2c407593..d7a203746a0d 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/ModStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -1,4 +1,4 @@ -//===- ModStream.cpp - PDB Module Info Stream Access ----------------------===// +//===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===// // // The LLVM Compiler Infrastructure // @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Native/ModStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" @@ -21,20 +21,22 @@ #include <cstdint> using namespace llvm; +using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; -ModStream::ModStream(const ModInfo &Module, - std::unique_ptr<MappedBlockStream> Stream) +ModuleDebugStreamRef::ModuleDebugStreamRef( + const DbiModuleDescriptor &Module, + std::unique_ptr<MappedBlockStream> Stream) : Mod(Module), Stream(std::move(Stream)) {} -ModStream::~ModStream() = default; +ModuleDebugStreamRef::~ModuleDebugStreamRef() = default; -Error ModStream::reload() { +Error ModuleDebugStreamRef::reload() { BinaryStreamReader Reader(*Stream); uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); - uint32_t C11Size = Mod.getLineInfoByteSize(); + uint32_t C11Size = Mod.getC11LineInfoByteSize(); uint32_t C13Size = Mod.getC13LineInfoByteSize(); if (C11Size > 0 && C13Size > 0) @@ -48,13 +50,14 @@ Error ModStream::reload() { if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4)) return EC; - if (auto EC = Reader.readStreamRef(LinesSubstream, C11Size)) + if (auto EC = Reader.readStreamRef(C11LinesSubstream, C11Size)) return EC; if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; BinaryStreamReader LineReader(C13LinesSubstream); - if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining())) + if (auto EC = + LineReader.readArray(LinesAndChecksums, LineReader.bytesRemaining())) return EC; uint32_t GlobalRefsSize; @@ -70,20 +73,17 @@ Error ModStream::reload() { } iterator_range<codeview::CVSymbolArray::Iterator> -ModStream::symbols(bool *HadError) const { - // It's OK if the stream is empty. - if (SymbolsSubstream.getUnderlyingStream().getLength() == 0) - return make_range(SymbolsSubstream.end(), SymbolsSubstream.end()); +ModuleDebugStreamRef::symbols(bool *HadError) const { return make_range(SymbolsSubstream.begin(HadError), SymbolsSubstream.end()); } -iterator_range<codeview::ModuleSubstreamArray::Iterator> -ModStream::lines(bool *HadError) const { - return make_range(LineInfo.begin(HadError), LineInfo.end()); +llvm::iterator_range<ModuleDebugStreamRef::LinesAndChecksumsIterator> +ModuleDebugStreamRef::linesAndChecksums() const { + return make_range(LinesAndChecksums.begin(), LinesAndChecksums.end()); } -bool ModStream::hasLineInfo() const { - return C13LinesSubstream.getLength() > 0 || LinesSubstream.getLength() > 0; +bool ModuleDebugStreamRef::hasLineInfo() const { + return C13LinesSubstream.getLength() > 0; } -Error ModStream::commit() { return Error::success(); } +Error ModuleDebugStreamRef::commit() { return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStreamBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStreamBuilder.cpp new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStreamBuilder.cpp diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp index 943e7fa13ab7..859295d2c7d3 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -15,9 +15,9 @@ #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Support/BinaryStream.h" @@ -337,8 +337,8 @@ Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { return *Symbols; } -Expected<StringTable &> PDBFile::getStringTable() { - if (!Strings || !StringTableStream) { +Expected<PDBStringTable &> PDBFile::getStringTable() { + if (!Strings) { auto IS = getPDBInfoStream(); if (!IS) return IS.takeError(); @@ -350,12 +350,13 @@ Expected<StringTable &> PDBFile::getStringTable() { if (!NS) return NS.takeError(); + auto N = llvm::make_unique<PDBStringTable>(); BinaryStreamReader Reader(**NS); - auto N = llvm::make_unique<StringTable>(); - if (auto EC = N->load(Reader)) + if (auto EC = N->reload(Reader)) return std::move(EC); - Strings = std::move(N); + assert(Reader.bytesRemaining() == 0); StringTableStream = std::move(*NS); + Strings = std::move(N); } return *Strings; } @@ -389,7 +390,7 @@ bool PDBFile::hasPDBSymbolStream() { bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } -bool PDBFile::hasStringTable() { +bool PDBFile::hasPDBStringTable() { auto IS = getPDBInfoStream(); if (!IS) return false; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index b3c84903bc7e..4dd965c69071 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -17,8 +17,8 @@ #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Support/BinaryStream.h" @@ -67,7 +67,9 @@ TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { return *Ipi; } -StringTableBuilder &PDBFileBuilder::getStringTableBuilder() { return Strings; } +PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { + return Strings; +} Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { auto ExpectedStream = Msf->addStream(Size); @@ -78,9 +80,9 @@ Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { } Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { - uint32_t StringTableSize = Strings.finalize(); + uint32_t StringsLen = Strings.calculateSerializedSize(); - if (auto EC = addNamedStream("/names", StringTableSize)) + if (auto EC = addNamedStream("/names", StringsLen)) return std::move(EC); if (auto EC = addNamedStream("/LinkInfo", 0)) return std::move(EC); @@ -107,6 +109,13 @@ Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { return Msf->build(); } +Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { + uint32_t SN = 0; + if (!NamedStreams.get(Name, SN)) + return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); + return SN; +} + Error PDBFileBuilder::commit(StringRef Filename) { auto ExpectedLayout = finalizeMsfLayout(); if (!ExpectedLayout) @@ -144,12 +153,12 @@ Error PDBFileBuilder::commit(StringRef Filename) { return EC; } - uint32_t StringTableStreamNo = 0; - if (!NamedStreams.get("/names", StringTableStreamNo)) - return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); + auto ExpectedSN = getNamedStreamIndex("/names"); + if (!ExpectedSN) + return ExpectedSN.takeError(); auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, - StringTableStreamNo); + *ExpectedSN); BinaryStreamWriter NSWriter(*NS); if (auto EC = Strings.commit(NSWriter)) return EC; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp new file mode 100644 index 000000000000..e84573fe07b8 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -0,0 +1,134 @@ +//===- PDBStringTable.cpp - PDB String 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/Native/PDBStringTable.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::pdb; + +uint32_t PDBStringTable::getByteSize() const { return ByteSize; } +uint32_t PDBStringTable::getNameCount() const { return NameCount; } +uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; } +uint32_t PDBStringTable::getSignature() const { return Header->Signature; } + +Error PDBStringTable::readHeader(BinaryStreamReader &Reader) { + if (auto EC = Reader.readObject(Header)) + return EC; + + if (Header->Signature != PDBStringTableSignature) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid hash table signature"); + if (Header->HashVersion != 1 && Header->HashVersion != 2) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported hash version"); + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::readStrings(BinaryStreamReader &Reader) { + BinaryStreamRef Stream; + if (auto EC = Reader.readStreamRef(Stream)) + return EC; + + if (auto EC = Strings.initialize(Stream)) { + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Invalid hash table byte length")); + } + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { + const support::ulittle32_t *HashCount; + if (auto EC = Reader.readObject(HashCount)) + return EC; + + if (auto EC = Reader.readArray(IDs, *HashCount)) { + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read bucket array")); + } + + return Error::success(); +} + +Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { + if (auto EC = Reader.readInteger(NameCount)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::reload(BinaryStreamReader &Reader) { + + BinaryStreamReader SectionReader; + + std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); + if (auto EC = readHeader(SectionReader)) + return EC; + + std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); + if (auto EC = readStrings(SectionReader)) + return EC; + + // We don't know how long the hash table is until we parse it, so let the + // function responsible for doing that figure it out. + if (auto EC = readHashTable(Reader)) + return EC; + + std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); + if (auto EC = readEpilogue(SectionReader)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const { + return Strings.getString(ID); +} + +Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { + uint32_t Hash = + (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); + size_t Count = IDs.size(); + uint32_t Start = Hash % Count; + for (size_t I = 0; I < Count; ++I) { + // The hash is just a starting point for the search, but if it + // doesn't work we should find the string no matter what, because + // we iterate the entire array. + uint32_t Index = (Start + I) % Count; + + uint32_t ID = IDs[Index]; + auto ExpectedStr = getStringForID(ID); + if (!ExpectedStr) + return ExpectedStr.takeError(); + + if (*ExpectedStr == Str) + return ID; + } + return make_error<RawError>(raw_error_code::no_entry); +} + +FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { + return IDs; +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp new file mode 100644 index 000000000000..a472181a4895 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -0,0 +1,133 @@ +//===- PDBStringTableBuilder.cpp - PDB String 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/Native/PDBStringTableBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::support::endian; +using namespace llvm::pdb; + +uint32_t PDBStringTableBuilder::insert(StringRef S) { + return Strings.insert(S); +} + +static uint32_t computeBucketCount(uint32_t NumStrings) { + // The /names stream is basically an on-disk open-addressing hash table. + // Hash collisions are resolved by linear probing. We cannot make + // utilization 100% because it will make the linear probing extremely + // slow. But lower utilization wastes disk space. As a reasonable + // load factor, we choose 80%. We need +1 because slot 0 is reserved. + return (NumStrings + 1) * 1.25; +} + +uint32_t PDBStringTableBuilder::calculateHashTableSize() const { + uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field. + Size += sizeof(uint32_t) * computeBucketCount(Strings.size()); + + return Size; +} + +uint32_t PDBStringTableBuilder::calculateSerializedSize() const { + uint32_t Size = 0; + Size += sizeof(PDBStringTableHeader); + Size += Strings.calculateSerializedSize(); + Size += calculateHashTableSize(); + Size += sizeof(uint32_t); // The /names stream ends with the string count. + return Size; +} + +Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const { + // Write a header + PDBStringTableHeader H; + H.Signature = PDBStringTableSignature; + H.HashVersion = 1; + H.ByteSize = Strings.calculateSerializedSize(); + if (auto EC = Writer.writeObject(H)) + return EC; + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const { + if (auto EC = Strings.commit(Writer)) + return EC; + + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const { + // Write a hash table. + uint32_t BucketCount = computeBucketCount(Strings.size()); + if (auto EC = Writer.writeInteger(BucketCount)) + return EC; + std::vector<ulittle32_t> Buckets(BucketCount); + + for (auto &Pair : Strings) { + StringRef S = Pair.getKey(); + uint32_t Offset = Pair.getValue(); + uint32_t Hash = hashStringV1(S); + + for (uint32_t I = 0; I != BucketCount; ++I) { + uint32_t Slot = (Hash + I) % BucketCount; + if (Slot == 0) + continue; // Skip reserved slot + if (Buckets[Slot] != 0) + continue; + Buckets[Slot] = Offset; + break; + } + } + + if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) + return EC; + + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const { + if (auto EC = Writer.writeInteger<uint32_t>(Strings.size())) + return EC; + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const { + BinaryStreamWriter SectionWriter; + + std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader)); + if (auto EC = writeHeader(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = + Writer.split(Strings.calculateSerializedSize()); + if (auto EC = writeStrings(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize()); + if (auto EC = writeHashTable(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t)); + if (auto EC = writeEpilogue(SectionWriter)) + return EC; + + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/StringTable.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/StringTable.cpp deleted file mode 100644 index 7e28389b8383..000000000000 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/StringTable.cpp +++ /dev/null @@ -1,109 +0,0 @@ -//===- StringTable.cpp - PDB String 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/Native/StringTable.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support; -using namespace llvm::pdb; - -StringTable::StringTable() {} - -Error StringTable::load(BinaryStreamReader &Stream) { - ByteSize = Stream.getLength(); - - const StringTableHeader *H; - if (auto EC = Stream.readObject(H)) - return EC; - - if (H->Signature != StringTableSignature) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid hash table signature"); - 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 = Stream.readStreamRef(NamesBuffer, H->ByteSize)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Invalid hash table byte length")); - - const support::ulittle32_t *HashCount; - if (auto EC = Stream.readObject(HashCount)) - return EC; - - if (auto EC = Stream.readArray(IDs, *HashCount)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read bucket array")); - - if (Stream.bytesRemaining() < sizeof(support::ulittle32_t)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Missing name count"); - - if (auto EC = Stream.readInteger(NameCount)) - return EC; - - if (Stream.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::stream_too_long, - "Unexpected bytes found in string table"); - - return Error::success(); -} - -uint32_t StringTable::getByteSize() const { - return ByteSize; -} - -StringRef StringTable::getStringForID(uint32_t ID) const { - if (ID == IDs[0]) - return StringRef(); - - // 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; - BinaryStreamReader NameReader(NamesBuffer); - NameReader.setOffset(ID); - if (auto EC = NameReader.readCString(Result)) - consumeError(std::move(EC)); - return Result; -} - -uint32_t StringTable::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) { - // The hash is just a starting point for the search, but if it - // doesn't work we should find the string no matter what, because - // we iterate the entire array. - uint32_t Index = (Start + I) % Count; - - uint32_t ID = IDs[Index]; - StringRef S = getStringForID(ID); - if (S == Str) - return ID; - } - // IDs[0] contains the ID of the "invalid" entry. - return IDs[0]; -} - -FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const { - return IDs; -} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp deleted file mode 100644 index e0f8370ab608..000000000000 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===- StringTableBuilder.cpp - PDB String 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/Native/StringTableBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support; -using namespace llvm::support::endian; -using namespace llvm::pdb; - -uint32_t StringTableBuilder::insert(StringRef S) { - auto P = Strings.insert({S, StringSize}); - - // If a given string didn't exist in the string table, we want to increment - // the string table size. - if (P.second) - StringSize += S.size() + 1; // +1 for '\0' - return P.first->second; -} - -static uint32_t computeBucketCount(uint32_t NumStrings) { - // The /names stream is basically an on-disk open-addressing hash table. - // Hash collisions are resolved by linear probing. We cannot make - // utilization 100% because it will make the linear probing extremely - // slow. But lower utilization wastes disk space. As a reasonable - // load factor, we choose 80%. We need +1 because slot 0 is reserved. - return (NumStrings + 1) * 1.25; -} - -uint32_t StringTableBuilder::finalize() { - uint32_t Size = 0; - Size += sizeof(StringTableHeader); - Size += StringSize; - Size += sizeof(uint32_t); // Hash table begins with 4-byte size field. - - uint32_t BucketCount = computeBucketCount(Strings.size()); - Size += BucketCount * sizeof(uint32_t); - - Size += - sizeof(uint32_t); // The /names stream ends with the number of strings. - return Size; -} - -Error StringTableBuilder::commit(BinaryStreamWriter &Writer) const { - // Write a header - StringTableHeader H; - H.Signature = StringTableSignature; - H.HashVersion = 1; - H.ByteSize = StringSize; - if (auto EC = Writer.writeObject(H)) - return EC; - - // Write a string table. - uint32_t StringStart = Writer.getOffset(); - for (auto Pair : Strings) { - StringRef S = Pair.first; - uint32_t Offset = Pair.second; - Writer.setOffset(StringStart + Offset); - if (auto EC = Writer.writeCString(S)) - return EC; - } - Writer.setOffset(StringStart + StringSize); - - // Write a hash table. - uint32_t BucketCount = computeBucketCount(Strings.size()); - if (auto EC = Writer.writeInteger(BucketCount)) - return EC; - std::vector<ulittle32_t> Buckets(BucketCount); - - for (auto Pair : Strings) { - StringRef S = Pair.first; - uint32_t Offset = Pair.second; - uint32_t Hash = hashStringV1(S); - - for (uint32_t I = 0; I != BucketCount; ++I) { - uint32_t Slot = (Hash + I) % BucketCount; - if (Slot == 0) - continue; // Skip reserved slot - if (Buckets[Slot] != 0) - continue; - Buckets[Slot] = Offset; - break; - } - } - - if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) - return EC; - if (auto EC = Writer.writeInteger(static_cast<uint32_t>(Strings.size()))) - return EC; - return Error::success(); -} diff --git a/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp index 7e56859c40e6..a41a065a983c 100644 --- a/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -467,8 +467,9 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status); #endif -std::string LLVMSymbolizer::DemangleName(const std::string &Name, - const SymbolizableModule *ModInfo) { +std::string +LLVMSymbolizer::DemangleName(const std::string &Name, + const SymbolizableModule *DbiModuleDescriptor) { #if !defined(_MSC_VER) // We can spoil names of symbols with C linkage, so use an heuristic // approach to check if the name should be demangled. @@ -496,7 +497,7 @@ std::string LLVMSymbolizer::DemangleName(const std::string &Name, return (result == 0) ? Name : std::string(DemangledName); } #endif - if (ModInfo && ModInfo->isWin32Module()) + if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) return std::string(demanglePE32ExternCFunc(Name)); return Name; } |