Martin Storsjo | 908b780 | 2019-10-21 08:01:52 | [diff] [blame] | 1 | //===- DWARF.cpp ----------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "lld/Common/DWARF.h" |
| 10 | #include "lld/Common/ErrorHandler.h" |
| 11 | |
| 12 | using namespace llvm; |
| 13 | |
| 14 | namespace lld { |
| 15 | |
| 16 | DWARFCache::DWARFCache(std::unique_ptr<llvm::DWARFContext> d) |
| 17 | : dwarf(std::move(d)) { |
| 18 | for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) { |
| 19 | auto report = [](Error err) { |
| 20 | handleAllErrors(std::move(err), |
| 21 | [](ErrorInfoBase &info) { warn(info.message()); }); |
| 22 | }; |
| 23 | Expected<const DWARFDebugLine::LineTable *> expectedLT = |
| 24 | dwarf->getLineTableForUnit(cu.get(), report); |
| 25 | const DWARFDebugLine::LineTable *lt = nullptr; |
| 26 | if (expectedLT) |
| 27 | lt = *expectedLT; |
| 28 | else |
| 29 | report(expectedLT.takeError()); |
| 30 | if (!lt) |
| 31 | continue; |
| 32 | lineTables.push_back(lt); |
| 33 | |
| 34 | // Loop over variable records and insert them to variableLoc. |
| 35 | for (const auto &entry : cu->dies()) { |
| 36 | DWARFDie die(cu.get(), &entry); |
| 37 | // Skip all tags that are not variables. |
| 38 | if (die.getTag() != dwarf::DW_TAG_variable) |
| 39 | continue; |
| 40 | |
| 41 | // Skip if a local variable because we don't need them for generating |
| 42 | // error messages. In general, only non-local symbols can fail to be |
| 43 | // linked. |
| 44 | if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0)) |
| 45 | continue; |
| 46 | |
| 47 | // Get the source filename index for the variable. |
| 48 | unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0); |
| 49 | if (!lt->hasFileAtIndex(file)) |
| 50 | continue; |
| 51 | |
| 52 | // Get the line number on which the variable is declared. |
| 53 | unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0); |
| 54 | |
| 55 | // Here we want to take the variable name to add it into variableLoc. |
| 56 | // Variable can have regular and linkage name associated. At first, we try |
| 57 | // to get linkage name as it can be different, for example when we have |
| 58 | // two variables in different namespaces of the same object. Use common |
| 59 | // name otherwise, but handle the case when it also absent in case if the |
| 60 | // input object file lacks some debug info. |
| 61 | StringRef name = |
| 62 | dwarf::toString(die.find(dwarf::DW_AT_linkage_name), |
| 63 | dwarf::toString(die.find(dwarf::DW_AT_name), "")); |
| 64 | if (!name.empty()) |
| 65 | variableLoc.insert({name, {lt, file, line}}); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // Returns the pair of file name and line number describing location of data |
| 71 | // object (variable, array, etc) definition. |
| 72 | Optional<std::pair<std::string, unsigned>> |
| 73 | DWARFCache::getVariableLoc(StringRef name) { |
| 74 | // Return if we have no debug information about data object. |
| 75 | auto it = variableLoc.find(name); |
| 76 | if (it == variableLoc.end()) |
| 77 | return None; |
| 78 | |
| 79 | // Take file name string from line table. |
| 80 | std::string fileName; |
| 81 | if (!it->second.lt->getFileNameByIndex( |
| 82 | it->second.file, {}, |
| 83 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) |
| 84 | return None; |
| 85 | |
| 86 | return std::make_pair(fileName, it->second.line); |
| 87 | } |
| 88 | |
| 89 | // Returns source line information for a given offset |
| 90 | // using DWARF debug info. |
| 91 | Optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset, |
| 92 | uint64_t sectionIndex) { |
| 93 | DILineInfo info; |
| 94 | for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { |
| 95 | if (lt->getFileLineInfoForAddress( |
| 96 | {offset, sectionIndex}, nullptr, |
| 97 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) |
| 98 | return info; |
| 99 | } |
| 100 | return None; |
| 101 | } |
| 102 | |
| 103 | } // namespace lld |