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