summaryrefslogtreecommitdiff
path: root/lld/ELF/InputFiles.cpp
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2017-11-01 07:42:38 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2017-11-01 07:42:38 +0000
commit82f0c42dadd751a5d457b53a9c1adceb3c9eabbb (patch)
treec20bc7531d586ebd10953c84bad7b24d7c1edd4f /lld/ELF/InputFiles.cpp
parent688f0ca6a76154bfd51e95d9b5b83fe6ada4d25b (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.cpp67
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);