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