xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DebugLineSectionEmitter.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
DebugLineSectionEmitter(const Triple & TheTriple,DwarfUnit & U)26    DebugLineSectionEmitter(const Triple &TheTriple, DwarfUnit &U)
27        : TheTriple(TheTriple), U(U) {}
28  
emit(const DWARFDebugLine::LineTable & LineTable)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:
init(Triple TheTriple)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  
emitLineTablePrologue(const DWARFDebugLine::Prologue & P,SectionDescriptor & Section)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
emitLineTablePrologueV2IncludeAndFileTable(const DWARFDebugLine::Prologue & P,SectionDescriptor & Section)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
emitLineTablePrologueV5IncludeAndFileTable(const DWARFDebugLine::Prologue & P,SectionDescriptor & Section)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  
emitLineTableProloguePayload(const DWARFDebugLine::Prologue & P,SectionDescriptor & Section)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  
emitLineTableRows(const DWARFDebugLine::LineTable & LineTable,SectionDescriptor & Section)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