From 83ba3ea53f20e2d08a543b4c7c897cff485a64cd Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 30 Jun 2019 11:19:56 +0000 Subject: [PATCH 1/5] Cleanup: llvm::bsearch -> llvm::partition_point after r364719 llvm-svn: 364720 (cherry picked from commit 78ee2fbf984b84db814bf7b3a68e2317e32b1a24) (cherry picked from commit c0dce9142114448f7bff085103f9518bf8946509) --- lld/ELF/DWARF.cpp | 2 +- lld/ELF/InputSection.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp index 9266320765aa6..3c2c7f70f2c26 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; 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]; } From 2ca03711f9ca9adaa908b51a1b0779dd8caa2d3e Mon Sep 17 00:00:00 2001 From: George Rimar Date: Mon, 15 Jul 2019 11:47:54 +0000 Subject: [PATCH 2/5] [LLD][ELF] - Minor simplification. NFC. This removes a call to `object::getSymbol`. We used this function in a next way: it was given an array of symbols and index and returned either a symbol at the index given or a error. This function was removed in D64631. (rL366052, but was reverted because of LLD compilation error that I didn't know about). It does not make much sense to keep this function on LLVM side only for LLD, because having only a list of symbols and the index it is not able to produce a valueable error message about context anyways. llvm-svn: 366057 (cherry picked from commit 8d9b9f6bf2cde253ff89369399a45172b10af512) (cherry picked from commit 966b3d34e8f8242f34457682dc723a039a74dfe1) --- lld/ELF/InputFiles.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index d1a72f0adc4c2..af9c800164baf 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -466,9 +466,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 +479,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; } From e90a08dcef8fc46c2bac8ee850ed717a11555c80 Mon Sep 17 00:00:00 2001 From: Alex Bradbury Date: Thu, 18 Jul 2019 05:22:55 +0000 Subject: [PATCH 3/5] [DWARF][RISCV] Add support for RISC-V relocations needed for debug info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When code relaxation is enabled many RISC-V fixups are not resolved but instead relocations are emitted. This happens even for DWARF debug sections. Therefore, to properly support the parsing of DWARF debug info we need to be able to resolve RISC-V relocations. This patch adds: * Support for RISC-V relocations in RelocationResolver * DWARF support for two relocations per object file offset * DWARF changes to support relocations in more DIE fields The two relocations per offset change is needed because some RISC-V relocations (used for label differences) come in pairs. Relocations can also be emitted for DWARF fields where relocations were not yet evaluated. Adding relocation support for some of these fields is essencial. On the other hand, LLVM currently emits RISC-V relocations for fixups that could be safely evaluated, since they can never be affected by code relaxations. This patch also adds relocation support for the fields affected by those extraneous relocations (the DWARF unit entry Length, and the DWARF debug line entry TotalLength and PrologueLength), for testing purposes. Differential Revision: https://reviews.llvm.org/D62062 Patch by Luís Marques. llvm-svn: 366402 (cherry picked from commit 44deaf7e54ef55a55965f0c5cf41d4436120f75f) (cherry picked from commit c2a99c62e98a545ab8fadcfa003df5075e9f4380) --- lld/ELF/DWARF.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp index 3c2c7f70f2c26..90038ec2b6c0b 100644 --- a/lld/ELF/DWARF.cpp +++ b/lld/ELF/DWARF.cpp @@ -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 From b9e581235e4866228994e3a1e3c97b5e1ad6ba7d Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Tue, 6 Aug 2019 13:37:34 +0000 Subject: [PATCH 4/5] [MachO] Update LLD to use 64-bit offsets with DataExtractor (3/5) Differential Revision: https://reviews.llvm.org/D65639 llvm-svn: 368032 (cherry picked from commit 5978c9249bbfc544814621234504fc55fc4d3d18) (cherry picked from commit 0fba2cc25a68a3eb3ef625f9c6cc3664318c5033) --- .../MachO/MachONormalizedFileToAtoms.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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"); From fe690a890aaaf336d09aaa65511db375bc92f438 Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Mon, 21 Oct 2019 08:01:52 +0000 Subject: [PATCH 5/5] [LLD] Move duplicated dwarf parsing code to the Common library. NFC. Differential Revision: https://reviews.llvm.org/D69197 llvm-svn: 375390 (cherry picked from commit 908b780952d965d344b7fd85358d933272922c10) (cherry picked from commit a18630d8a3a9bce3e9012744de371a5d5768f2db) --- lld/COFF/InputFiles.h | 3 + lld/Common/CMakeLists.txt | 2 + lld/Common/DWARF.cpp | 103 +++++++++++++++++++++++++++++++++ lld/ELF/InputFiles.cpp | 77 ++---------------------- lld/ELF/InputFiles.h | 12 +--- lld/include/lld/Common/DWARF.h | 47 +++++++++++++++ 6 files changed, 161 insertions(+), 83 deletions(-) create mode 100644 lld/Common/DWARF.cpp create mode 100644 lld/include/lld/Common/DWARF.h 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/InputFiles.cpp b/lld/ELF/InputFiles.cpp index af9c800164baf..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". 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/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