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