Skip to content

Commit

Permalink
[CodeView] Isolate Debug Info Fragments into standalone classes.
Browse files Browse the repository at this point in the history
Previously parsing of these were all grouped together into a
single master class that could parse any type of debug info
fragment.

With writing forthcoming, the complexity of each individual
fragment is enough to warrant them having their own classes so
that reading and writing of each fragment type can be grouped
together, but isolated from the code for reading and writing
other fragment types.

In doing so, I found a place where parsing code was duplicated
for the FileChecksums fragment, across llvm-readobj and the
CodeView library, and one of the implementations had a bug.
Now that the codepaths are merged, the bug is resolved.

Differential Revision: https://reviews.llvm.org/D32547

llvm-svn: 301557
  • Loading branch information
Zachary Turner committed Apr 27, 2017
1 parent e509447 commit c37cb0c
Show file tree
Hide file tree
Showing 19 changed files with 511 additions and 326 deletions.
7 changes: 0 additions & 7 deletions llvm/include/llvm/DebugInfo/CodeView/Line.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,6 @@ struct InlineeSourceLine {
// ulittle32_t Files[];
};

struct FileChecksum {
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.
};

} // namespace codeview
} // namespace llvm

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===- ModuleDebugLineFragment.h --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFILECHECKSUMFRAGMENT_H
#define LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFILECHECKSUMFRAGMENT_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Endian.h"

namespace llvm {
namespace codeview {

struct FileChecksumEntry {
uint32_t FileNameOffset; // Byte offset of filename in global stringtable.
FileChecksumKind Kind; // The type of checksum.
ArrayRef<uint8_t> Checksum; // The bytes of the checksum.
};
}
}

namespace llvm {
template <> struct VarStreamArrayExtractor<codeview::FileChecksumEntry> {
public:
typedef void ContextType;

static Error extract(BinaryStreamRef Stream, uint32_t &Len,
codeview::FileChecksumEntry &Item, void *Ctx);
};
}

namespace llvm {
namespace codeview {
class ModuleDebugFileChecksumFragment final : public ModuleDebugFragment {
typedef VarStreamArray<FileChecksumEntry> FileChecksumArray;
typedef FileChecksumArray::Iterator Iterator;

public:
ModuleDebugFileChecksumFragment()
: ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums) {}

static bool classof(const ModuleDebugFragment *S) {
return S->kind() == ModuleDebugFragmentKind::FileChecksums;
}

Error initialize(BinaryStreamReader Reader);

Iterator begin() const { return Checksums.begin(); }
Iterator end() const { return Checksums.end(); }

private:
FileChecksumArray Checksums;
};
}
}

#endif
68 changes: 6 additions & 62 deletions llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragment.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,79 +11,23 @@
#define LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENT_H

#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Casting.h"

namespace llvm {
namespace codeview {

// Corresponds to the `CV_DebugSSubsectionHeader_t` structure.
struct ModuleDebugFragmentHeader {
support::ulittle32_t Kind; // codeview::ModuleDebugFragmentKind enum
support::ulittle32_t Length; // number of bytes occupied by this record.
};

// Corresponds to the `CV_DebugSLinesHeader_t` structure.
struct LineFragmentHeader {
support::ulittle32_t RelocOffset; // Code offset of line contribution.
support::ulittle16_t RelocSegment; // Code segment of line contribution.
support::ulittle16_t Flags; // See LineFlags enumeration.
support::ulittle32_t CodeSize; // Code size of this line contribution.
};

// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure.
struct LineBlockFragmentHeader {
support::ulittle32_t NameIndex; // Index in DBI name buffer of filename.
support::ulittle32_t NumLines; // Number of lines
support::ulittle32_t BlockSize; // Code size of block, in bytes.
// The following two variable length arrays appear immediately after the
// header. The structure definitions follow.
// LineNumberEntry Lines[NumLines];
// ColumnNumberEntry Columns[NumLines];
};

// Corresponds to `CV_Line_t` structure
struct LineNumberEntry {
support::ulittle32_t Offset; // Offset to start of code bytes for line number
support::ulittle32_t Flags; // Start:24, End:7, IsStatement:1
};

// Corresponds to `CV_Column_t` structure
struct ColumnNumberEntry {
support::ulittle16_t StartColumn;
support::ulittle16_t EndColumn;
};

class ModuleDebugFragment {
public:
ModuleDebugFragment();
ModuleDebugFragment(ModuleDebugFragmentKind Kind, BinaryStreamRef Data);
static Error initialize(BinaryStreamRef Stream, ModuleDebugFragment &Info);
uint32_t getRecordLength() const;
ModuleDebugFragmentKind kind() const;
BinaryStreamRef getRecordData() const;
explicit ModuleDebugFragment(ModuleDebugFragmentKind Kind) : Kind(Kind) {}

virtual ~ModuleDebugFragment();
ModuleDebugFragmentKind kind() const { return Kind; }

private:
protected:
ModuleDebugFragmentKind Kind;
BinaryStreamRef Data;
};

typedef VarStreamArray<ModuleDebugFragment> ModuleDebugFragmentArray;
} // namespace codeview

template <> struct VarStreamArrayExtractor<codeview::ModuleDebugFragment> {
typedef void ContextType;

static Error extract(BinaryStreamRef Stream, uint32_t &Length,
codeview::ModuleDebugFragment &Info, void *Ctx) {
if (auto EC = codeview::ModuleDebugFragment::initialize(Stream, Info))
return EC;
Length = Info.getRecordLength();
return Error::success();
}
};
} // namespace llvm

