blob: 06559bc38c86ccb9dbd5d7d619bd92e13785f8a8 [file] [log] [blame]
//===- DWARFLinkerCompileUnit.cpp -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/Support/FormatVariadic.h"
namespace llvm {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() {
llvm::errs() << "{\n";
llvm::errs() << " AddrAdjust: " << AddrAdjust << '\n';
llvm::errs() << " Ctxt: " << formatv("{0:x}", Ctxt) << '\n';
llvm::errs() << " Clone: " << formatv("{0:x}", Clone) << '\n';
llvm::errs() << " ParentIdx: " << ParentIdx << '\n';
llvm::errs() << " Keep: " << Keep << '\n';
llvm::errs() << " InDebugMap: " << InDebugMap << '\n';
llvm::errs() << " Prune: " << Prune << '\n';
llvm::errs() << " Incomplete: " << Incomplete << '\n';
llvm::errs() << " InModuleScope: " << InModuleScope << '\n';
llvm::errs() << " ODRMarkingDone: " << ODRMarkingDone << '\n';
llvm::errs() << " UnclonedReference: " << UnclonedReference << '\n';
llvm::errs() << "}\n";
}
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Check if the DIE at \p Idx is in the scope of a function.
static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
while (Idx) {
if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram)
return true;
Idx = U.getInfo(Idx).ParentIdx;
}
return false;
}
uint16_t CompileUnit::getLanguage() {
if (!Language) {
DWARFDie CU = getOrigUnit().getUnitDIE();
Language = dwarf::toUnsigned(CU.find(dwarf::DW_AT_language), 0);
}
return Language;
}
StringRef CompileUnit::getSysRoot() {
if (SysRoot.empty()) {
DWARFDie CU = getOrigUnit().getUnitDIE();
SysRoot = dwarf::toStringRef(CU.find(dwarf::DW_AT_LLVM_sysroot)).str();
}
return SysRoot;
}
void CompileUnit::markEverythingAsKept() {
unsigned Idx = 0;
for (auto &I : Info) {
// Mark everything that wasn't explicit marked for pruning.
I.Keep = !I.Prune;
auto DIE = OrigUnit.getDIEAtIndex(Idx++);
DWARFUnit *U = DIE.getDwarfUnit();
// Try to guess which DIEs must go to the accelerator tables. We do that
// just for variables, because functions will be handled depending on
// whether they carry a DW_AT_low_pc attribute or not.
if (DIE.getTag() != dwarf::DW_TAG_variable &&
DIE.getTag() != dwarf::DW_TAG_constant)
continue;
std::optional<DWARFFormValue> Value;
if (!(Value = DIE.find(dwarf::DW_AT_location))) {
if ((Value = DIE.find(dwarf::DW_AT_const_value)) &&
!inFunctionScope(*this, I.ParentIdx))
I.InDebugMap = true;
continue;
}
if (auto ExprLockBlock = Value->getAsBlock()) {
// Parse 'exprloc' expression.
DataExtractor Data(toStringRef(*ExprLockBlock),
U->getContext().isLittleEndian(),
U->getAddressByteSize());
DWARFExpression Expression(Data, U->getAddressByteSize(),
U->getFormParams().Format);
for (DWARFExpression::iterator It = Expression.begin();
(It != Expression.end()) && !I.InDebugMap; ++It) {
DWARFExpression::iterator NextIt = It;
++NextIt;
switch (It->getCode()) {
case dwarf::DW_OP_const2u:
case dwarf::DW_OP_const4u:
case dwarf::DW_OP_const8u:
case dwarf::DW_OP_const2s:
case dwarf::DW_OP_const4s:
case dwarf::DW_OP_const8s:
if (NextIt == Expression.end() ||
NextIt->getCode() != dwarf::DW_OP_form_tls_address)
break;
[[fallthrough]];
case dwarf::DW_OP_constx:
case dwarf::DW_OP_addr:
case dwarf::DW_OP_addrx:
I.InDebugMap = true;
break;
default:
// Nothing to do.
break;
}
}
}
}
}
uint64_t CompileUnit::computeNextUnitOffset(uint16_t DwarfVersion) {
NextUnitOffset = StartOffset;
if (NewUnit) {
NextUnitOffset += (DwarfVersion >= 5) ? 12 : 11; // Header size
NextUnitOffset += NewUnit->getUnitDie().getSize();
}
return NextUnitOffset;
}
/// Keep track of a forward cross-cu reference from this unit
/// to \p Die that lives in \p RefUnit.
void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
DeclContext *Ctxt, PatchLocation Attr) {
ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
}
void CompileUnit::fixupForwardReferences() {
for (const auto &Ref : ForwardDIEReferences) {
DIE *RefDie;
const CompileUnit *RefUnit;
PatchLocation Attr;
DeclContext *Ctxt;
std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
if (Ctxt && Ctxt->hasCanonicalDIE()) {
assert(Ctxt->getCanonicalDIEOffset() &&
"Canonical die offset is not set");
Attr.set(Ctxt->getCanonicalDIEOffset());
} else {
assert(RefDie->getOffset() && "Referenced die offset is not set");
Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
}
}
}
void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
Labels.insert({LabelLowPc, PcOffset});
}
void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
int64_t PcOffset) {
Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset);
if (LowPc)
LowPc = std::min(*LowPc, FuncLowPc + PcOffset);
else
LowPc = FuncLowPc + PcOffset;
this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
}
void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
UnitRangeAttribute = Attr;
return;
}
RangeAttributes.emplace_back(Attr);
}
void CompileUnit::noteLocationAttribute(PatchLocation Attr) {
LocationAttributes.emplace_back(Attr);
}
void CompileUnit::addNamespaceAccelerator(const DIE *Die,
DwarfStringPoolEntryRef Name) {
Namespaces.emplace_back(Name, Die);
}
void CompileUnit::addObjCAccelerator(const DIE *Die,
DwarfStringPoolEntryRef Name,
bool SkipPubSection) {
ObjC.emplace_back(Name, Die, SkipPubSection);
}
void CompileUnit::addNameAccelerator(const DIE *Die,
DwarfStringPoolEntryRef Name,
bool SkipPubSection) {
Pubnames.emplace_back(Name, Die, SkipPubSection);
}
void CompileUnit::addTypeAccelerator(const DIE *Die,
DwarfStringPoolEntryRef Name,
bool ObjcClassImplementation,
uint32_t QualifiedNameHash) {
Pubtypes.emplace_back(Name, Die, QualifiedNameHash, ObjcClassImplementation);
}
} // namespace llvm