summaryrefslogtreecommitdiff
path: root/ELF/GdbIndex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/GdbIndex.cpp')
-rw-r--r--ELF/GdbIndex.cpp88
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>;