1908b7809SMartin Storsjo //===- DWARF.cpp ----------------------------------------------------------===// 2908b7809SMartin Storsjo // 3908b7809SMartin Storsjo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4908b7809SMartin Storsjo // See https://llvm.org/LICENSE.txt for license information. 5908b7809SMartin Storsjo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6908b7809SMartin Storsjo // 7908b7809SMartin Storsjo //===----------------------------------------------------------------------===// 8908b7809SMartin Storsjo 9908b7809SMartin Storsjo #include "lld/Common/DWARF.h" 10908b7809SMartin Storsjo #include "lld/Common/ErrorHandler.h" 11908b7809SMartin Storsjo 12908b7809SMartin Storsjo using namespace llvm; 13908b7809SMartin Storsjo 14908b7809SMartin Storsjo namespace lld { 15908b7809SMartin Storsjo 16908b7809SMartin Storsjo DWARFCache::DWARFCache(std::unique_ptr<llvm::DWARFContext> d) 17908b7809SMartin Storsjo : dwarf(std::move(d)) { 18908b7809SMartin Storsjo for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) { 19908b7809SMartin Storsjo auto report = [](Error err) { 20908b7809SMartin Storsjo handleAllErrors(std::move(err), 21908b7809SMartin Storsjo [](ErrorInfoBase &info) { warn(info.message()); }); 22908b7809SMartin Storsjo }; 23908b7809SMartin Storsjo Expected<const DWARFDebugLine::LineTable *> expectedLT = 24908b7809SMartin Storsjo dwarf->getLineTableForUnit(cu.get(), report); 25908b7809SMartin Storsjo const DWARFDebugLine::LineTable *lt = nullptr; 26908b7809SMartin Storsjo if (expectedLT) 27908b7809SMartin Storsjo lt = *expectedLT; 28908b7809SMartin Storsjo else 29908b7809SMartin Storsjo report(expectedLT.takeError()); 30908b7809SMartin Storsjo if (!lt) 31908b7809SMartin Storsjo continue; 32908b7809SMartin Storsjo lineTables.push_back(lt); 33908b7809SMartin Storsjo 34908b7809SMartin Storsjo // Loop over variable records and insert them to variableLoc. 35908b7809SMartin Storsjo for (const auto &entry : cu->dies()) { 36908b7809SMartin Storsjo DWARFDie die(cu.get(), &entry); 37908b7809SMartin Storsjo // Skip all tags that are not variables. 38908b7809SMartin Storsjo if (die.getTag() != dwarf::DW_TAG_variable) 39908b7809SMartin Storsjo continue; 40908b7809SMartin Storsjo 41908b7809SMartin Storsjo // Skip if a local variable because we don't need them for generating 42908b7809SMartin Storsjo // error messages. In general, only non-local symbols can fail to be 43908b7809SMartin Storsjo // linked. 44908b7809SMartin Storsjo if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0)) 45908b7809SMartin Storsjo continue; 46908b7809SMartin Storsjo 47908b7809SMartin Storsjo // Get the source filename index for the variable. 48908b7809SMartin Storsjo unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0); 49908b7809SMartin Storsjo if (!lt->hasFileAtIndex(file)) 50908b7809SMartin Storsjo continue; 51908b7809SMartin Storsjo 52908b7809SMartin Storsjo // Get the line number on which the variable is declared. 53908b7809SMartin Storsjo unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0); 54908b7809SMartin Storsjo 55908b7809SMartin Storsjo // Here we want to take the variable name to add it into variableLoc. 56908b7809SMartin Storsjo // Variable can have regular and linkage name associated. At first, we try 57908b7809SMartin Storsjo // to get linkage name as it can be different, for example when we have 58908b7809SMartin Storsjo // two variables in different namespaces of the same object. Use common 59908b7809SMartin Storsjo // name otherwise, but handle the case when it also absent in case if the 60908b7809SMartin Storsjo // input object file lacks some debug info. 61908b7809SMartin Storsjo StringRef name = 62908b7809SMartin Storsjo dwarf::toString(die.find(dwarf::DW_AT_linkage_name), 63908b7809SMartin Storsjo dwarf::toString(die.find(dwarf::DW_AT_name), "")); 64908b7809SMartin Storsjo if (!name.empty()) 65908b7809SMartin Storsjo variableLoc.insert({name, {lt, file, line}}); 66908b7809SMartin Storsjo } 67908b7809SMartin Storsjo } 68908b7809SMartin Storsjo } 69908b7809SMartin Storsjo 70908b7809SMartin Storsjo // Returns the pair of file name and line number describing location of data 71908b7809SMartin Storsjo // object (variable, array, etc) definition. 72c33511c8SFangrui Song std::optional<std::pair<std::string, unsigned>> 73908b7809SMartin Storsjo DWARFCache::getVariableLoc(StringRef name) { 74908b7809SMartin Storsjo // Return if we have no debug information about data object. 75908b7809SMartin Storsjo auto it = variableLoc.find(name); 76908b7809SMartin Storsjo if (it == variableLoc.end()) 77c33511c8SFangrui Song return std::nullopt; 78908b7809SMartin Storsjo 79908b7809SMartin Storsjo // Take file name string from line table. 80908b7809SMartin Storsjo std::string fileName; 81908b7809SMartin Storsjo if (!it->second.lt->getFileNameByIndex( 82908b7809SMartin Storsjo it->second.file, {}, 83908b7809SMartin Storsjo DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) 84c33511c8SFangrui Song return std::nullopt; 85908b7809SMartin Storsjo 86908b7809SMartin Storsjo return std::make_pair(fileName, it->second.line); 87908b7809SMartin Storsjo } 88908b7809SMartin Storsjo 89908b7809SMartin Storsjo // Returns source line information for a given offset 90908b7809SMartin Storsjo // using DWARF debug info. 91c33511c8SFangrui Song std::optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset, 92908b7809SMartin Storsjo uint64_t sectionIndex) { 93908b7809SMartin Storsjo DILineInfo info; 94908b7809SMartin Storsjo for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { 95908b7809SMartin Storsjo if (lt->getFileLineInfoForAddress( 96*0886440eSAmit Kumar Pandey {offset, sectionIndex}, false, nullptr, 97908b7809SMartin Storsjo DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) 98908b7809SMartin Storsjo return info; 99908b7809SMartin Storsjo } 100c33511c8SFangrui Song return std::nullopt; 101908b7809SMartin Storsjo } 102908b7809SMartin Storsjo 103908b7809SMartin Storsjo } // namespace lld 104