xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DebugLineSectionEmitter.h (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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     if (P.FileNames.empty()) {
197       // file_name_entry_format_count (ubyte).
198       Section.emitIntVal(0, 1);
199     } else {
200       // file_name_entry_format_count (ubyte).
201       Section.emitIntVal(2 + (P.ContentTypes.HasMD5 ? 1 : 0), 1);
202 
203       // file_name_entry_format (sequence of ULEB128 pairs).
204       encodeULEB128(dwarf::DW_LNCT_path, Section.OS);
205       encodeULEB128(P.FileNames[0].Name.getForm(), Section.OS);
206 
207       encodeULEB128(dwarf::DW_LNCT_directory_index, Section.OS);
208       encodeULEB128(dwarf::DW_FORM_data1, Section.OS);
209 
210       if (P.ContentTypes.HasMD5) {
211         encodeULEB128(dwarf::DW_LNCT_MD5, Section.OS);
212         encodeULEB128(dwarf::DW_FORM_data16, Section.OS);
213       }
214     }
215 
216     // file_names_count (ULEB128).
217     encodeULEB128(P.FileNames.size(), Section.OS);
218 
219     // file_names (sequence of file name entries).
220     for (auto File : P.FileNames) {
221       std::optional<const char *> FileNameStr = dwarf::toString(File.Name);
222       if (!FileNameStr) {
223         U.warn("cann't read string from line table.");
224         return;
225       }
226 
227       // A null-terminated string containing the full or relative path name of a
228       // source file.
229       Section.emitString(File.Name.getForm(), *FileNameStr);
230       Section.emitIntVal(File.DirIdx, 1);
231 
232       if (P.ContentTypes.HasMD5) {
233         Section.emitBinaryData(
234             StringRef(reinterpret_cast<const char *>(File.Checksum.data()),
235                       File.Checksum.size()));
236       }
237     }
238   }
239 
240   void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P,
241                                     SectionDescriptor &Section) {
242     // minimum_instruction_length (ubyte).
243     Section.emitIntVal(P.MinInstLength, 1);
244     if (P.FormParams.Version >= 4) {
245       // maximum_operations_per_instruction (ubyte).
246       Section.emitIntVal(P.MaxOpsPerInst, 1);
247     }
248     // default_is_stmt (ubyte).
249     Section.emitIntVal(P.DefaultIsStmt, 1);
250     // line_base (sbyte).
251     Section.emitIntVal(P.LineBase, 1);
252     // line_range (ubyte).
253     Section.emitIntVal(P.LineRange, 1);
254     // opcode_base (ubyte).
255     Section.emitIntVal(P.OpcodeBase, 1);
256 
257     // standard_opcode_lengths (array of ubyte).
258     for (auto Length : P.StandardOpcodeLengths)
259       Section.emitIntVal(Length, 1);
260 
261     if (P.FormParams.Version < 5)
262       emitLineTablePrologueV2IncludeAndFileTable(P, Section);
263     else
264       emitLineTablePrologueV5IncludeAndFileTable(P, Section);
265   }
266 
267   void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable,
268                          SectionDescriptor &Section) {
269 
270     MCDwarfLineTableParams Params;
271     Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
272     Params.DWARF2LineBase = LineTable.Prologue.LineBase;
273     Params.DWARF2LineRange = LineTable.Prologue.LineRange;
274 
275     SmallString<128> EncodingBuffer;
276 
277     if (LineTable.Rows.empty()) {
278       // We only have the dummy entry, dsymutil emits an entry with a 0
279       // address in that case.
280       MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
281                               0, EncodingBuffer);
282       Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
283       return;
284     }
285 
286     // Line table state machine fields
287     unsigned FileNum = 1;
288     unsigned LastLine = 1;
289     unsigned Column = 0;
290     unsigned IsStatement = 1;
291     unsigned Isa = 0;
292     uint64_t Address = -1ULL;
293 
294     unsigned RowsSinceLastSequence = 0;
295 
296     for (const DWARFDebugLine::Row &Row : LineTable.Rows) {
297       int64_t AddressDelta;
298       if (Address == -1ULL) {
299         Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);
300         encodeULEB128(Section.getFormParams().AddrSize + 1, Section.OS);
301         Section.emitIntVal(dwarf::DW_LNE_set_address, 1);
302         Section.emitIntVal(Row.Address.Address,
303                            Section.getFormParams().AddrSize);
304         AddressDelta = 0;
305       } else {
306         AddressDelta =
307             (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;
308       }
309 
310       // FIXME: code copied and transformed from
311       // MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share this
312       // code, but the current compatibility requirement with classic dsymutil
313       // makes it hard. Revisit that once this requirement is dropped.
314 
315       if (FileNum != Row.File) {
316         FileNum = Row.File;
317         Section.emitIntVal(dwarf::DW_LNS_set_file, 1);
318         encodeULEB128(FileNum, Section.OS);
319       }
320       if (Column != Row.Column) {
321         Column = Row.Column;
322         Section.emitIntVal(dwarf::DW_LNS_set_column, 1);
323         encodeULEB128(Column, Section.OS);
324       }
325 
326       // FIXME: We should handle the discriminator here, but dsymutil doesn't
327       // consider it, thus ignore it for now.
328 
329       if (Isa != Row.Isa) {
330         Isa = Row.Isa;
331         Section.emitIntVal(dwarf::DW_LNS_set_isa, 1);
332         encodeULEB128(Isa, Section.OS);
333       }
334       if (IsStatement != Row.IsStmt) {
335         IsStatement = Row.IsStmt;
336         Section.emitIntVal(dwarf::DW_LNS_negate_stmt, 1);
337       }
338       if (Row.BasicBlock)
339         Section.emitIntVal(dwarf::DW_LNS_set_basic_block, 1);
340 
341       if (Row.PrologueEnd)
342         Section.emitIntVal(dwarf::DW_LNS_set_prologue_end, 1);
343 
344       if (Row.EpilogueBegin)
345         Section.emitIntVal(dwarf::DW_LNS_set_epilogue_begin, 1);
346 
347       int64_t LineDelta = int64_t(Row.Line) - LastLine;
348       if (!Row.EndSequence) {
349         MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,
350                                 EncodingBuffer);
351         Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
352         EncodingBuffer.resize(0);
353         Address = Row.Address.Address;
354         LastLine = Row.Line;
355         RowsSinceLastSequence++;
356       } else {
357         if (LineDelta) {
358           Section.emitIntVal(dwarf::DW_LNS_advance_line, 1);
359           encodeSLEB128(LineDelta, Section.OS);
360         }
361         if (AddressDelta) {
362           Section.emitIntVal(dwarf::DW_LNS_advance_pc, 1);
363           encodeULEB128(AddressDelta, Section.OS);
364         }
365         MCDwarfLineAddr::encode(*MC, Params,
366                                 std::numeric_limits<int64_t>::max(), 0,
367                                 EncodingBuffer);
368         Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
369         EncodingBuffer.resize(0);
370         Address = -1ULL;
371         LastLine = FileNum = IsStatement = 1;
372         RowsSinceLastSequence = Column = Isa = 0;
373       }
374     }
375 
376     if (RowsSinceLastSequence) {
377       MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),
378                               0, EncodingBuffer);
379       Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());
380       EncodingBuffer.resize(0);
381     }
382   }
383 
384   Triple TheTriple;
385   DwarfUnit &U;
386 
387   std::unique_ptr<MCRegisterInfo> MRI;
388   std::unique_ptr<MCAsmInfo> MAI;
389   std::unique_ptr<MCContext> MC;
390   std::unique_ptr<MCSubtargetInfo> MSTI;
391 };
392 
393 } // end of namespace parallel
394 } // end of namespace dwarf_linker
395 } // end of namespace llvm
396 
397 #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H
398