xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp (revision a85404906bc8f402318524b4ccd196712fc09fbd)
1  //===- llvm/CodeGen/DwarfFile.cpp - Dwarf Debug Framework -----------------===//
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  #include "DwarfFile.h"
10  #include "DwarfCompileUnit.h"
11  #include "DwarfDebug.h"
12  #include "DwarfUnit.h"
13  #include "llvm/CodeGen/AsmPrinter.h"
14  #include "llvm/IR/DebugInfoMetadata.h"
15  #include "llvm/IR/Metadata.h"
16  #include "llvm/MC/MCStreamer.h"
17  #include <algorithm>
18  #include <cstdint>
19  
20  using namespace llvm;
21  
22  DwarfFile::DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA)
23      : Asm(AP), Abbrevs(AbbrevAllocator), StrPool(DA, *Asm, Pref) {}
24  
25  void DwarfFile::addUnit(std::unique_ptr<DwarfCompileUnit> U) {
26    CUs.push_back(std::move(U));
27  }
28  
29  // Emit the various dwarf units to the unit section USection with
30  // the abbreviations going into ASection.
31  void DwarfFile::emitUnits(bool UseOffsets) {
32    for (const auto &TheU : CUs)
33      emitUnit(TheU.get(), UseOffsets);
34  }
35  
36  void DwarfFile::emitUnit(DwarfUnit *TheU, bool UseOffsets) {
37    if (TheU->getCUNode()->isDebugDirectivesOnly())
38      return;
39  
40    MCSection *S = TheU->getSection();
41  
42    if (!S)
43      return;
44  
45    // Skip CUs that ended up not being needed (split CUs that were abandoned
46    // because they added no information beyond the non-split CU)
47    if (llvm::empty(TheU->getUnitDie().values()))
48      return;
49  
50    Asm->OutStreamer->SwitchSection(S);
51    TheU->emitHeader(UseOffsets);
52    Asm->emitDwarfDIE(TheU->getUnitDie());
53  
54    if (MCSymbol *EndLabel = TheU->getEndLabel())
55      Asm->OutStreamer->emitLabel(EndLabel);
56  }
57  
58  // Compute the size and offset for each DIE.
59  void DwarfFile::computeSizeAndOffsets() {
60    // Offset from the first CU in the debug info section is 0 initially.
61    uint64_t SecOffset = 0;
62  
63    // Iterate over each compile unit and set the size and offsets for each
64    // DIE within each compile unit. All offsets are CU relative.
65    for (const auto &TheU : CUs) {
66      if (TheU->getCUNode()->isDebugDirectivesOnly())
67        continue;
68  
69      // Skip CUs that ended up not being needed (split CUs that were abandoned
70      // because they added no information beyond the non-split CU)
71      if (llvm::empty(TheU->getUnitDie().values()))
72        return;
73  
74      TheU->setDebugSectionOffset(SecOffset);
75      SecOffset += computeSizeAndOffsetsForUnit(TheU.get());
76    }
77    if (SecOffset > UINT32_MAX && !Asm->isDwarf64())
78      report_fatal_error("The generated debug information is too large "
79                         "for the 32-bit DWARF format.");
80  }
81  
82  unsigned DwarfFile::computeSizeAndOffsetsForUnit(DwarfUnit *TheU) {
83    // CU-relative offset is reset to 0 here.
84    unsigned Offset = Asm->getUnitLengthFieldByteSize() + // Length of Unit Info
85                      TheU->getHeaderSize();              // Unit-specific headers
86  
87    // The return value here is CU-relative, after laying out
88    // all of the CU DIE.
89    return computeSizeAndOffset(TheU->getUnitDie(), Offset);
90  }
91  
92  // Compute the size and offset of a DIE. The offset is relative to start of the
93  // CU. It returns the offset after laying out the DIE.
94  unsigned DwarfFile::computeSizeAndOffset(DIE &Die, unsigned Offset) {
95    return Die.computeOffsetsAndAbbrevs(Asm, Abbrevs, Offset);
96  }
97  
98  void DwarfFile::emitAbbrevs(MCSection *Section) { Abbrevs.Emit(Asm, Section); }
99  
100  // Emit strings into a string section.
101  void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection,
102                              bool UseRelativeOffsets) {
103    StrPool.emit(*Asm, StrSection, OffsetSection, UseRelativeOffsets);
104  }
105  
106  bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) {
107    auto &ScopeVars = ScopeVariables[LS];
108    const DILocalVariable *DV = Var->getVariable();
109    if (unsigned ArgNum = DV->getArg()) {
110      auto Cached = ScopeVars.Args.find(ArgNum);
111      if (Cached == ScopeVars.Args.end())
112        ScopeVars.Args[ArgNum] = Var;
113      else {
114        Cached->second->addMMIEntry(*Var);
115        return false;
116      }
117    } else {
118      ScopeVars.Locals.push_back(Var);
119    }
120    return true;
121  }
122  
123  void DwarfFile::addScopeLabel(LexicalScope *LS, DbgLabel *Label) {
124    SmallVectorImpl<DbgLabel *> &Labels = ScopeLabels[LS];
125    Labels.push_back(Label);
126  }
127  
128  std::pair<uint32_t, RangeSpanList *>
129  DwarfFile::addRange(const DwarfCompileUnit &CU, SmallVector<RangeSpan, 2> R) {
130    CURangeLists.push_back(
131        RangeSpanList{Asm->createTempSymbol("debug_ranges"), &CU, std::move(R)});
132    return std::make_pair(CURangeLists.size() - 1, &CURangeLists.back());
133  }
134