Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -58,6 +58,7 @@ class InputFile; class Lazy; class SymbolBody; +template class ObjectInfo; // Debugging information helper class. The main purpose is to // retrieve source file and line for error reporting. Linker may @@ -68,12 +69,13 @@ typedef typename ELFT::uint uintX_t; public: - DIHelper(InputFile *F); + DIHelper(elf::ObjectFile *F); ~DIHelper(); - std::string getLineInfo(uintX_t Offset); + std::string getLineInfo(InputSectionBase *S, uintX_t Offset); private: std::unique_ptr DwarfLine; + std::unique_ptr> ObjInfo; }; // The root class of input files. Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -35,13 +35,55 @@ std::vector InputFile::Pool; -template DIHelper::DIHelper(elf::InputFile *F) { +// 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. +template class elf::ObjectInfo : public LoadedObjectInfo { +public: + ObjectInfo(ObjectFile *F); + + uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override; + std::unique_ptr clone() const override; + + DenseMap OffsetMap; +}; + +template elf::ObjectInfo::ObjectInfo(ObjectFile *F) { + for (InputSectionBase *S : F->getSections()) { + if (!S || S == &InputSectionBase::Discarded) + continue; + + OffsetMap.insert({S->Name, S->Offset}); + } +} + +template +uint64_t elf::ObjectInfo::getSectionLoadAddress( + const object::SectionRef &Sec) const { + + StringRef Name; + if (Sec.getName(Name)) + return 0; + + auto It = OffsetMap.find(Name); + return It == OffsetMap.end() ? 0 : It->second; +} + +template +std::unique_ptr elf::ObjectInfo::clone() const { + return std::unique_ptr(); +} + +template DIHelper::DIHelper(elf::ObjectFile *F) { Expected> Obj = object::ObjectFile::createObjectFile(F->MB); if (!Obj) return; - DWARFContextInMemory Dwarf(*Obj.get()); + ObjInfo.reset(new ObjectInfo(F)); + DWARFContextInMemory Dwarf(*Obj.get(), ObjInfo.get()); DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs)); DataExtractor LineData(Dwarf.getLineSection().Data, ELFT::TargetEndianness == support::little, @@ -54,7 +96,9 @@ template DIHelper::~DIHelper() {} -template std::string DIHelper::getLineInfo(uintX_t Offset) { +template +std::string DIHelper::getLineInfo(InputSectionBase *S, + uintX_t Offset) { if (!DwarfLine) return ""; @@ -64,7 +108,12 @@ const DWARFDebugLine::LineTable *LineTbl = DwarfLine->getLineTable(0); if (!LineTbl) return ""; - LineTbl->getFileLineInfoForAddress(Offset, nullptr, Spec.FLIKind, LineInfo); + + // Use fake address calcuated by adding section file offset and offset in + // section. + // See comments for ObjectInfo class + LineTbl->getFileLineInfoForAddress(S->Offset + Offset, nullptr, Spec.FLIKind, + LineInfo); return LineInfo.Line != 0 ? LineInfo.FileName + " (" + std::to_string(LineInfo.Line) + ")" : ""; Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -88,6 +88,7 @@ public: // These corresponds to the fields in Elf_Shdr. uintX_t Flags; + uintX_t Offset = 0; uintX_t Entsize; uint32_t Type; uint32_t Link; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -75,7 +75,9 @@ Kind SectionKind) : InputSectionBase(File, Hdr->sh_flags, Hdr->sh_type, Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, - getSectionContents(File, Hdr), Name, SectionKind) {} + getSectionContents(File, Hdr), Name, SectionKind) { + this->Offset = Hdr->sh_offset; +} template size_t InputSectionBase::getSize() const { if (auto *D = dyn_cast>(this)) Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -544,7 +544,7 @@ ObjectFile *File = S.getFile(); // First check if we can get desired values from debugging information. - std::string LineInfo = File->getDIHelper()->getLineInfo(Offset); + std::string LineInfo = File->getDIHelper()->getLineInfo(&S, Offset); if (!LineInfo.empty()) return LineInfo; Index: test/ELF/Inputs/undef-debug.s =================================================================== --- test/ELF/Inputs/undef-debug.s +++ test/ELF/Inputs/undef-debug.s @@ -1,3 +1,11 @@ .file 1 "undef-debug.s" .loc 1 3 .quad zed3 + +.section .text.1,"ax" +.loc 1 7 + .quad zed4 + +.section .text.2,"ax" +.loc 1 11 + .quad zed5 Index: test/ELF/undef.s =================================================================== --- test/ELF/undef.s +++ test/ELF/undef.s @@ -10,6 +10,8 @@ # CHECK: error: undef.s (.text+0x10): undefined symbol 'foo(int)' # CHECK: error: {{.*}}2.a({{.*}}.o) (.text+0x0): undefined symbol 'zed2' # CHECK: error: undef-debug.s (3): undefined symbol 'zed3' +# CHECK: error: undef-debug.s (7): undefined symbol 'zed4' +# CHECK: error: undef-debug.s (11): undefined symbol 'zed5' # RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \ # RUN: FileCheck -check-prefix=NO-DEMANGLE %s