xref: /freebsd/contrib/llvm-project/lld/Common/DWARF.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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