xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DebugLineSectionEmitter.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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"
13 #include "llvm/DWARFLinker/AddressesMap.h"
14 #include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
15 #include "llvm/DebugInfo/DWARF/DWARFObject.h"
16 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
17 #include "llvm/MC/TargetRegistry.h"
18 
19 namespace llvm {
20 namespace dwarf_linker {
21 namespace parallel {
22 
23 /// This class emits specified line table into the .debug_line section.
24 class DebugLineSectionEmitter {
25 public:
26   DebugLineSectionEmitter(const Triple &TheTriple, DwarfUnit &U)
27       : TheTriple(TheTriple), U(U) {}
28 
29   Error emit(const DWARFDebugLine::LineTable &LineTable) {
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 =
38         U.getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);
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 -
53                OutSection.getFormParams().getDwarfOffsetByteSize() <
54            OffsetAfterUnitLength);
55     OutSection.apply(OffsetAfterUnitLength -
56                          OutSection.getFormParams().getDwarfOffsetByteSize(),
57                      dwarf::DW_FORM_sec_offset,
58                      OffsetAfterEnd - OffsetAfterUnitLength);
59 
60     return Error::success();
61   }
62 
63 private:
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 
82     MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
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 Discriminator = 0;
319     unsigned IsStatement = 1;
320     unsigned Isa = 0;
321     uint64_t Address = -1ULL;
322 
323     unsigned RowsSinceLastSequence = 0;
324 
325     for (const DWARFDebugLine::Row &Row : LineTable.Rows) {
326       int64_t AddressDelta;
327       if (Address == -1ULL) {
328         Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);
329         encodeULEB128(Section.getFormParams().AddrSize + 1, Section.OS);
330         Section.emitIntVal(dwarf::DW_LNE_set_address, 1);
331         Section.emitIntVal(Row.Address.Address,
332                            Section.getFormParams().AddrSize);
333         AddressDelta = 0;
334       } else {
335         AddressDelta =
336             (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;
337       }
338 
339       // FIXME: code copied and transformed from
340       // MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share this
341       // code, but the current compatibility requirement with classic dsymutil
342       // makes it hard. Revisit that once this requirement is dropped.
343 
344       if (FileNum != Row.File) {
345         FileNum = Row.File;
346         Section.emitIntVal(dwarf::DW_LNS_set_file, 1);
347         encodeULEB128(FileNum, Section.OS);
348       }
349       if (Column != Row.Column) {
350         Column = Row.Column;
351         Section.emitIntVal(dwarf::DW_LNS_set_column, 1);
352         encodeULEB128(Column, Section.OS);
353       }
354       if (Discriminator != Row.Discriminator && MC->getDwarfVersion() >= 4) {
355         Discriminator = Row.Discriminator;
356         unsigned Size = getULEB128Size(Discriminator);
357         Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);
358         encodeULEB128(Size + 1, Section.OS);
359         Section.emitIntVal(dwarf::DW_LNE_set_discriminator, 1);
360         encodeULEB128(Discriminator, Section.OS);
361       }
362       Discriminator = 0;
363 
364       if (Isa != Row.Isa) {
365         Isa = Row.Isa;
366         Section.emitIntVal(dwarf::DW_LNS_set_isa, 1);
367         encodeULEB128(Isa, Section.OS);
368       }
369       if (IsStatement != Row.IsStmt) {
370         IsStatement = Row.IsStmt;
371         Section.emitIntVal(dwarf::DW_LNS_negate_stmt, 1);
372       }
373       if (Row.BasicBlock)
374         Section.emitIntVal(dwarf::DW_LNS_set_basic_block, 1);
375 
376       if (Row.PrologueEnd)
377         Section.emitIntVal(dwarf::DW_LNS_set_prologue_end, 1);
378 
379       if (Row.EpilogueBegin)
380         Section.emitIntVal(dwarf::DW_LNS_set_epilogue_begin, 1);
381 
382       int64_t LineDelta = int64_t(Row.Line) - LastLine;
383       if (!Row.EndSequence) {
384         MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,
385                                 EncodingBuffer);
386         Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
387         EncodingBuffer.resize(0);
388         Address = Row.Address.Address;
389         LastLine = Row.Line;
390         RowsSinceLastSequence++;
391       } else {
392         if (LineDelta) {
393           Section.emitIntVal(dwarf::DW_LNS_advance_line, 1);
394           encodeSLEB128(LineDelta, Section.OS);
395         }
396         if (AddressDelta) {
397           Section.emitIntVal(dwarf::DW_LNS_advance_pc, 1);
398           encodeULEB128(AddressDelta, Section.OS);
399         }
400         MCDwarfLineAddr::encode(*MC, Params,
401                                 std::numeric_limits<int64_t>::max(), 0,
402                                 EncodingBuffer);
403         Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
404         EncodingBuffer.resize(0);
405         Address = -1ULL;
406         LastLine = FileNum = IsStatement = 1;
407         RowsSinceLastSequence = Column = Discriminator = Isa = 0;
408       }
409     }
410 
411     if (RowsSinceLastSequence) {
412       MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
413                               0, EncodingBuffer);
414       Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
415       EncodingBuffer.resize(0);
416     }
417   }
418 
419   Triple TheTriple;
420   DwarfUnit &U;
421 
422   std::unique_ptr<MCRegisterInfo> MRI;
423   std::unique_ptr<MCAsmInfo> MAI;
424   std::unique_ptr<MCContext> MC;
425   std::unique_ptr<MCSubtargetInfo> MSTI;
426 };
427 
428 } // end of namespace parallel
429 } // end of namespace dwarf_linker
430 } // end of namespace llvm
431 
432 #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H
433