| //===- GdbIndex.cpp -------------------------------------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // 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 "GdbIndex.h" |
| #include "Symbols.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 <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) { |
| for (InputSectionBase *Sec : Obj->getSections()) { |
| if (!Sec) |
| continue; |
| if (LLDDWARFSection *M = StringSwitch<LLDDWARFSection *>(Sec->Name) |
| .Case(".debug_info", &InfoSection) |
| .Case(".debug_ranges", &RangeSection) |
| .Case(".debug_line", &LineSection) |
| .Default(nullptr)) { |
| Sec->maybeDecompress(); |
| M->Data = toStringRef(Sec->Data); |
| M->Sec = Sec; |
| continue; |
| } |
| if (Sec->Name == ".debug_abbrev") |
| AbbrevSection = toStringRef(Sec->Data); |
| else if (Sec->Name == ".debug_gnu_pubnames") |
| GnuPubNamesSection = toStringRef(Sec->Data); |
| else if (Sec->Name == ".debug_gnu_pubtypes") |
| GnuPubTypesSection = toStringRef(Sec->Data); |
| else if (Sec->Name == ".debug_str") |
| StrSection = toStringRef(Sec->Data); |
| } |
| } |
| |
| // 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 <class ELFT> |
| template <class RelTy> |
| Optional<RelocAddrEntry> |
| LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos, |
| ArrayRef<RelTy> 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<ELFT> *File = Sec.getFile<ELFT>(); |
| uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); |
| const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex]; |
| uint32_t SecIndex = File->getSectionIndex(Sym); |
| |
| // Broken debug info can point to a non-Defined symbol. |
| auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel)); |
| if (!DR) { |
| error("unsupported relocation target while parsing debug info"); |
| return None; |
| } |
| uint64_t Val = DR->Value + getAddend<ELFT>(Rel); |
| |
| // FIXME: We should be consistent about always adding the file |
| // offset or not. |
| if (DR->Section->Flags & ELF::SHF_ALLOC) |
| Val += cast<InputSection>(DR->Section)->getOffsetInFile(); |
| |
| return RelocAddrEntry{SecIndex, Val}; |
| } |
| |
| template <class ELFT> |
| Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &S, |
| uint64_t Pos) const { |
| auto &Sec = static_cast<const LLDDWARFSection &>(S); |
| if (Sec.Sec->AreRelocsRela) |
| return findAux(*Sec.Sec, Pos, Sec.Sec->template relas<ELFT>()); |
| return findAux(*Sec.Sec, Pos, Sec.Sec->template rels<ELFT>()); |
| } |
| |
| template class elf::LLDDwarfObj<ELF32LE>; |
| template class elf::LLDDwarfObj<ELF32BE>; |
| template class elf::LLDDwarfObj<ELF64LE>; |
| template class elf::LLDDwarfObj<ELF64BE>; |