1 | //===- DebugLinesSubsection.cpp -------------------------------------------===// |
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 | #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" |
10 | #include "llvm/ADT/ArrayRef.h" |
11 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
12 | #include "llvm/DebugInfo/CodeView/CodeViewError.h" |
13 | #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" |
14 | #include "llvm/Support/BinaryStreamReader.h" |
15 | #include "llvm/Support/BinaryStreamWriter.h" |
16 | #include "llvm/Support/Error.h" |
17 | #include <cassert> |
18 | #include <cstdint> |
19 | |
20 | using namespace llvm; |
21 | using namespace llvm::codeview; |
22 | |
23 | Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len, |
24 | LineColumnEntry &Item) { |
25 | const LineBlockFragmentHeader *; |
26 | BinaryStreamReader Reader(Stream); |
27 | if (auto EC = Reader.readObject(Dest&: BlockHeader)) |
28 | return EC; |
29 | bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns); |
30 | uint32_t LineInfoSize = |
31 | BlockHeader->NumLines * |
32 | (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); |
33 | if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader)) |
34 | return make_error<CodeViewError>(Args: cv_error_code::corrupt_record, |
35 | Args: "Invalid line block record size" ); |
36 | uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader); |
37 | if (LineInfoSize > Size) |
38 | return make_error<CodeViewError>(Args: cv_error_code::corrupt_record, |
39 | Args: "Invalid line block record size" ); |
40 | // The value recorded in BlockHeader->BlockSize includes the size of |
41 | // LineBlockFragmentHeader. |
42 | Len = BlockHeader->BlockSize; |
43 | Item.NameIndex = BlockHeader->NameIndex; |
44 | if (auto EC = Reader.readArray(Array&: Item.LineNumbers, NumItems: BlockHeader->NumLines)) |
45 | return EC; |
46 | if (HasColumn) { |
47 | if (auto EC = Reader.readArray(Array&: Item.Columns, NumItems: BlockHeader->NumLines)) |
48 | return EC; |
49 | } |
50 | return Error::success(); |
51 | } |
52 | |
53 | DebugLinesSubsectionRef::DebugLinesSubsectionRef() |
54 | : DebugSubsectionRef(DebugSubsectionKind::Lines) {} |
55 | |
56 | Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) { |
57 | if (auto EC = Reader.readObject(Dest&: Header)) |
58 | return EC; |
59 | |
60 | LinesAndColumns.getExtractor().Header = Header; |
61 | if (auto EC = Reader.readArray(Array&: LinesAndColumns, Size: Reader.bytesRemaining())) |
62 | return EC; |
63 | |
64 | return Error::success(); |
65 | } |
66 | |
67 | bool DebugLinesSubsectionRef::hasColumnInfo() const { |
68 | return !!(Header->Flags & LF_HaveColumns); |
69 | } |
70 | |
71 | DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums, |
72 | DebugStringTableSubsection &Strings) |
73 | : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {} |
74 | |
75 | void DebugLinesSubsection::createBlock(StringRef FileName) { |
76 | uint32_t Offset = Checksums.mapChecksumOffset(FileName); |
77 | |
78 | Blocks.emplace_back(args&: Offset); |
79 | } |
80 | |
81 | void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) { |
82 | Block &B = Blocks.back(); |
83 | LineNumberEntry LNE; |
84 | LNE.Flags = Line.getRawData(); |
85 | LNE.Offset = Offset; |
86 | B.Lines.push_back(x: LNE); |
87 | } |
88 | |
89 | void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset, |
90 | const LineInfo &Line, |
91 | uint32_t ColStart, |
92 | uint32_t ColEnd) { |
93 | Block &B = Blocks.back(); |
94 | assert(B.Lines.size() == B.Columns.size()); |
95 | |
96 | addLineInfo(Offset, Line); |
97 | ColumnNumberEntry CNE; |
98 | CNE.StartColumn = ColStart; |
99 | CNE.EndColumn = ColEnd; |
100 | B.Columns.push_back(x: CNE); |
101 | } |
102 | |
103 | Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const { |
104 | LineFragmentHeader ; |
105 | Header.CodeSize = CodeSize; |
106 | Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0; |
107 | Header.RelocOffset = RelocOffset; |
108 | Header.RelocSegment = RelocSegment; |
109 | |
110 | if (auto EC = Writer.writeObject(Obj: Header)) |
111 | return EC; |
112 | |
113 | for (const auto &B : Blocks) { |
114 | LineBlockFragmentHeader ; |
115 | assert(B.Lines.size() == B.Columns.size() || B.Columns.empty()); |
116 | |
117 | BlockHeader.NumLines = B.Lines.size(); |
118 | BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader); |
119 | BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry); |
120 | if (hasColumnInfo()) |
121 | BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry); |
122 | BlockHeader.NameIndex = B.ChecksumBufferOffset; |
123 | if (auto EC = Writer.writeObject(Obj: BlockHeader)) |
124 | return EC; |
125 | |
126 | if (auto EC = Writer.writeArray(Array: ArrayRef(B.Lines))) |
127 | return EC; |
128 | |
129 | if (hasColumnInfo()) { |
130 | if (auto EC = Writer.writeArray(Array: ArrayRef(B.Columns))) |
131 | return EC; |
132 | } |
133 | } |
134 | return Error::success(); |
135 | } |
136 | |
137 | uint32_t DebugLinesSubsection::calculateSerializedSize() const { |
138 | uint32_t Size = sizeof(LineFragmentHeader); |
139 | for (const auto &B : Blocks) { |
140 | Size += sizeof(LineBlockFragmentHeader); |
141 | Size += B.Lines.size() * sizeof(LineNumberEntry); |
142 | if (hasColumnInfo()) |
143 | Size += B.Columns.size() * sizeof(ColumnNumberEntry); |
144 | } |
145 | return Size; |
146 | } |
147 | |
148 | void DebugLinesSubsection::setRelocationAddress(uint16_t Segment, |
149 | uint32_t Offset) { |
150 | RelocOffset = Offset; |
151 | RelocSegment = Segment; |
152 | } |
153 | |
154 | void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; } |
155 | |
156 | void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; } |
157 | |
158 | bool DebugLinesSubsection::hasColumnInfo() const { |
159 | return Flags & LF_HaveColumns; |
160 | } |
161 | |