Skip to content

LLD cherry-picks #26

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lld/COFF/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<Symbol *> Symbols;

DWARFCache *dwarf;
};

// This type represents import library members that contain DLL names
Expand Down
2 changes: 2 additions & 0 deletions lld/Common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -46,6 +47,7 @@ add_lld_library(lldCommon
LINK_COMPONENTS
Codegen
Core
DebugInfoDWARF
Demangle
MC
Option
Expand Down
103 changes: 103 additions & 0 deletions lld/Common/DWARF.cpp
Original file line number Diff line number Diff line change
@@ -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<llvm::DWARFContext> d)
: dwarf(std::move(d)) {
for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) {
auto report = [](Error err) {
handleAllErrors(std::move(err),
[](ErrorInfoBase &info) { warn(info.message()); });
};
Expected<const DWARFDebugLine::LineTable *> 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<std::pair<std::string, unsigned>>
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<DILineInfo> 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
5 changes: 3 additions & 2 deletions lld/ELF/DWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Optional<RelocAddrEntry>
LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos,
ArrayRef<RelTy> 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;
Expand Down Expand Up @@ -110,7 +110,8 @@ LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos,
DataRefImpl D;
D.p = getAddend<ELFT>(Rel);
return RelocAddrEntry{SecIndex, RelocationRef(D, nullptr),
LLDRelocationResolver<RelTy>::Resolve, Val};
Val, Optional<object::RelocationRef>(),
0, LLDRelocationResolver<RelTy>::Resolve};
}

template <class ELFT>
Expand Down
87 changes: 10 additions & 77 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -252,57 +251,8 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
}

template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
for (std::unique_ptr<DWARFUnit> &CU : Dwarf->compile_units()) {
auto Report = [](Error Err) {
handleAllErrors(std::move(Err),
[](ErrorInfoBase &Info) { warn(Info.message()); });
};
Expected<const DWARFDebugLine::LineTable *> 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<DWARFCache>(std::make_unique<DWARFContext>(
std::make_unique<LLDDwarfObj<ELFT>>(this)));
}

// Returns the pair of file name and line number describing location of data
Expand All @@ -312,19 +262,7 @@ Optional<std::pair<std::string, unsigned>>
ObjFile<ELFT>::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
Expand All @@ -346,14 +284,7 @@ Optional<DILineInfo> ObjFile<ELFT>::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 "<internal>", "foo.a(bar.o)" or "baz.o".
Expand Down Expand Up @@ -466,9 +397,11 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool IgnoreComdats) {
template <class ELFT>
StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec) {
const Elf_Sym *Sym =
CHECK(object::getSymbol<ELFT>(this->getELFSyms<ELFT>(), Sec.sh_info), this);
StringRef Signature = CHECK(Sym->getName(this->StringTable), this);
typename ELFT::SymRange Symbols = this->getELFSyms<ELFT>();
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.
Expand All @@ -477,7 +410,7 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> 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;
}
Expand Down
12 changes: 2 additions & 10 deletions lld/ELF/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -26,7 +26,6 @@

namespace llvm {
class TarWriter;
struct DILineInfo;
namespace lto {
class InputFile;
}
Expand Down Expand Up @@ -284,14 +283,7 @@ template <class ELFT> 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<llvm::DWARFContext> Dwarf;
std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables;
struct VarLoc {
const llvm::DWARFDebugLine::LineTable *LT;
unsigned File;
unsigned Line;
};
llvm::DenseMap<StringRef, VarLoc> VariableLoc;
DWARFCache *dwarf;
llvm::once_flag InitDwarfLine;
};

Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}

Expand Down
47 changes: 47 additions & 0 deletions lld/include/lld/Common/DWARF.h
Original file line number Diff line number Diff line change
@@ -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 <memory>
#include <string>

namespace llvm {
struct DILineInfo;
} // namespace llvm

namespace lld {

class DWARFCache {
public:
DWARFCache(std::unique_ptr<llvm::DWARFContext> dwarf);
llvm::Optional<llvm::DILineInfo> getDILineInfo(uint64_t offset,
uint64_t sectionIndex);
llvm::Optional<std::pair<std::string, unsigned>>
getVariableLoc(StringRef name);

private:
std::unique_ptr<llvm::DWARFContext> dwarf;
std::vector<const llvm::DWARFDebugLine::LineTable *> lineTables;
struct VarLoc {
const llvm::DWARFDebugLine::LineTable *lt;
unsigned file;
unsigned line;
};
llvm::DenseMap<StringRef, VarLoc> variableLoc;
};

} // namespace lld

#endif
Loading