//===- DWARF.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 // //===----------------------------------------------------------------------===// // // The -gdb-index option instructs the linker to emit a .gdb_index section. // The section contains information to make gdb startup faster. // The format of the section is described at // https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html. // //===----------------------------------------------------------------------===// #include "DWARF.h" #include "Symbols.h" #include "Target.h" #include "lld/Common/Memory.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" using namespace llvm; using namespace llvm::object; using namespace lld; using namespace lld::elf; template LLDDwarfObj::LLDDwarfObj(ObjFile *Obj) { for (InputSectionBase *Sec : Obj->getSections()) { if (!Sec) continue; if (LLDDWARFSection *M = StringSwitch(Sec->Name) .Case(".debug_addr", &AddrSection) .Case(".debug_gnu_pubnames", &GnuPubNamesSection) .Case(".debug_gnu_pubtypes", &GnuPubTypesSection) .Case(".debug_info", &InfoSection) .Case(".debug_ranges", &RangeSection) .Case(".debug_rnglists", &RngListsSection) .Case(".debug_line", &LineSection) .Default(nullptr)) { M->Data = toStringRef(Sec->data()); M->Sec = Sec; continue; } if (Sec->Name == ".debug_abbrev") AbbrevSection = toStringRef(Sec->data()); else if (Sec->Name == ".debug_str") StrSection = toStringRef(Sec->data()); else if (Sec->Name == ".debug_line_str") LineStringSection = toStringRef(Sec->data()); } } namespace { template struct LLDRelocationResolver { // In the ELF ABIs, S sepresents the value of the symbol in the relocation // entry. For Rela, the addend is stored as part of the relocation entry. static uint64_t Resolve(object::RelocationRef Ref, uint64_t S, uint64_t /* A */) { return S + Ref.getRawDataRefImpl().p; } }; template struct LLDRelocationResolver> { // For Rel, the addend A is supplied by the caller. static uint64_t Resolve(object::RelocationRef /*Ref*/, uint64_t S, uint64_t A) { return S + A; } }; } // namespace // Find if there is a relocation at Pos in Sec. The code is a bit // more complicated than usual because we need to pass a section index // to llvm since it has no idea about InputSection. template template Optional LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, ArrayRef Rels) const { auto It = std::lower_bound( Rels.begin(), Rels.end(), Pos, [](const RelTy &A, uint64_t B) { return A.r_offset < B; }); if (It == Rels.end() || It->r_offset != Pos) return None; const RelTy &Rel = *It; const ObjFile *File = Sec.getFile(); uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); const typename ELFT::Sym &Sym = File->template getELFSyms()[SymIndex]; uint32_t SecIndex = File->getSectionIndex(Sym); // Broken debug info can point to a non-Defined symbol. auto *DR = dyn_cast(&File->getRelocTargetSym(Rel)); if (!DR) { RelType Type = Rel.getType(Config->IsMips64EL); if (Type != Target->NoneRel) error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" + llvm::utohexstr(Rel.r_offset) + " has unsupported target"); return None; } uint64_t Val = DR->Value; // FIXME: We should be consistent about always adding the file // offset or not. if (DR->Section->Flags & ELF::SHF_ALLOC) Val += cast(DR->Section)->getOffsetInFile(); DataRefImpl D; D.p = getAddend(Rel); return RelocAddrEntry{SecIndex, RelocationRef(D, nullptr), LLDRelocationResolver::Resolve, Val}; } template Optional LLDDwarfObj::find(const llvm::DWARFSection &S, uint64_t Pos) const { auto &Sec = static_cast(S); if (Sec.Sec->AreRelocsRela) return findAux(*Sec.Sec, Pos, Sec.Sec->template relas()); return findAux(*Sec.Sec, Pos, Sec.Sec->template rels()); } template class elf::LLDDwarfObj; template class elf::LLDDwarfObj; template class elf::LLDDwarfObj; template class elf::LLDDwarfObj;