aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h
blob: 31344a9427db5f6e58145172b2db81a5a780661a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//===- ModuleSubstreamVisitor.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_MODULESUBSTREAMVISITOR_H
#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <cstdint>

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 IModuleSubstreamVisitor {
public:
  virtual ~IModuleSubstreamVisitor() = default;

  virtual Error visitUnknown(ModuleSubstreamKind Kind,
                             BinaryStreamRef Data) = 0;
  virtual Error visitSymbols(BinaryStreamRef Data);
  virtual Error visitLines(BinaryStreamRef Data,
                           const LineSubstreamHeader *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 visitModuleSubstream(const ModuleSubstream &R,
                           IModuleSubstreamVisitor &V);
} // end namespace codeview

template <> class VarStreamArrayExtractor<codeview::LineColumnEntry> {
public:
  VarStreamArrayExtractor(const codeview::LineSubstreamHeader *Header)
      : Header(Header) {}

  Error operator()(BinaryStreamRef Stream, uint32_t &Len,
                   codeview::LineColumnEntry &Item) const {
    using namespace codeview;
    const LineFileBlockHeader *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(LineFileBlockHeader))
      return make_error<CodeViewError>(cv_error_code::corrupt_record,
                                       "Invalid line block record size");
    uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader);
    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
    // LineFileBlockHeader.
    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();
  }

private:
  const codeview::LineSubstreamHeader *Header;
};

template <> class VarStreamArrayExtractor<codeview::FileChecksumEntry> {
public:
  Error operator()(BinaryStreamRef Stream, uint32_t &Len,
                   codeview::FileChecksumEntry &Item) const {
    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;
    return Error::success();
  }
};

} // end namespace llvm

#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H