LLVM 19.0.0git
DebugLineSectionEmitter.h
Go to the documentation of this file.
1//===- DebugLineSectionEmitter.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_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H
10#define LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H
11
12#include "DWARFEmitterImpl.h"
18
19namespace llvm {
20namespace dwarf_linker {
21namespace parallel {
22
23/// This class emits specified line table into the .debug_line section.
25public:
27 : TheTriple(TheTriple), U(U) {}
28
30 // FIXME: remove dependence on MCDwarfLineAddr::encode.
31 // As we reuse MCDwarfLineAddr::encode, we need to create/initialize
32 // some MC* classes.
33 if (Error Err = init(TheTriple))
34 return Err;
35
36 // Get descriptor for output .debug_line section.
37 SectionDescriptor &OutSection =
39
40 // unit_length.
41 OutSection.emitUnitLength(0xBADDEF);
42 uint64_t OffsetAfterUnitLength = OutSection.OS.tell();
43
44 // Emit prologue.
45 emitLineTablePrologue(LineTable.Prologue, OutSection);
46
47 // Emit rows.
48 emitLineTableRows(LineTable, OutSection);
49 uint64_t OffsetAfterEnd = OutSection.OS.tell();
50
51 // Update unit length field with actual length value.
52 assert(OffsetAfterUnitLength -
54 OffsetAfterUnitLength);
55 OutSection.apply(OffsetAfterUnitLength -
57 dwarf::DW_FORM_sec_offset,
58 OffsetAfterEnd - OffsetAfterUnitLength);
59
60 return Error::success();
61 }
62
63private:
64 Error init(Triple TheTriple) {
65 std::string ErrorStr;
66 std::string TripleName;
67
68 // Get the target.
69 const Target *TheTarget =
70 TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
71 if (!TheTarget)
72 return createStringError(std::errc::invalid_argument, ErrorStr.c_str());
73 TripleName = TheTriple.getTriple();
74
75 // Create all the MC Objects.
76 MRI.reset(TheTarget->createMCRegInfo(TripleName));
77 if (!MRI)
78 return createStringError(std::errc::invalid_argument,
79 "no register info for target %s",
80 TripleName.c_str());
81
83 MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
84 if (!MAI)
85 return createStringError(std::errc::invalid_argument,
86 "no asm info for target %s", TripleName.c_str());
87
88 MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
89 if (!MSTI)
90 return createStringError(std::errc::invalid_argument,
91 "no subtarget info for target %s",
92 TripleName.c_str());
93
94 MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,
95 nullptr, true, "__DWARF"));
96
97 return Error::success();
98 }
99
100 void emitLineTablePrologue(const DWARFDebugLine::Prologue &P,
101 SectionDescriptor &Section) {
102 // version (uhalf).
103 Section.emitIntVal(P.getVersion(), 2);
104 if (P.getVersion() == 5) {
105 // address_size (ubyte).
106 Section.emitIntVal(P.getAddressSize(), 1);
107
108 // segment_selector_size (ubyte).
109 Section.emitIntVal(P.SegSelectorSize, 1);
110 }
111
112 // header_length.
113 Section.emitOffset(0xBADDEF);
114
115 uint64_t OffsetAfterPrologueLength = Section.OS.tell();
116 emitLineTableProloguePayload(P, Section);
117 uint64_t OffsetAfterPrologueEnd = Section.OS.tell();
118
119 // Update prologue length field with actual length value.
120 Section.apply(OffsetAfterPrologueLength -
121 Section.getFormParams().getDwarfOffsetByteSize(),
122 dwarf::DW_FORM_sec_offset,
123 OffsetAfterPrologueEnd - OffsetAfterPrologueLength);
124 }
125
126 void
127 emitLineTablePrologueV2IncludeAndFileTable(const DWARFDebugLine::Prologue &P,
128 SectionDescriptor &Section) {
129 // include_directories (sequence of path names).
130 for (const DWARFFormValue &Include : P.IncludeDirectories) {
131 std::optional<const char *> IncludeStr = dwarf::toString(Include);
132 if (!IncludeStr) {
133 U.warn("cann't read string from line table.");
134 return;
135 }
136
137 Section.emitString(Include.getForm(), *IncludeStr);
138 }
139 // The last entry is followed by a single null byte.
140 Section.emitIntVal(0, 1);
141
142 // file_names (sequence of file entries).
143 for (const DWARFDebugLine::FileNameEntry &File : P.FileNames) {
144 std::optional<const char *> FileNameStr = dwarf::toString(File.Name);
145 if (!FileNameStr) {
146 U.warn("cann't read string from line table.");
147 return;
148 }
149
150 // A null-terminated string containing the full or relative path name of a
151 // source file.
152 Section.emitString(File.Name.getForm(), *FileNameStr);
153
154 // An unsigned LEB128 number representing the directory index of a
155 // directory in the include_directories section.
156 encodeULEB128(File.DirIdx, Section.OS);
157 // An unsigned LEB128 number representing the (implementation-defined)
158 // time of last modification for the file, or 0 if not available.
159 encodeULEB128(File.ModTime, Section.OS);
160 // An unsigned LEB128 number representing the length in bytes of the file,
161 // or 0 if not available.
162 encodeULEB128(File.Length, Section.OS);
163 }
164 // The last entry is followed by a single null byte.
165 Section.emitIntVal(0, 1);
166 }
167
168 void
169 emitLineTablePrologueV5IncludeAndFileTable(const DWARFDebugLine::Prologue &P,
170 SectionDescriptor &Section) {
171 if (P.IncludeDirectories.empty()) {
172 // directory_entry_format_count(ubyte).
173 Section.emitIntVal(0, 1);
174 } else {
175 // directory_entry_format_count(ubyte).
176 Section.emitIntVal(1, 1);
177
178 // directory_entry_format (sequence of ULEB128 pairs).
179 encodeULEB128(dwarf::DW_LNCT_path, Section.OS);
180 encodeULEB128(P.IncludeDirectories[0].getForm(), Section.OS);
181 }
182
183 // directories_count (ULEB128).
184 encodeULEB128(P.IncludeDirectories.size(), Section.OS);
185 // directories (sequence of directory names).
186 for (auto Include : P.IncludeDirectories) {
187 std::optional<const char *> IncludeStr = dwarf::toString(Include);
188 if (!IncludeStr) {
189 U.warn("cann't read string from line table.");
190 return;
191 }
192
193 Section.emitString(Include.getForm(), *IncludeStr);
194 }
195
196 bool HasChecksums = P.ContentTypes.HasMD5;
197 bool HasInlineSources = P.ContentTypes.HasSource;
198
199 dwarf::Form FileNameForm = dwarf::DW_FORM_string;
200 dwarf::Form LLVMSourceForm = dwarf::DW_FORM_string;
201
202 if (P.FileNames.empty()) {
203 // file_name_entry_format_count (ubyte).
204 Section.emitIntVal(0, 1);
205 } else {
206 FileNameForm = P.FileNames[0].Name.getForm();
207 LLVMSourceForm = P.FileNames[0].Source.getForm();
208
209 // file_name_entry_format_count (ubyte).
210 Section.emitIntVal(
211 2 + (HasChecksums ? 1 : 0) + (HasInlineSources ? 1 : 0), 1);
212
213 // file_name_entry_format (sequence of ULEB128 pairs).
214 encodeULEB128(dwarf::DW_LNCT_path, Section.OS);
215 encodeULEB128(FileNameForm, Section.OS);
216
217 encodeULEB128(dwarf::DW_LNCT_directory_index, Section.OS);
218 encodeULEB128(dwarf::DW_FORM_data1, Section.OS);
219
220 if (HasChecksums) {
221 encodeULEB128(dwarf::DW_LNCT_MD5, Section.OS);
222 encodeULEB128(dwarf::DW_FORM_data16, Section.OS);
223 }
224
225 if (HasInlineSources) {
226 encodeULEB128(dwarf::DW_LNCT_LLVM_source, Section.OS);
227 encodeULEB128(LLVMSourceForm, Section.OS);
228 }
229 }
230
231 // file_names_count (ULEB128).
232 encodeULEB128(P.FileNames.size(), Section.OS);
233
234 // file_names (sequence of file name entries).
235 for (auto File : P.FileNames) {
236 std::optional<const char *> FileNameStr = dwarf::toString(File.Name);
237 if (!FileNameStr) {
238 U.warn("cann't read string from line table.");
239 return;
240 }
241
242 // A null-terminated string containing the full or relative path name of a
243 // source file.
244 Section.emitString(FileNameForm, *FileNameStr);
245 Section.emitIntVal(File.DirIdx, 1);
246
247 if (HasChecksums) {
248 assert((File.Checksum.size() == 16) &&
249 "checksum size is not equal to 16 bytes.");
250 Section.emitBinaryData(
251 StringRef(reinterpret_cast<const char *>(File.Checksum.data()),
252 File.Checksum.size()));
253 }
254
255 if (HasInlineSources) {
256 std::optional<const char *> FileSourceStr =
257 dwarf::toString(File.Source);
258 if (!FileSourceStr) {
259 U.warn("cann't read string from line table.");
260 return;
261 }
262
263 Section.emitString(LLVMSourceForm, *FileSourceStr);
264 }
265 }
266 }
267
268 void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P,
269 SectionDescriptor &Section) {
270 // minimum_instruction_length (ubyte).
271 Section.emitIntVal(P.MinInstLength, 1);
272 if (P.FormParams.Version >= 4) {
273 // maximum_operations_per_instruction (ubyte).
274 Section.emitIntVal(P.MaxOpsPerInst, 1);
275 }
276 // default_is_stmt (ubyte).
277 Section.emitIntVal(P.DefaultIsStmt, 1);
278 // line_base (sbyte).
279 Section.emitIntVal(P.LineBase, 1);
280 // line_range (ubyte).
281 Section.emitIntVal(P.LineRange, 1);
282 // opcode_base (ubyte).
283 Section.emitIntVal(P.OpcodeBase, 1);
284
285 // standard_opcode_lengths (array of ubyte).
286 for (auto Length : P.StandardOpcodeLengths)
287 Section.emitIntVal(Length, 1);
288
289 if (P.FormParams.Version < 5)
290 emitLineTablePrologueV2IncludeAndFileTable(P, Section);
291 else
292 emitLineTablePrologueV5IncludeAndFileTable(P, Section);
293 }
294
295 void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable,
296 SectionDescriptor &Section) {
297
298 MCDwarfLineTableParams Params;
299 Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
300 Params.DWARF2LineBase = LineTable.Prologue.LineBase;
301 Params.DWARF2LineRange = LineTable.Prologue.LineRange;
302
303 SmallString<128> EncodingBuffer;
304
305 if (LineTable.Rows.empty()) {
306 // We only have the dummy entry, dsymutil emits an entry with a 0
307 // address in that case.
308 MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
309 0, EncodingBuffer);
310 Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
311 return;
312 }
313
314 // Line table state machine fields
315 unsigned FileNum = 1;
316 unsigned LastLine = 1;
317 unsigned Column = 0;
318 unsigned IsStatement = 1;
319 unsigned Isa = 0;
320 uint64_t Address = -1ULL;
321
322 unsigned RowsSinceLastSequence = 0;
323
324 for (const DWARFDebugLine::Row &Row : LineTable.Rows) {
325 int64_t AddressDelta;
326 if (Address == -1ULL) {
327 Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);
328 encodeULEB128(Section.getFormParams().AddrSize + 1, Section.OS);
329 Section.emitIntVal(dwarf::DW_LNE_set_address, 1);
330 Section.emitIntVal(Row.Address.Address,
331 Section.getFormParams().AddrSize);
332 AddressDelta = 0;
333 } else {
335 (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;
336 }
337
338 // FIXME: code copied and transformed from
339 // MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share this
340 // code, but the current compatibility requirement with classic dsymutil
341 // makes it hard. Revisit that once this requirement is dropped.
342
343 if (FileNum != Row.File) {
344 FileNum = Row.File;
345 Section.emitIntVal(dwarf::DW_LNS_set_file, 1);
346 encodeULEB128(FileNum, Section.OS);
347 }
348 if (Column != Row.Column) {
349 Column = Row.Column;
350 Section.emitIntVal(dwarf::DW_LNS_set_column, 1);
351 encodeULEB128(Column, Section.OS);
352 }
353
354 // FIXME: We should handle the discriminator here, but dsymutil doesn't
355 // consider it, thus ignore it for now.
356
357 if (Isa != Row.Isa) {
358 Isa = Row.Isa;
359 Section.emitIntVal(dwarf::DW_LNS_set_isa, 1);
360 encodeULEB128(Isa, Section.OS);
361 }
362 if (IsStatement != Row.IsStmt) {
363 IsStatement = Row.IsStmt;
364 Section.emitIntVal(dwarf::DW_LNS_negate_stmt, 1);
365 }
366 if (Row.BasicBlock)
367 Section.emitIntVal(dwarf::DW_LNS_set_basic_block, 1);
368
369 if (Row.PrologueEnd)
370 Section.emitIntVal(dwarf::DW_LNS_set_prologue_end, 1);
371
372 if (Row.EpilogueBegin)
373 Section.emitIntVal(dwarf::DW_LNS_set_epilogue_begin, 1);
374
375 int64_t LineDelta = int64_t(Row.Line) - LastLine;
376 if (!Row.EndSequence) {
377 MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,
378 EncodingBuffer);
379 Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
380 EncodingBuffer.resize(0);
381 Address = Row.Address.Address;
382 LastLine = Row.Line;
383 RowsSinceLastSequence++;
384 } else {
385 if (LineDelta) {
386 Section.emitIntVal(dwarf::DW_LNS_advance_line, 1);
387 encodeSLEB128(LineDelta, Section.OS);
388 }
389 if (AddressDelta) {
390 Section.emitIntVal(dwarf::DW_LNS_advance_pc, 1);
392 }
393 MCDwarfLineAddr::encode(*MC, Params,
394 std::numeric_limits<int64_t>::max(), 0,
395 EncodingBuffer);
396 Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
397 EncodingBuffer.resize(0);
398 Address = -1ULL;
399 LastLine = FileNum = IsStatement = 1;
400 RowsSinceLastSequence = Column = Isa = 0;
401 }
402 }
403
404 if (RowsSinceLastSequence) {
405 MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
406 0, EncodingBuffer);
407 Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
408 EncodingBuffer.resize(0);
409 }
410 }
411
412 Triple TheTriple;
413 DwarfUnit &U;
414
415 std::unique_ptr<MCRegisterInfo> MRI;
416 std::unique_ptr<MCAsmInfo> MAI;
417 std::unique_ptr<MCContext> MC;
418 std::unique_ptr<MCSubtargetInfo> MSTI;
419};
420
421} // end of namespace parallel
422} // end of namespace dwarf_linker
423} // end of namespace llvm
424
425#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Context object for machine code objects.
Definition: MCContext.h:76
static void encode(MCContext &Context, MCDwarfLineTableParams Params, int64_t LineDelta, uint64_t AddrDelta, SmallVectorImpl< char > &OS)
Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
Definition: MCDwarf.cpp:683
Target - Wrapper for Target specific information.
MCSubtargetInfo * createMCSubtargetInfo(StringRef TheTriple, StringRef CPU, StringRef Features) const
createMCSubtargetInfo - Create a MCSubtargetInfo implementation.
MCRegisterInfo * createMCRegInfo(StringRef TT) const
createMCRegInfo - Create a MCRegisterInfo implementation.
MCAsmInfo * createMCAsmInfo(const MCRegisterInfo &MRI, StringRef TheTriple, const MCTargetOptions &Options) const
createMCAsmInfo - Create a MCAsmInfo implementation for the specified target triple.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
const std::string & getTriple() const
Definition: Triple.h:426
This class emits specified line table into the .debug_line section.
Error emit(const DWARFDebugLine::LineTable &LineTable)
DebugLineSectionEmitter(const Triple &TheTriple, DwarfUnit &U)
Base class for all Dwarf units(Compile unit/Type table unit).
SectionDescriptor & getOrCreateSectionDescriptor(DebugSectionKind SectionKind)
Returns descriptor for the specified section of SectionKind.
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:150
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
MCTargetOptions InitMCTargetOptionsFromFlags()
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Length
Definition: DWP.cpp:456
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a SLEB128 value to an output stream.
Definition: LEB128.h:23
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition: LEB128.h:80
static const Target * lookupTarget(StringRef Triple, std::string &Error)
lookupTarget - Lookup a target based on a target triple.
uint8_t getDwarfOffsetByteSize() const
The size of a reference is determined by the DWARF 32/64-bit format.
Definition: Dwarf.h:780
dwarf::FormParams getFormParams() const
Returns FormParams used by section.
Definition: DWARFLinker.h:107
This structure is used to keep data of the concrete section.
raw_svector_ostream OS
Stream which stores data to the Contents.
void emitUnitLength(uint64_t Length)
Emit unit length into the current section contents.
void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val)
Write specified Value of AttrForm to the PatchOffset.