#endif // LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENT_H
62 changes: 62 additions & 0 deletions llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===- ModuleDebugFragment.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H
#define LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H

#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"

namespace llvm {
namespace codeview {

// Corresponds to the `CV_DebugSSubsectionHeader_t` structure.
struct ModuleDebugFragmentHeader {
support::ulittle32_t Kind; // codeview::ModuleDebugFragmentKind enum
support::ulittle32_t Length; // number of bytes occupied by this record.
};

class ModuleDebugFragmentRecord {
public:
ModuleDebugFragmentRecord();
ModuleDebugFragmentRecord(ModuleDebugFragmentKind Kind, BinaryStreamRef Data);

static Error initialize(BinaryStreamRef Stream,
ModuleDebugFragmentRecord &Info);
uint32_t getRecordLength() const;
ModuleDebugFragmentKind kind() const;
BinaryStreamRef getRecordData() const;

private:
ModuleDebugFragmentKind Kind;
BinaryStreamRef Data;
};

typedef VarStreamArray<ModuleDebugFragmentRecord> ModuleDebugFragmentArray;

} // namespace codeview

template <>
struct VarStreamArrayExtractor<codeview::ModuleDebugFragmentRecord> {
typedef void ContextType;

static Error extract(BinaryStreamRef Stream, uint32_t &Length,
codeview::ModuleDebugFragmentRecord &Info, void *Ctx) {
if (auto EC = codeview::ModuleDebugFragmentRecord::initialize(Stream, Info))
return EC;
Length = Info.getRecordLength();
return Error::success();
}
};
} // namespace llvm

#endif // LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H
102 changes: 13 additions & 89 deletions llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamRef.h"
Expand All @@ -26,105 +29,26 @@ namespace llvm {

namespace codeview {

struct LineColumnEntry {
support::ulittle32_t NameIndex;
FixedStreamArray<LineNumberEntry> LineNumbers;
FixedStreamArray<ColumnNumberEntry> Columns;
};

struct FileChecksumEntry {
uint32_t FileNameOffset; // Byte offset of filename in global stringtable.
FileChecksumKind Kind; // The type of checksum.
ArrayRef<uint8_t> Checksum; // The bytes of the checksum.
};

typedef VarStreamArray<LineColumnEntry> LineInfoArray;
typedef VarStreamArray<FileChecksumEntry> FileChecksumArray;

class ModuleDebugFragmentVisitor {
public:
virtual ~ModuleDebugFragmentVisitor() = default;

virtual Error visitUnknown(ModuleDebugFragmentKind Kind,
BinaryStreamRef Data) = 0;
virtual Error visitSymbols(BinaryStreamRef Data);
virtual Error visitLines(BinaryStreamRef Data,
const LineFragmentHeader *Header,
const LineInfoArray &Lines);
virtual Error visitStringTable(BinaryStreamRef Data);
virtual Error visitFileChecksums(BinaryStreamRef Data,
const FileChecksumArray &Checksums);
virtual Error visitFrameData(BinaryStreamRef Data);
virtual Error visitInlineeLines(BinaryStreamRef Data);
virtual Error visitCrossScopeImports(BinaryStreamRef Data);
virtual Error visitCrossScopeExports(BinaryStreamRef Data);
virtual Error visitILLines(BinaryStreamRef Data);
virtual Error visitFuncMDTokenMap(BinaryStreamRef Data);
virtual Error visitTypeMDTokenMap(BinaryStreamRef Data);
virtual Error visitMergedAssemblyInput(BinaryStreamRef Data);
virtual Error visitCoffSymbolRVA(BinaryStreamRef Data);
};

Error visitModuleDebugFragment(const ModuleDebugFragment &R,
ModuleDebugFragmentVisitor &V);
} // end namespace codeview

template <> class VarStreamArrayExtractor<codeview::LineColumnEntry> {
public:
typedef const codeview::LineFragmentHeader ContextType;

static Error extract(BinaryStreamRef Stream, uint32_t &Len,
codeview::LineColumnEntry &Item, ContextType *Header) {
using namespace codeview;
const LineBlockFragmentHeader *BlockHeader;
BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readObject(BlockHeader))
return EC;
bool HasColumn = Header->Flags & uint32_t(LineFlags::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;
}
virtual Error visitUnknown(ModuleDebugUnknownFragment &Unknown) {
return Error::success();
}
virtual Error visitLines(ModuleDebugLineFragment &Lines) {
return Error::success();
}
};

template <> class VarStreamArrayExtractor<codeview::FileChecksumEntry> {
public:
typedef void ContextType;

static Error extract(BinaryStreamRef Stream, uint32_t &Len,
codeview::FileChecksumEntry &Item, void *Ctx) {
using namespace codeview;
const FileChecksum *Header;
BinaryStreamReader Reader(Stream);
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 = sizeof(FileChecksum) + Header->ChecksumSize;
virtual Error visitFileChecksums(ModuleDebugFileChecksumFragment &Checksums) {
return Error::success();
}
};

Error visitModuleDebugFragment(const ModuleDebugFragmentRecord &R,
ModuleDebugFragmentVisitor &V);
} // end namespace codeview

} // end namespace llvm

#endif // LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTVISITOR_H

0 comments on commit c37cb0c

Please sign in to comment.