1//===- DebugLinesSubsection.h -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGLINESSUBSECTION_H
10#define LLVM_DEBUGINFO_CODEVIEW_DEBUGLINESSUBSECTION_H
11
12#include "llvm/ADT/StringRef.h"
13#include "llvm/DebugInfo/CodeView/CodeView.h"
14#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
15#include "llvm/DebugInfo/CodeView/Line.h"
16#include "llvm/Support/BinaryStreamArray.h"
17#include "llvm/Support/BinaryStreamReader.h"
18#include "llvm/Support/BinaryStreamRef.h"
19#include "llvm/Support/Endian.h"
20#include "llvm/Support/Error.h"
21#include <cstdint>
22#include <vector>
23
24namespace llvm {
25namespace codeview {
26
27class DebugChecksumsSubsection;
28class DebugStringTableSubsection;
29
30// Corresponds to the `CV_DebugSLinesHeader_t` structure.
31struct LineFragmentHeader {
32  support::ulittle32_t RelocOffset;  // Code offset of line contribution.
33  support::ulittle16_t RelocSegment; // Code segment of line contribution.
34  support::ulittle16_t Flags;        // See LineFlags enumeration.
35  support::ulittle32_t CodeSize;     // Code size of this line contribution.
36};
37
38// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure.
39struct LineBlockFragmentHeader {
40  support::ulittle32_t NameIndex; // Offset of FileChecksum entry in File
41                                  // checksums buffer.  The checksum entry then
42                                  // contains another offset into the string
43                                  // table of the actual name.
44  support::ulittle32_t NumLines;  // Number of lines
45  support::ulittle32_t BlockSize; // Code size of block, in bytes.
46  // The following two variable length arrays appear immediately after the
47  // header.  The structure definitions follow.
48  // LineNumberEntry   Lines[NumLines];
49  // ColumnNumberEntry Columns[NumLines];
50};
51
52// Corresponds to `CV_Line_t` structure
53struct LineNumberEntry {
54  support::ulittle32_t Offset; // Offset to start of code bytes for line number
55  support::ulittle32_t Flags;  // Start:24, End:7, IsStatement:1
56};
57
58// Corresponds to `CV_Column_t` structure
59struct ColumnNumberEntry {
60  support::ulittle16_t StartColumn;
61  support::ulittle16_t EndColumn;
62};
63
64struct LineColumnEntry {
65  support::ulittle32_t NameIndex;
66  FixedStreamArray<LineNumberEntry> LineNumbers;
67  FixedStreamArray<ColumnNumberEntry> Columns;
68};
69
70class LineColumnExtractor {
71public:
72  Error operator()(BinaryStreamRef Stream, uint32_t &Len,
73                   LineColumnEntry &Item);
74
75  const LineFragmentHeader *Header = nullptr;
76};
77
78class DebugLinesSubsectionRef final : public DebugSubsectionRef {
79  friend class LineColumnExtractor;
80
81  using LineInfoArray = VarStreamArray<LineColumnEntry, LineColumnExtractor>;
82  using Iterator = LineInfoArray::Iterator;
83
84public:
85  DebugLinesSubsectionRef();
86
87  static bool classof(const DebugSubsectionRef *S) {
88    return S->kind() == DebugSubsectionKind::Lines;
89  }
90
91  Error initialize(BinaryStreamReader Reader);
92
93  Iterator begin() const { return LinesAndColumns.begin(); }
94  Iterator end() const { return LinesAndColumns.end(); }
95
96  const LineFragmentHeader *header() const { return Header; }
97
98  bool hasColumnInfo() const;
99
100private:
101  const LineFragmentHeader *Header = nullptr;
102  LineInfoArray LinesAndColumns;
103};
104
105class DebugLinesSubsection final : public DebugSubsection {
106  struct Block {
107    Block(uint32_t ChecksumBufferOffset)
108        : ChecksumBufferOffset(ChecksumBufferOffset) {}
109
110    uint32_t ChecksumBufferOffset;
111    std::vector<LineNumberEntry> Lines;
112    std::vector<ColumnNumberEntry> Columns;
113  };
114
115public:
116  DebugLinesSubsection(DebugChecksumsSubsection &Checksums,
117                       DebugStringTableSubsection &Strings);
118
119  static bool classof(const DebugSubsection *S) {
120    return S->kind() == DebugSubsectionKind::Lines;
121  }
122
123  void createBlock(StringRef FileName);
124  void addLineInfo(uint32_t Offset, const LineInfo &Line);
125  void addLineAndColumnInfo(uint32_t Offset, const LineInfo &Line,
126                            uint32_t ColStart, uint32_t ColEnd);
127
128  uint32_t calculateSerializedSize() const override;
129  Error commit(BinaryStreamWriter &Writer) const override;
130
131  void setRelocationAddress(uint16_t Segment, uint32_t Offset);
132  void setCodeSize(uint32_t Size);
133  void setFlags(LineFlags Flags);
134
135  bool hasColumnInfo() const;
136
137private:
138  DebugChecksumsSubsection &Checksums;
139  uint32_t RelocOffset = 0;
140  uint16_t RelocSegment = 0;
141  uint32_t CodeSize = 0;
142  LineFlags Flags = LF_None;
143  std::vector<Block> Blocks;
144};
145
146} // end namespace codeview
147} // end namespace llvm
148
149#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGLINESSUBSECTION_H
150