diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index 22017f78013d6..591d0c83ad6a0 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -10,6 +10,7 @@ #define LLD_COFF_INPUT_FILES_H #include "Config.h" +#include "lld/Common/DWARF.h" #include "lld/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -258,6 +259,8 @@ class ObjFile : public InputFile { // index. Nonexistent indices (which are occupied by auxiliary // symbols in the real symbol table) are filled with null pointers. std::vector Symbols; + + DWARFCache *dwarf; }; // This type represents import library members that contain DLL names diff --git a/lld/Common/CMakeLists.txt b/lld/Common/CMakeLists.txt index 70849cc7b94b2..1a04a8074bed0 100644 --- a/lld/Common/CMakeLists.txt +++ b/lld/Common/CMakeLists.txt @@ -29,6 +29,7 @@ set_property(SOURCE Version.cpp APPEND PROPERTY add_lld_library(lldCommon Args.cpp + DWARF.cpp ErrorHandler.cpp Filesystem.cpp Memory.cpp @@ -46,6 +47,7 @@ add_lld_library(lldCommon LINK_COMPONENTS Codegen Core + DebugInfoDWARF Demangle MC Option diff --git a/lld/Common/DWARF.cpp b/lld/Common/DWARF.cpp new file mode 100644 index 0000000000000..077adbcaf8581 --- /dev/null +++ b/lld/Common/DWARF.cpp @@ -0,0 +1,103 @@ +//===- DWARF.cpp ----------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lld/Common/DWARF.h" +#include "lld/Common/ErrorHandler.h" + +using namespace llvm; + +namespace lld { + +DWARFCache::DWARFCache(std::unique_ptr d) + : dwarf(std::move(d)) { + for (std::unique_ptr &cu : dwarf->compile_units()) { + auto report = [](Error err) { + handleAllErrors(std::move(err), + [](ErrorInfoBase &info) { warn(info.message()); }); + }; + Expected expectedLT = + dwarf->getLineTableForUnit(cu.get(), report); + const DWARFDebugLine::LineTable *lt = nullptr; + if (expectedLT) + lt = *expectedLT; + else + report(expectedLT.takeError()); + if (!lt) + continue; + lineTables.push_back(lt); + + // Loop over variable records and insert them to variableLoc. + for (const auto &entry : cu->dies()) { + DWARFDie die(cu.get(), &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); + + // Here we want to take the variable name to add it into variableLoc. + // Variable can have regular and linkage name associated. At first, we try + // to get linkage name as it can be different, for example when we have + // two variables in different namespaces of the same object. Use common + // name otherwise, but handle the case when it also absent in case if the + // input object file lacks some debug info. + StringRef name = + dwarf::toString(die.find(dwarf::DW_AT_linkage_name), + dwarf::toString(die.find(dwarf::DW_AT_name), "")); + if (!name.empty()) + variableLoc.insert({name, {lt, file, line}}); + } + } +} + +// Returns the pair of file name and line number describing location of data +// object (variable, array, etc) definition. +Optional> +DWARFCache::getVariableLoc(StringRef name) { + // 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 (!it->second.lt->getFileNameByIndex( + it->second.file, {}, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) + return None; + + return std::make_pair(fileName, it->second.line); +} + +// Returns source line information for a given offset +// using DWARF debug info. +Optional DWARFCache::getDILineInfo(uint64_t offset, + uint64_t sectionIndex) { + DILineInfo info; + for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { + if (lt->getFileLineInfoForAddress( + {offset, sectionIndex}, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) + return info; + } + return None; +} + +} // namespace lld diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp index 9266320765aa6..90038ec2b6c0b 100644 --- a/lld/ELF/DWARF.cpp +++ b/lld/ELF/DWARF.cpp @@ -82,7 +82,7 @@ Optional LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, ArrayRef Rels) const { auto It = - llvm::bsearch(Rels, [=](const RelTy &A) { return Pos <= A.r_offset; }); + partition_point(Rels, [=](const RelTy &A) { return A.r_offset < Pos; }); if (It == Rels.end() || It->r_offset != Pos) return None; const RelTy &Rel = *It; @@ -110,7 +110,8 @@ LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, DataRefImpl D; D.p = getAddend(Rel); return RelocAddrEntry{SecIndex, RelocationRef(D, nullptr), - LLDRelocationResolver::Resolve, Val}; + Val, Optional(), + 0, LLDRelocationResolver::Resolve}; } template diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index d1a72f0adc4c2..13c1557069b1c 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -17,7 +17,6 @@ #include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/LTO/LTO.h" @@ -252,57 +251,8 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, } template void ObjFile::initializeDwarf() { - Dwarf = llvm::make_unique(make_unique>(this)); - for (std::unique_ptr &CU : Dwarf->compile_units()) { - auto Report = [](Error Err) { - handleAllErrors(std::move(Err), - [](ErrorInfoBase &Info) { warn(Info.message()); }); - }; - Expected ExpectedLT = - Dwarf->getLineTableForUnit(CU.get(), Report); - const DWARFDebugLine::LineTable *LT = nullptr; - if (ExpectedLT) - LT = *ExpectedLT; - else - Report(ExpectedLT.takeError()); - if (!LT) - continue; - LineTables.push_back(LT); - - // Loop over variable records and insert them to VariableLoc. - for (const auto &Entry : CU->dies()) { - DWARFDie Die(CU.get(), &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); - - // Here we want to take the variable name to add it into VariableLoc. - // Variable can have regular and linkage name associated. At first, we try - // to get linkage name as it can be different, for example when we have - // two variables in different namespaces of the same object. Use common - // name otherwise, but handle the case when it also absent in case if the - // input object file lacks some debug info. - StringRef Name = - dwarf::toString(Die.find(dwarf::DW_AT_linkage_name), - dwarf::toString(Die.find(dwarf::DW_AT_name), "")); - if (!Name.empty()) - VariableLoc.insert({Name, {LT, File, Line}}); - } - } + dwarf = make(std::make_unique( + std::make_unique>(this))); } // Returns the pair of file name and line number describing location of data @@ -312,19 +262,7 @@ Optional> ObjFile::getVariableLoc(StringRef Name) { llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); - // 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 (!It->second.LT->getFileNameByIndex( - It->second.File, nullptr, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) - return None; - - return std::make_pair(FileName, It->second.Line); + return dwarf->getVariableLoc(Name); } // Returns source line information for a given offset @@ -346,14 +284,7 @@ Optional ObjFile::getDILineInfo(InputSectionBase *S, // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. - DILineInfo Info; - for (const llvm::DWARFDebugLine::LineTable *LT : LineTables) { - if (LT->getFileLineInfoForAddress( - {S->getOffsetInFile() + Offset, SectionIndex}, nullptr, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info)) - return Info; - } - return None; + return dwarf->getDILineInfo(S->getOffsetInFile() + Offset, SectionIndex); } // Returns "", "foo.a(bar.o)" or "baz.o". @@ -466,9 +397,11 @@ template void ObjFile::parse(bool IgnoreComdats) { template StringRef ObjFile::getShtGroupSignature(ArrayRef Sections, const Elf_Shdr &Sec) { - const Elf_Sym *Sym = - CHECK(object::getSymbol(this->getELFSyms(), Sec.sh_info), this); - StringRef Signature = CHECK(Sym->getName(this->StringTable), this); + typename ELFT::SymRange Symbols = this->getELFSyms(); + if (Sec.sh_info >= Symbols.size()) + fatal(toString(this) + ": invalid symbol index"); + const typename ELFT::Sym &Sym = Symbols[Sec.sh_info]; + StringRef Signature = CHECK(Sym.getName(this->StringTable), this); // As a special case, if a symbol is a section symbol and has no name, // we use a section name as a signature. @@ -477,7 +410,7 @@ StringRef ObjFile::getShtGroupSignature(ArrayRef Sections, // standard, but GNU gold 1.14 (the newest version as of July 2017) or // older produce such sections as outputs for the -r option, so we need // a bug-compatibility. - if (Signature.empty() && Sym->getType() == STT_SECTION) + if (Signature.empty() && Sym.getType() == STT_SECTION) return getSectionName(Sec); return Signature; } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 588d59ab2351a..501c511523e68 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -10,13 +10,13 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" +#include "lld/Common/DWARF.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/IR/Comdat.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" @@ -26,7 +26,6 @@ namespace llvm { class TarWriter; -struct DILineInfo; namespace lto { class InputFile; } @@ -284,14 +283,7 @@ template class ObjFile : public ELFFileBase { // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. - std::unique_ptr Dwarf; - std::vector LineTables; - struct VarLoc { - const llvm::DWARFDebugLine::LineTable *LT; - unsigned File; - unsigned Line; - }; - llvm::DenseMap VariableLoc; + DWARFCache *dwarf; llvm::once_flag InitDwarfLine; }; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index d077c017ca718..8cb1e3e4fb22a 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1268,8 +1268,8 @@ SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to do a binary search of the original section piece vector. - auto It = llvm::bsearch(Pieces, - [=](SectionPiece P) { return Offset < P.InputOff; }); + auto It = partition_point( + Pieces, [=](SectionPiece P) { return P.InputOff <= Offset; }); return &It[-1]; } diff --git a/lld/include/lld/Common/DWARF.h b/lld/include/lld/Common/DWARF.h new file mode 100644 index 0000000000000..f0d3d2fbda775 --- /dev/null +++ b/lld/include/lld/Common/DWARF.h @@ -0,0 +1,47 @@ +//===- DWARF.h --------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_DWARF_H +#define LLD_DWARF_H + +#include "lld/Common/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include +#include + +namespace llvm { +struct DILineInfo; +} // namespace llvm + +namespace lld { + +class DWARFCache { +public: + DWARFCache(std::unique_ptr dwarf); + llvm::Optional getDILineInfo(uint64_t offset, + uint64_t sectionIndex); + llvm::Optional> + getVariableLoc(StringRef name); + +private: + std::unique_ptr dwarf; + std::vector lineTables; + struct VarLoc { + const llvm::DWARFDebugLine::LineTable *lt; + unsigned file; + unsigned line; + }; + llvm::DenseMap variableLoc; +}; + +} // namespace lld + +#endif diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 879f07fb4760c..bcddb977b0239 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -832,10 +832,10 @@ dataExtractorFromSection(const NormalizedFile &normalizedFile, // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE // inspection" code if possible. -static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData, +static uint64_t getCUAbbrevOffset(llvm::DataExtractor abbrevData, uint64_t abbrCode) { uint64_t curCode; - uint32_t offset = 0; + uint64_t offset = 0; while ((curCode = abbrevData.getULEB128(&offset)) != abbrCode) { // Tag abbrevData.getULEB128(&offset); @@ -853,13 +853,13 @@ static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData, static Expected getIndexedString(const NormalizedFile &normalizedFile, llvm::dwarf::Form form, llvm::DataExtractor infoData, - uint32_t &infoOffset, const Section &stringsSection) { + uint64_t &infoOffset, const Section &stringsSection) { if (form == llvm::dwarf::DW_FORM_string) return infoData.getCStr(&infoOffset); if (form != llvm::dwarf::DW_FORM_strp) return llvm::make_error( "string field encoded without DW_FORM_strp"); - uint32_t stringOffset = infoData.getU32(&infoOffset); + uint64_t stringOffset = infoData.getU32(&infoOffset); llvm::DataExtractor stringsData = dataExtractorFromSection(normalizedFile, stringsSection); return stringsData.getCStr(&stringOffset); @@ -875,7 +875,7 @@ readCompUnit(const NormalizedFile &normalizedFile, StringRef path) { // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE // inspection" code if possible. - uint32_t offset = 0; + uint64_t offset = 0; llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::DWARF32; auto infoData = dataExtractorFromSection(normalizedFile, info); uint32_t length = infoData.getU32(&offset); @@ -897,7 +897,7 @@ readCompUnit(const NormalizedFile &normalizedFile, uint32_t abbrCode = infoData.getULEB128(&offset); auto abbrevData = dataExtractorFromSection(normalizedFile, abbrev); - uint32_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode); + uint64_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode); uint64_t tag = abbrevData.getULEB128(&abbrevOffset); if (tag != llvm::dwarf::DW_TAG_compile_unit) return llvm::make_error("top level DIE is not a compile unit");