diff options
| author | George Rimar <grimar@accesssoftek.com> | 2017-11-01 07:42:38 +0000 |
|---|---|---|
| committer | George Rimar <grimar@accesssoftek.com> | 2017-11-01 07:42:38 +0000 |
| commit | 82f0c42dadd751a5d457b53a9c1adceb3c9eabbb (patch) | |
| tree | c20bc7531d586ebd10953c84bad7b24d7c1edd4f /lld/ELF/InputFiles.cpp | |
| parent | 688f0ca6a76154bfd51e95d9b5b83fe6ada4d25b (diff) | |
[ELF] - Teach LLD to report line numbers for data symbols.
This is PR34826.
Currently LLD is unable to report line number when reporting
duplicate declaration of some variable.
That happens because for extracting line information we always use
.debug_line section content which describes mapping from machine
instructions to source file locations, what does not help for
variables as does not describe them.
In this patch I am taking the approproate information about
variables locations from the .debug_info section.
Differential revision: https://reviews.llvm.org/D38721
llvm-svn: 317080
Diffstat (limited to 'lld/ELF/InputFiles.cpp')
| -rw-r--r-- | lld/ELF/InputFiles.cpp | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index e1cc2fe0de45..98329cdc0cde 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -67,7 +67,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { return MBRef; } -template <class ELFT> void ObjFile<ELFT>::initializeDwarfLine() { +template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this)); const DWARFObject &Obj = Dwarf.getDWARFObj(); DwarfLine.reset(new DWARFDebugLine); @@ -77,7 +77,68 @@ template <class ELFT> void ObjFile<ELFT>::initializeDwarfLine() { // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. - DwarfLine->getOrParseLineTable(LineData, 0); + const DWARFDebugLine::LineTable *LT = + DwarfLine->getOrParseLineTable(LineData, 0); + + // Return if there is no debug information about CU available. + if (!Dwarf.getNumCompileUnits()) + return; + + // Loop over variable records and insert them to VariableLoc. + DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0); + for (const auto &Entry : CU->dies()) { + DWARFDie Die(CU, &Entry); + // Skip all tags that are not variables. + if (Die.getTag() != dwarf::DW_TAG_variable) + continue; + + // Skip if a local variable because we don't need them for generating error + // messages. In general, only non-local symbols can fail to be linked. + if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) + continue; + + // Get the source filename index for the variable. + unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); + if (!LT->hasFileAtIndex(File)) + continue; + + // Get the line number on which the variable is declared. + unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); + + // Get the name of the variable and add the collected information to + // VariableLoc. Usually Name is non-empty, but it can be empty if the input + // object file lacks some debug info. + StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), ""); + if (!Name.empty()) + VariableLoc.insert({Name, {File, Line}}); + } +} + +// Returns the pair of file name and line number describing location of data +// object (variable, array, etc) definition. +template <class ELFT> +Optional<std::pair<std::string, unsigned>> +ObjFile<ELFT>::getVariableLoc(StringRef Name) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); + + // There is always only one CU so it's offset is 0. + const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0); + if (!LT) + return None; + + // Return if we have no debug information about data object. + auto It = VariableLoc.find(Name); + if (It == VariableLoc.end()) + return None; + + // Take file name string from line table. + std::string FileName; + if (!LT->getFileNameByIndex( + It->second.first /* File */, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) + return None; + + return std::make_pair(FileName, It->second.second /*Line*/); } // Returns source line information for a given offset @@ -85,7 +146,7 @@ template <class ELFT> void ObjFile<ELFT>::initializeDwarfLine() { template <class ELFT> Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S, uint64_t Offset) { - llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); }); + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); |
