11cf11a4cSAlexey Lapshin //===- DWARFLinkerCompileUnit.cpp -----------------------------------------===//
21cf11a4cSAlexey Lapshin //
31cf11a4cSAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41cf11a4cSAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information.
51cf11a4cSAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61cf11a4cSAlexey Lapshin //
71cf11a4cSAlexey Lapshin //===----------------------------------------------------------------------===//
81cf11a4cSAlexey Lapshin 
91cf11a4cSAlexey Lapshin #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
101cf11a4cSAlexey Lapshin #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
111cf11a4cSAlexey Lapshin 
121cf11a4cSAlexey Lapshin namespace llvm {
131cf11a4cSAlexey Lapshin 
141cf11a4cSAlexey Lapshin /// Check if the DIE at \p Idx is in the scope of a function.
inFunctionScope(CompileUnit & U,unsigned Idx)151cf11a4cSAlexey Lapshin static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
161cf11a4cSAlexey Lapshin   while (Idx) {
171cf11a4cSAlexey Lapshin     if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram)
181cf11a4cSAlexey Lapshin       return true;
191cf11a4cSAlexey Lapshin     Idx = U.getInfo(Idx).ParentIdx;
201cf11a4cSAlexey Lapshin   }
211cf11a4cSAlexey Lapshin   return false;
221cf11a4cSAlexey Lapshin }
231cf11a4cSAlexey Lapshin 
getLanguage()241cf11a4cSAlexey Lapshin uint16_t CompileUnit::getLanguage() {
251cf11a4cSAlexey Lapshin   if (!Language) {
261cf11a4cSAlexey Lapshin     DWARFDie CU = getOrigUnit().getUnitDIE();
271cf11a4cSAlexey Lapshin     Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0);
281cf11a4cSAlexey Lapshin   }
291cf11a4cSAlexey Lapshin   return Language;
301cf11a4cSAlexey Lapshin }
311cf11a4cSAlexey Lapshin 
getSysRoot()3222cb36c8SAdrian Prantl StringRef CompileUnit::getSysRoot() {
3322cb36c8SAdrian Prantl   if (SysRoot.empty()) {
3422cb36c8SAdrian Prantl     DWARFDie CU = getOrigUnit().getUnitDIE();
3522cb36c8SAdrian Prantl     SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str();
3622cb36c8SAdrian Prantl   }
3722cb36c8SAdrian Prantl   return SysRoot;
3822cb36c8SAdrian Prantl }
3922cb36c8SAdrian Prantl 
markEverythingAsKept()401cf11a4cSAlexey Lapshin void CompileUnit::markEverythingAsKept() {
411cf11a4cSAlexey Lapshin   unsigned Idx = 0;
421cf11a4cSAlexey Lapshin 
431cf11a4cSAlexey Lapshin   for (auto &I : Info) {
441cf11a4cSAlexey Lapshin     // Mark everything that wasn't explicit marked for pruning.
451cf11a4cSAlexey Lapshin     I.Keep = !I.Prune;
461cf11a4cSAlexey Lapshin     auto DIE = OrigUnit.getDIEAtIndex(Idx++);
471cf11a4cSAlexey Lapshin 
481cf11a4cSAlexey Lapshin     // Try to guess which DIEs must go to the accelerator tables. We do that
491cf11a4cSAlexey Lapshin     // just for variables, because functions will be handled depending on
501cf11a4cSAlexey Lapshin     // whether they carry a DW_AT_low_pc attribute or not.
511cf11a4cSAlexey Lapshin     if (DIE.getTag() != dwarf::DW_TAG_variable &&
521cf11a4cSAlexey Lapshin         DIE.getTag() != dwarf::DW_TAG_constant)
531cf11a4cSAlexey Lapshin       continue;
541cf11a4cSAlexey Lapshin 
551cf11a4cSAlexey Lapshin     Optional<DWARFFormValue> Value;
561cf11a4cSAlexey Lapshin     if (!(Value = DIE.find(dwarf::DW_AT_location))) {
571cf11a4cSAlexey Lapshin       if ((Value = DIE.find(dwarf::DW_AT_const_value)) &&
581cf11a4cSAlexey Lapshin           !inFunctionScope(*this, I.ParentIdx))
591cf11a4cSAlexey Lapshin         I.InDebugMap = true;
601cf11a4cSAlexey Lapshin       continue;
611cf11a4cSAlexey Lapshin     }
621cf11a4cSAlexey Lapshin     if (auto Block = Value->getAsBlock()) {
631cf11a4cSAlexey Lapshin       if (Block->size() > OrigUnit.getAddressByteSize() &&
641cf11a4cSAlexey Lapshin           (*Block)[0] == dwarf::DW_OP_addr)
651cf11a4cSAlexey Lapshin         I.InDebugMap = true;
661cf11a4cSAlexey Lapshin     }
671cf11a4cSAlexey Lapshin   }
681cf11a4cSAlexey Lapshin }
691cf11a4cSAlexey Lapshin 
computeNextUnitOffset(uint16_t DwarfVersion)70f1d5cbbdSJonas Devlieghere uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {
711cf11a4cSAlexey Lapshin   NextUnitOffset = StartOffset;
721cf11a4cSAlexey Lapshin   if (NewUnit) {
73f1d5cbbdSJonas Devlieghere     NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size
741cf11a4cSAlexey Lapshin     NextUnitOffset += NewUnit->getUnitDie().getSize();
751cf11a4cSAlexey Lapshin   }
761cf11a4cSAlexey Lapshin   return NextUnitOffset;
771cf11a4cSAlexey Lapshin }
781cf11a4cSAlexey Lapshin 
791cf11a4cSAlexey Lapshin /// Keep track of a forward cross-cu reference from this unit
801cf11a4cSAlexey Lapshin /// to \p Die that lives in \p RefUnit.
noteForwardReference(DIE * Die,const CompileUnit * RefUnit,DeclContext * Ctxt,PatchLocation Attr)811cf11a4cSAlexey Lapshin void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
821cf11a4cSAlexey Lapshin                                        DeclContext *Ctxt, PatchLocation Attr) {
831cf11a4cSAlexey Lapshin   ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
841cf11a4cSAlexey Lapshin }
851cf11a4cSAlexey Lapshin 
fixupForwardReferences()861cf11a4cSAlexey Lapshin void CompileUnit::fixupForwardReferences() {
871cf11a4cSAlexey Lapshin   for (const auto &Ref : ForwardDIEReferences) {
881cf11a4cSAlexey Lapshin     DIE *RefDie;
891cf11a4cSAlexey Lapshin     const CompileUnit *RefUnit;
901cf11a4cSAlexey Lapshin     PatchLocation Attr;
911cf11a4cSAlexey Lapshin     DeclContext *Ctxt;
921cf11a4cSAlexey Lapshin     std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
932b747241SAlexey Lapshin     if (Ctxt && Ctxt->hasCanonicalDIE()) {
942b747241SAlexey Lapshin       assert(Ctxt->getCanonicalDIEOffset() &&
952b747241SAlexey Lapshin              "Canonical die offset is not set");
961cf11a4cSAlexey Lapshin       Attr.set(Ctxt->getCanonicalDIEOffset());
972b747241SAlexey Lapshin     } else
981cf11a4cSAlexey Lapshin       Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
991cf11a4cSAlexey Lapshin   }
1001cf11a4cSAlexey Lapshin }
1011cf11a4cSAlexey Lapshin 
addLabelLowPc(uint64_t LabelLowPc,int64_t PcOffset)1021cf11a4cSAlexey Lapshin void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
1031cf11a4cSAlexey Lapshin   Labels.insert({LabelLowPc, PcOffset});
1041cf11a4cSAlexey Lapshin }
1051cf11a4cSAlexey Lapshin 
addFunctionRange(uint64_t FuncLowPc,uint64_t FuncHighPc,int64_t PcOffset)1061cf11a4cSAlexey Lapshin void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
1071cf11a4cSAlexey Lapshin                                    int64_t PcOffset) {
108*8bb4451aSAlexey Lapshin   Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset);
1091cf11a4cSAlexey Lapshin   this->LowPc = std::min(LowPc, FuncLowPc + PcOffset);
1101cf11a4cSAlexey Lapshin   this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
1111cf11a4cSAlexey Lapshin }
1121cf11a4cSAlexey Lapshin 
noteRangeAttribute(const DIE & Die,PatchLocation Attr)1131cf11a4cSAlexey Lapshin void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
1141cf11a4cSAlexey Lapshin   if (Die.getTag() != dwarf::DW_TAG_compile_unit)
1151cf11a4cSAlexey Lapshin     RangeAttributes.push_back(Attr);
1161cf11a4cSAlexey Lapshin   else
1171cf11a4cSAlexey Lapshin     UnitRangeAttribute = Attr;
1181cf11a4cSAlexey Lapshin }
1191cf11a4cSAlexey Lapshin 
noteLocationAttribute(PatchLocation Attr,int64_t PcOffset)1201cf11a4cSAlexey Lapshin void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
1211cf11a4cSAlexey Lapshin   LocationAttributes.emplace_back(Attr, PcOffset);
1221cf11a4cSAlexey Lapshin }
1231cf11a4cSAlexey Lapshin 
addNamespaceAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name)1241cf11a4cSAlexey Lapshin void CompileUnit::addNamespaceAccelerator(const DIE *Die,
1251cf11a4cSAlexey Lapshin                                           DwarfStringPoolEntryRef Name) {
1261cf11a4cSAlexey Lapshin   Namespaces.emplace_back(Name, Die);
1271cf11a4cSAlexey Lapshin }
1281cf11a4cSAlexey Lapshin 
addObjCAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool SkipPubSection)1291cf11a4cSAlexey Lapshin void CompileUnit::addObjCAccelerator(const DIE *Die,
1301cf11a4cSAlexey Lapshin                                      DwarfStringPoolEntryRef Name,
1311cf11a4cSAlexey Lapshin                                      bool SkipPubSection) {
1321cf11a4cSAlexey Lapshin   ObjC.emplace_back(Name, Die, SkipPubSection);
1331cf11a4cSAlexey Lapshin }
1341cf11a4cSAlexey Lapshin 
addNameAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool SkipPubSection)1351cf11a4cSAlexey Lapshin void CompileUnit::addNameAccelerator(const DIE *Die,
1361cf11a4cSAlexey Lapshin                                      DwarfStringPoolEntryRef Name,
1371cf11a4cSAlexey Lapshin                                      bool SkipPubSection) {
1381cf11a4cSAlexey Lapshin   Pubnames.emplace_back(Name, Die, SkipPubSection);
1391cf11a4cSAlexey Lapshin }
1401cf11a4cSAlexey Lapshin 
addTypeAccelerator(const DIE * Die,DwarfStringPoolEntryRef Name,bool ObjcClassImplementation,uint32_t QualifiedNameHash)1411cf11a4cSAlexey Lapshin void CompileUnit::addTypeAccelerator(const DIE *Die,
1421cf11a4cSAlexey Lapshin                                      DwarfStringPoolEntryRef Name,
1431cf11a4cSAlexey Lapshin                                      bool ObjcClassImplementation,
1441cf11a4cSAlexey Lapshin                                      uint32_t QualifiedNameHash) {
1451cf11a4cSAlexey Lapshin   Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);
1461cf11a4cSAlexey Lapshin }
1471cf11a4cSAlexey Lapshin 
1481cf11a4cSAlexey Lapshin } // namespace llvm
149