Index: ELF/GdbIndex.h =================================================================== --- ELF/GdbIndex.h +++ ELF/GdbIndex.h @@ -19,6 +19,51 @@ class InputSection; +struct LLDDWARFSection final : public llvm::DWARFSection { + InputSectionBase *Sec = nullptr; +}; + +template class LLDDwarfObj final : public llvm::DWARFObj { + elf::ObjectFile *Obj; + LLDDWARFSection InfoSection; + LLDDWARFSection RangeSection; + LLDDWARFSection LineSection; + StringRef AbbrevSection; + StringRef GnuPubNamesSection; + StringRef GnuPubTypesSection; + + template + llvm::Optional findAux(const InputSectionBase &Sec, + uint64_t Pos, + ArrayRef Rels) const; + +public: + explicit LLDDwarfObj(elf::ObjectFile *Obj); + const llvm::DWARFSection &getInfoSection() const override { + return InfoSection; + } + const llvm::DWARFSection &getRangeSection() const override { + return RangeSection; + } + const llvm::DWARFSection &getLineSection() const override { + return LineSection; + } + StringRef getCUIndexSection() const override { return ""; } + StringRef getAbbrevSection() const override { return AbbrevSection; } + StringRef getStringSection() const override { return ""; } + StringRef getGnuPubNamesSection() const override { + return GnuPubNamesSection; + } + StringRef getGnuPubTypesSection() const override { + return GnuPubTypesSection; + } + bool isLittleEndian() const override { + return ELFT::TargetEndianness == llvm::support::little; + } + llvm::Optional find(const llvm::DWARFSection &Sec, + uint64_t Pos) const override; +}; + // Struct represents single entry of address area of gdb index. struct AddressEntry { InputSection *Section; Index: ELF/GdbIndex.cpp =================================================================== --- ELF/GdbIndex.cpp +++ ELF/GdbIndex.cpp @@ -47,3 +47,70 @@ Table[I] = Sym; } } + +template +LLDDwarfObj::LLDDwarfObj(elf::ObjectFile *Obj) : Obj(Obj) { + for (InputSectionBase *Sec : Obj->getSections()) { + if (!Sec) + continue; + if (LLDDWARFSection *M = StringSwitch(Sec->Name) + .Case(".debug_info", &InfoSection) + .Case(".debug_ranges", &RangeSection) + .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_gnu_pubnames") + GnuPubNamesSection = toStringRef(Sec->Data); + else if (Sec->Name == ".debug_gnu_pubtypes") + GnuPubTypesSection = 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 +template +Optional +LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, + ArrayRef Rels) const { + auto I = llvm::find_if(Rels, + [=](const RelTy &Rel) { return Rel.r_offset == Pos; }); + if (I == Rels.end()) + return None; + const RelTy &Rel = *I; + const elf::ObjectFile *File = Sec.getFile(); + uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); + const typename ELFT::Sym &Sym = File->getELFSymbols()[SymIndex]; + uint32_t SecIndex = File->getSectionIndex(Sym); + SymbolBody &B = File->getRelocTargetSym(Rel); + auto &DR = cast(B); + uint64_t Val = DR.Value + getAddend(Rel); + + // 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(); + + RelocAddrEntry Ret{SecIndex, Val}; + return Ret; +} + +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; Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -126,6 +126,7 @@ uint32_t getSectionIndex(const Elf_Sym &Sym) const; Elf_Sym_Range getGlobalSymbols(); + Elf_Sym_Range getELFSymbols() const { return Symbols; } protected: ArrayRef Symbols; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -39,20 +39,6 @@ InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} -namespace { -// In ELF object file all section addresses are zero. If we have multiple -// .text sections (when using -ffunction-section or comdat group) then -// LLVM DWARF parser will not be able to parse .debug_line correctly, unless -// we assign each section some unique address. This callback method assigns -// each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfoHelper { -public: - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - return static_cast(Sec).getOffset(); - } -}; -} - Optional elf::readFile(StringRef Path) { log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); @@ -71,13 +57,10 @@ } template void elf::ObjectFile::initializeDwarfLine() { - std::unique_ptr Obj = - check(object::ObjectFile::createObjectFile(this->MB), toString(this)); - - ObjectInfo ObjInfo; - DWARFContextInMemory Dwarf(*Obj, &ObjInfo); + LLDDwarfObj DO(this); + DWARFContext Dwarf(DO); DwarfLine.reset(new DWARFDebugLine); - DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE, + DWARFDataExtractor LineData(DO, DO.getLineSection(), Config->IsLE, Config->Wordsize); // The second parameter is offset in .debug_line section @@ -506,9 +489,14 @@ // If that's the case, we want to eliminate .debug_gnu_pub{names,types} // because they are redundant and can waste large amount of disk space // (for example, they are about 400 MiB in total for a clang debug build.) + // We still create the section and mark it dead so that the gdb index code + // can use the InputSection to access the data. if (Config->GdbIndex && - (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) - return &InputSection::Discarded; + (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) { + auto *Ret = make(this, &Sec, Name); + Script->discard({Ret}); + return Ret; + } // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1738,7 +1738,9 @@ // Range list with zero size has no effect. if (R.LowPC == R.HighPC) continue; - Ret.push_back({cast(S), R.LowPC, R.HighPC, CurrentCu}); + auto *IS = cast(S); + uint64_t Offset = IS->getOffsetInFile(); + Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CurrentCu}); } ++CurrentCu; } @@ -1747,8 +1749,8 @@ static std::vector readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { - StringRef Data[] = {Dwarf.getGnuPubNamesSection(), - Dwarf.getGnuPubTypesSection()}; + StringRef Data[] = {Dwarf.getDWARFObj().getGnuPubNamesSection(), + Dwarf.getDWARFObj().getGnuPubTypesSection()}; std::vector Ret; for (StringRef D : Data) { @@ -1798,7 +1800,7 @@ } } -static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) { +static GdbIndexChunk readDwarf(DWARFContext &Dwarf, InputSection *Sec) { GdbIndexChunk Ret; Ret.DebugInfoSec = Sec; Ret.CompilationUnits = readCuList(Dwarf); @@ -1810,16 +1812,9 @@ template GdbIndexSection *elf::createGdbIndex() { std::vector Chunks; for (InputSection *Sec : getDebugInfoSections()) { - InputFile *F = Sec->File; - std::error_code EC; - ELFObjectFile Obj(F->MB, EC); - if (EC) - fatal(EC.message()); - DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) { - error(toString(F) + ": error parsing DWARF data:\n>>> " + - toString(std::move(E))); - return ErrorPolicy::Continue; - }); + elf::ObjectFile *F = Sec->getFile(); + LLDDwarfObj DO(F); + DWARFContext Dwarf(DO); Chunks.push_back(readDwarf(Dwarf, Sec)); } return make(std::move(Chunks)); Index: test/ELF/invalid/invalid-debug-relocations.test =================================================================== --- test/ELF/invalid/invalid-debug-relocations.test +++ test/ELF/invalid/invalid-debug-relocations.test @@ -2,8 +2,7 @@ # RUN: yaml2obj %s -o %t.o # RUN: not ld.lld -gdb-index %t.o -o %t.exe 2>&1 | FileCheck %s -# CHECK: error: {{.*}}.o: error parsing DWARF data: -# CHECK-NEXT: >>> failed to compute relocation: Unknown, Invalid data was encountered while parsing the file +# CHECK: error: {{.*}}invalid-debug-relocations.test.tmp.o: unknown relocation type: Unknown (255) !ELF FileHeader: