1 //===- DebugLinesSubsection.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
21 using namespace llvm::codeview
;
23 Error
LineColumnExtractor::operator()(BinaryStreamRef Stream
, uint32_t &Len
,
24 LineColumnEntry
&Item
) {
25 const LineBlockFragmentHeader
*BlockHeader
;
26 BinaryStreamReader
Reader(Stream
);
27 if (auto EC
= Reader
.readObject(BlockHeader
))
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
>(cv_error_code::corrupt_record
,
35 "Invalid line block record size");
36 uint32_t Size
= BlockHeader
->BlockSize
- sizeof(LineBlockFragmentHeader
);
37 if (LineInfoSize
> Size
)
38 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
,
39 "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(Item
.LineNumbers
, BlockHeader
->NumLines
))
47 if (auto EC
= Reader
.readArray(Item
.Columns
, BlockHeader
->NumLines
))
50 return Error::success();
53 DebugLinesSubsectionRef::DebugLinesSubsectionRef()
54 : DebugSubsectionRef(DebugSubsectionKind::Lines
) {}
56 Error
DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader
) {
57 if (auto EC
= Reader
.readObject(Header
))
60 LinesAndColumns
.getExtractor().Header
= Header
;
61 if (auto EC
= Reader
.readArray(LinesAndColumns
, Reader
.bytesRemaining()))
64 return Error::success();
67 bool DebugLinesSubsectionRef::hasColumnInfo() const {
68 return !!(Header
->Flags
& LF_HaveColumns
);
71 DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection
&Checksums
,
72 DebugStringTableSubsection
&Strings
)
73 : DebugSubsection(DebugSubsectionKind::Lines
), Checksums(Checksums
) {}
75 void DebugLinesSubsection::createBlock(StringRef FileName
) {
76 uint32_t Offset
= Checksums
.mapChecksumOffset(FileName
);
78 Blocks
.emplace_back(Offset
);
81 void DebugLinesSubsection::addLineInfo(uint32_t Offset
, const LineInfo
&Line
) {
82 Block
&B
= Blocks
.back();
84 LNE
.Flags
= Line
.getRawData();
86 B
.Lines
.push_back(LNE
);
89 void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset
,
93 Block
&B
= Blocks
.back();
94 assert(B
.Lines
.size() == B
.Columns
.size());
96 addLineInfo(Offset
, Line
);
97 ColumnNumberEntry CNE
;
98 CNE
.StartColumn
= ColStart
;
99 CNE
.EndColumn
= ColEnd
;
100 B
.Columns
.push_back(CNE
);
103 Error
DebugLinesSubsection::commit(BinaryStreamWriter
&Writer
) const {
104 LineFragmentHeader Header
;
105 Header
.CodeSize
= CodeSize
;
106 Header
.Flags
= hasColumnInfo() ? LF_HaveColumns
: 0;
107 Header
.RelocOffset
= RelocOffset
;
108 Header
.RelocSegment
= RelocSegment
;
110 if (auto EC
= Writer
.writeObject(Header
))
113 for (const auto &B
: Blocks
) {
114 LineBlockFragmentHeader BlockHeader
;
115 assert(B
.Lines
.size() == B
.Columns
.size() || B
.Columns
.empty());
117 BlockHeader
.NumLines
= B
.Lines
.size();
118 BlockHeader
.BlockSize
= sizeof(LineBlockFragmentHeader
);
119 BlockHeader
.BlockSize
+= BlockHeader
.NumLines
* sizeof(LineNumberEntry
);
121 BlockHeader
.BlockSize
+= BlockHeader
.NumLines
* sizeof(ColumnNumberEntry
);
122 BlockHeader
.NameIndex
= B
.ChecksumBufferOffset
;
123 if (auto EC
= Writer
.writeObject(BlockHeader
))
126 if (auto EC
= Writer
.writeArray(makeArrayRef(B
.Lines
)))
129 if (hasColumnInfo()) {
130 if (auto EC
= Writer
.writeArray(makeArrayRef(B
.Columns
)))
134 return Error::success();
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
);
143 Size
+= B
.Columns
.size() * sizeof(ColumnNumberEntry
);
148 void DebugLinesSubsection::setRelocationAddress(uint16_t Segment
,
150 RelocOffset
= Offset
;
151 RelocSegment
= Segment
;
154 void DebugLinesSubsection::setCodeSize(uint32_t Size
) { CodeSize
= Size
; }
156 void DebugLinesSubsection::setFlags(LineFlags Flags
) { this->Flags
= Flags
; }
158 bool DebugLinesSubsection::hasColumnInfo() const {
159 return Flags
& LF_HaveColumns
;