185868e8aSDimitry Andric //===- DWARF.cpp ----------------------------------------------------------===//
285868e8aSDimitry Andric //
385868e8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
485868e8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
585868e8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
685868e8aSDimitry Andric //
785868e8aSDimitry Andric //===----------------------------------------------------------------------===//
885868e8aSDimitry Andric
985868e8aSDimitry Andric #include "lld/Common/DWARF.h"
1085868e8aSDimitry Andric #include "lld/Common/ErrorHandler.h"
1185868e8aSDimitry Andric
1285868e8aSDimitry Andric using namespace llvm;
1385868e8aSDimitry Andric
1485868e8aSDimitry Andric namespace lld {
1585868e8aSDimitry Andric
DWARFCache(std::unique_ptr<llvm::DWARFContext> d)1685868e8aSDimitry Andric DWARFCache::DWARFCache(std::unique_ptr<llvm::DWARFContext> d)
1785868e8aSDimitry Andric : dwarf(std::move(d)) {
1885868e8aSDimitry Andric for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) {
1985868e8aSDimitry Andric auto report = [](Error err) {
2085868e8aSDimitry Andric handleAllErrors(std::move(err),
2185868e8aSDimitry Andric [](ErrorInfoBase &info) { warn(info.message()); });
2285868e8aSDimitry Andric };
2385868e8aSDimitry Andric Expected<const DWARFDebugLine::LineTable *> expectedLT =
2485868e8aSDimitry Andric dwarf->getLineTableForUnit(cu.get(), report);
2585868e8aSDimitry Andric const DWARFDebugLine::LineTable *lt = nullptr;
2685868e8aSDimitry Andric if (expectedLT)
2785868e8aSDimitry Andric lt = *expectedLT;
2885868e8aSDimitry Andric else
2985868e8aSDimitry Andric report(expectedLT.takeError());
3085868e8aSDimitry Andric if (!lt)
3185868e8aSDimitry Andric continue;
3285868e8aSDimitry Andric lineTables.push_back(lt);
3385868e8aSDimitry Andric
3485868e8aSDimitry Andric // Loop over variable records and insert them to variableLoc.
3585868e8aSDimitry Andric for (const auto &entry : cu->dies()) {
3685868e8aSDimitry Andric DWARFDie die(cu.get(), &entry);
3785868e8aSDimitry Andric // Skip all tags that are not variables.
3885868e8aSDimitry Andric if (die.getTag() != dwarf::DW_TAG_variable)
3985868e8aSDimitry Andric continue;
4085868e8aSDimitry Andric
4185868e8aSDimitry Andric // Skip if a local variable because we don't need them for generating
4285868e8aSDimitry Andric // error messages. In general, only non-local symbols can fail to be
4385868e8aSDimitry Andric // linked.
4485868e8aSDimitry Andric if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0))
4585868e8aSDimitry Andric continue;
4685868e8aSDimitry Andric
4785868e8aSDimitry Andric // Get the source filename index for the variable.
4885868e8aSDimitry Andric unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0);
4985868e8aSDimitry Andric if (!lt->hasFileAtIndex(file))
5085868e8aSDimitry Andric continue;
5185868e8aSDimitry Andric
5285868e8aSDimitry Andric // Get the line number on which the variable is declared.
5385868e8aSDimitry Andric unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0);
5485868e8aSDimitry Andric
5585868e8aSDimitry Andric // Here we want to take the variable name to add it into variableLoc.
5685868e8aSDimitry Andric // Variable can have regular and linkage name associated. At first, we try
5785868e8aSDimitry Andric // to get linkage name as it can be different, for example when we have
5885868e8aSDimitry Andric // two variables in different namespaces of the same object. Use common
5985868e8aSDimitry Andric // name otherwise, but handle the case when it also absent in case if the
6085868e8aSDimitry Andric // input object file lacks some debug info.
6185868e8aSDimitry Andric StringRef name =
6285868e8aSDimitry Andric dwarf::toString(die.find(dwarf::DW_AT_linkage_name),
6385868e8aSDimitry Andric dwarf::toString(die.find(dwarf::DW_AT_name), ""));
6485868e8aSDimitry Andric if (!name.empty())
6585868e8aSDimitry Andric variableLoc.insert({name, {lt, file, line}});
6685868e8aSDimitry Andric }
6785868e8aSDimitry Andric }
6885868e8aSDimitry Andric }
6985868e8aSDimitry Andric
7085868e8aSDimitry Andric // Returns the pair of file name and line number describing location of data
7185868e8aSDimitry Andric // object (variable, array, etc) definition.
72*bdd1243dSDimitry Andric std::optional<std::pair<std::string, unsigned>>
getVariableLoc(StringRef name)7385868e8aSDimitry Andric DWARFCache::getVariableLoc(StringRef name) {
7485868e8aSDimitry Andric // Return if we have no debug information about data object.
7585868e8aSDimitry Andric auto it = variableLoc.find(name);
7685868e8aSDimitry Andric if (it == variableLoc.end())
77*bdd1243dSDimitry Andric return std::nullopt;
7885868e8aSDimitry Andric
7985868e8aSDimitry Andric // Take file name string from line table.
8085868e8aSDimitry Andric std::string fileName;
8185868e8aSDimitry Andric if (!it->second.lt->getFileNameByIndex(
8285868e8aSDimitry Andric it->second.file, {},
8385868e8aSDimitry Andric DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName))
84*bdd1243dSDimitry Andric return std::nullopt;
8585868e8aSDimitry Andric
8685868e8aSDimitry Andric return std::make_pair(fileName, it->second.line);
8785868e8aSDimitry Andric }
8885868e8aSDimitry Andric
8985868e8aSDimitry Andric // Returns source line information for a given offset
9085868e8aSDimitry Andric // using DWARF debug info.
getDILineInfo(uint64_t offset,uint64_t sectionIndex)91*bdd1243dSDimitry Andric std::optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset,
9285868e8aSDimitry Andric uint64_t sectionIndex) {
9385868e8aSDimitry Andric DILineInfo info;
9485868e8aSDimitry Andric for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) {
9585868e8aSDimitry Andric if (lt->getFileLineInfoForAddress(
9685868e8aSDimitry Andric {offset, sectionIndex}, nullptr,
9785868e8aSDimitry Andric DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info))
9885868e8aSDimitry Andric return info;
9985868e8aSDimitry Andric }
100*bdd1243dSDimitry Andric return std::nullopt;
10185868e8aSDimitry Andric }
10285868e8aSDimitry Andric
10385868e8aSDimitry Andric } // namespace lld
104