1//===- DWARFLinkerCompileUnit.cpp -----------------------------------------===//
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 "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
10#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
11
12namespace llvm {
13
14/// Check if the DIE at \p Idx is in the scope of a function.
15static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
16  while (Idx) {
17    if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram)
18      return true;
19    Idx = U.getInfo(Idx).ParentIdx;
20  }
21  return false;
22}
23
24uint16_t CompileUnit::getLanguage() {
25  if (!Language) {
26    DWARFDie CU = getOrigUnit().getUnitDIE();
27    Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0);
28  }
29  return Language;
30}
31
32StringRef CompileUnit::getSysRoot() {
33  if (SysRoot.empty()) {
34    DWARFDie CU = getOrigUnit().getUnitDIE();
35    SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str();
36  }
37  return SysRoot;
38}
39
40void CompileUnit::markEverythingAsKept() {
41  unsigned Idx = 0;
42
43  setHasInterestingContent();
44
45  for (auto &I : Info) {
46    // Mark everything that wasn't explicit marked for pruning.
47    I.Keep = !I.Prune;
48    auto DIE = OrigUnit.getDIEAtIndex(Idx++);
49
50    // Try to guess which DIEs must go to the accelerator tables. We do that
51    // just for variables, because functions will be handled depending on
52    // whether they carry a DW_AT_low_pc attribute or not.
53    if (DIE.getTag() != dwarf::DW_TAG_variable &&
54        DIE.getTag() != dwarf::DW_TAG_constant)
55      continue;
56
57    Optional<DWARFFormValue> Value;
58    if (!(Value = DIE.find(dwarf::DW_AT_location))) {
59      if ((Value = DIE.find(dwarf::DW_AT_const_value)) &&
60          !inFunctionScope(*this, I.ParentIdx))
61        I.InDebugMap = true;
62      continue;
63    }
64    if (auto Block = Value->getAsBlock()) {
65      if (Block->size() > OrigUnit.getAddressByteSize() &&
66          (*Block)[0] == dwarf::DW_OP_addr)
67        I.InDebugMap = true;
68    }
69  }
70}
71
72uint64_t CompileUnit::computeNextUnitOffset() {
73  NextUnitOffset = StartOffset;
74  if (NewUnit) {
75    NextUnitOffset += 11 /* Header size */;
76    NextUnitOffset += NewUnit->getUnitDie().getSize();
77  }
78  return NextUnitOffset;
79}
80
81/// Keep track of a forward cross-cu reference from this unit
82/// to \p Die that lives in \p RefUnit.
83void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
84                                       DeclContext *Ctxt, PatchLocation Attr) {
85  ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
86}
87
88void CompileUnit::fixupForwardReferences() {
89  for (const auto &Ref : ForwardDIEReferences) {
90    DIE *RefDie;
91    const CompileUnit *RefUnit;
92    PatchLocation Attr;
93    DeclContext *Ctxt;
94    std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
95    if (Ctxt && Ctxt->getCanonicalDIEOffset())
96      Attr.set(Ctxt->getCanonicalDIEOffset());
97    else
98      Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
99  }
100}
101
102void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
103  Labels.insert({LabelLowPc, PcOffset});
104}
105
106void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
107                                   int64_t PcOffset) {
108  //  Don't add empty ranges to the interval map.  They are a problem because
109  //  the interval map expects half open intervals. This is safe because they
110  //  are empty anyway.
111  if (FuncHighPc != FuncLowPc)
112    Ranges.insert(FuncLowPc, FuncHighPc, PcOffset);
113  this->LowPc = std::min(LowPc, FuncLowPc + PcOffset);
114  this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
115}
116
117void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
118  if (Die.getTag() != dwarf::DW_TAG_compile_unit)
119    RangeAttributes.push_back(Attr);
120  else
121    UnitRangeAttribute = Attr;
122}
123
124void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
125  LocationAttributes.emplace_back(Attr, PcOffset);
126}
127
128void CompileUnit::addNamespaceAccelerator(const DIE *Die,
129                                          DwarfStringPoolEntryRef Name) {
130  Namespaces.emplace_back(Name, Die);
131}
132
133void CompileUnit::addObjCAccelerator(const DIE *Die,
134                                     DwarfStringPoolEntryRef Name,
135                                     bool SkipPubSection) {
136  ObjC.emplace_back(Name, Die, SkipPubSection);
137}
138
139void CompileUnit::addNameAccelerator(const DIE *Die,
140                                     DwarfStringPoolEntryRef Name,
141                                     bool SkipPubSection) {
142  Pubnames.emplace_back(Name, Die, SkipPubSection);
143}
144
145void CompileUnit::addTypeAccelerator(const DIE *Die,
146                                     DwarfStringPoolEntryRef Name,
147                                     bool ObjcClassImplementation,
148                                     uint32_t QualifiedNameHash) {
149  Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);
150}
151
152} // namespace llvm
153