diff options
Diffstat (limited to 'ELF/GdbIndex.cpp')
-rw-r--r-- | ELF/GdbIndex.cpp | 88 |
1 files changed, 70 insertions, 18 deletions
diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp index 99e02d0025b0..d27b57f95938 100644 --- a/ELF/GdbIndex.cpp +++ b/ELF/GdbIndex.cpp @@ -15,7 +15,8 @@ //===----------------------------------------------------------------------===// #include "GdbIndex.h" -#include "Memory.h" +#include "Symbols.h" +#include "lld/Common/Memory.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" @@ -24,26 +25,77 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf; -std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) { - GdbSymbol *&Sym = Map[Offset]; - if (Sym) - return {false, Sym}; - Sym = make<GdbSymbol>(Hash, Offset); - return {true, Sym}; +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->maybeUncompress(); + 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); + } } -void GdbHashTab::finalizeContents() { - uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3)); - uint32_t Mask = Size - 1; - Table.resize(Size); +// 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; - for (auto &P : Map) { - GdbSymbol *Sym = P.second; - uint32_t I = Sym->NameHash & Mask; - uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1; + 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); - while (Table[I]) - I = (I + Step) & Mask; - Table[I] = 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>; |