diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:45 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:45 +0000 |
commit | d2bd9e70b16db88a7808ee2280b0a107afbfdd3b (patch) | |
tree | 12612d2c593445b297ac656911c9db7cf9065bdd /Common | |
parent | f1e1c239e31b467e17f1648b1f524fc9ab5b431a (diff) | |
download | src-vendor/lld.tar.gz src-vendor/lld.zip |
Vendor import of stripped lld trunk r375505, the last commit before thevendor/lld/lld-trunk-r375505vendor/lld
upstream Subversion repository was made read-only, and the LLVM project
migrated to GitHub:
https://llvm.org/svn/llvm-project/lld/trunk@375505
Notes
Notes:
svn path=/vendor/lld/dist/; revision=353950
svn path=/vendor/lld/lld-r375505/; revision=353951; tag=vendor/lld/lld-trunk-r375505
Diffstat (limited to 'Common')
-rw-r--r-- | Common/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Common/DWARF.cpp | 103 | ||||
-rw-r--r-- | Common/ErrorHandler.cpp | 139 | ||||
-rw-r--r-- | Common/Strings.cpp | 34 | ||||
-rw-r--r-- | Common/TargetOptionsCommandFlags.cpp | 4 |
5 files changed, 200 insertions, 82 deletions
diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index 70849cc7b94b..1a04a8074bed 100644 --- a/Common/CMakeLists.txt +++ b/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/Common/DWARF.cpp b/Common/DWARF.cpp new file mode 100644 index 000000000000..077adbcaf858 --- /dev/null +++ b/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<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 diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp index c87c0609b260..b91854c51cef 100644 --- a/Common/ErrorHandler.cpp +++ b/Common/ErrorHandler.cpp @@ -29,16 +29,14 @@ using namespace lld; // but outs() or errs() are not thread-safe. We protect them using a mutex. static std::mutex mu; -// Prints "\n" or does nothing, depending on Msg contents of -// the previous call of this function. -static void newline(raw_ostream *errorOS, const Twine &msg) { - // True if the previous error message contained "\n". - // We want to separate multi-line error messages with a newline. - static bool flag; - - if (flag) - *errorOS << "\n"; - flag = StringRef(msg.str()).contains('\n'); +// We want to separate multi-line messages with a newline. `sep` is "\n" +// if the last messages was multi-line. Otherwise "". +static StringRef sep; + +static StringRef getSeparator(const Twine &msg) { + if (StringRef(msg.str()).contains('\n')) + return "\n"; + return ""; } ErrorHandler &lld::errorHandler() { @@ -46,6 +44,10 @@ ErrorHandler &lld::errorHandler() { return handler; } +void lld::enableColors(bool enable) { + errorHandler().errorOS->enable_colors(enable); +} + void lld::exitLld(int val) { // Delete any temporary file, while keeping the memory mapping open. if (errorHandler().outputBuffer) @@ -85,56 +87,69 @@ void lld::checkError(Error e) { [&](ErrorInfoBase &eib) { error(eib.message()); }); } -static std::string getLocation(std::string msg, std::string defaultMsg) { - static std::vector<std::regex> Regexes{ - std::regex(R"(^undefined symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"), +// This is for --vs-diagnostics. +// +// Normally, lld's error message starts with argv[0]. Therefore, it usually +// looks like this: +// +// ld.lld: error: ... +// +// This error message style is unfortunately unfriendly to Visual Studio +// IDE. VS interprets the first word of the first line as an error location +// and make it clickable, thus "ld.lld" in the above message would become a +// clickable text. When you click it, VS opens "ld.lld" executable file with +// a binary editor. +// +// As a workaround, we print out an error location instead of "ld.lld" if +// lld is running in VS diagnostics mode. As a result, error message will +// look like this: +// +// src/foo.c(35): error: ... +// +// This function returns an error location string. An error location is +// extracted from an error message using regexps. +std::string ErrorHandler::getLocation(const Twine &msg) { + if (!vsDiagnostics) + return logName; + + static std::regex regexes[] = { + std::regex( + R"(^undefined (?:\S+ )?symbol:.*\n)" + R"(>>> referenced by .+\((\S+):(\d+)\))"), + std::regex( + R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"), std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), std::regex( R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), std::regex( - R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"), - std::regex( - R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), + R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"), + std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"), std::regex( - R"(^undefined (internal|hidden|protected) symbol: .*\n>>> referenced by (\S+):(\d+)\n.*)"), + R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"), + std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), std::regex(R"((\S+):(\d+): unclosed quote)"), }; - std::smatch Match; - for (std::regex &Re : Regexes) { - if (std::regex_search(msg, Match, Re)) { - return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")" - : Match.str(1); - } - } - return defaultMsg; -} - -void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c, - const Twine &msg) { + std::string str = msg.str(); + for (std::regex &re : regexes) { + std::smatch m; + if (!std::regex_search(str, m, re)) + continue; - if (vsDiagnostics) { - // A Visual Studio-style error message starts with an error location. - // If a location cannot be extracted then we default to LogName. - *errorOS << getLocation(msg.str(), logName) << ": "; - } else { - *errorOS << logName << ": "; + assert(m.size() == 2 || m.size() == 3); + if (m.size() == 2) + return m.str(1); + return m.str(1) + "(" + m.str(2) + ")"; } - if (colorDiagnostics) { - errorOS->changeColor(c, true); - *errorOS << s; - errorOS->resetColor(); - } else { - *errorOS << s; - } + return logName; } void ErrorHandler::log(const Twine &msg) { - if (verbose) { - std::lock_guard<std::mutex> lock(mu); - *errorOS << logName << ": " << msg << "\n"; - } + if (!verbose) + return; + std::lock_guard<std::mutex> lock(mu); + *errorOS << logName << ": " << msg << "\n"; } void ErrorHandler::message(const Twine &msg) { @@ -150,25 +165,41 @@ void ErrorHandler::warn(const Twine &msg) { } std::lock_guard<std::mutex> lock(mu); - newline(errorOS, msg); - printHeader("warning: ", raw_ostream::MAGENTA, msg); - *errorOS << msg << "\n"; + *errorOS << sep << getLocation(msg) << ": " << Colors::MAGENTA + << "warning: " << Colors::RESET << msg << "\n"; + sep = getSeparator(msg); } void ErrorHandler::error(const Twine &msg) { + // If Visual Studio-style error message mode is enabled, + // this particular error is printed out as two errors. + if (vsDiagnostics) { + static std::regex re(R"(^(duplicate symbol: .*))" + R"((\n>>> defined at \S+:\d+.*\n>>>.*))" + R"((\n>>> defined at \S+:\d+.*\n>>>.*))"); + std::string str = msg.str(); + std::smatch m; + + if (std::regex_match(str, m, re)) { + error(m.str(1) + m.str(2)); + error(m.str(1) + m.str(3)); + return; + } + } + std::lock_guard<std::mutex> lock(mu); - newline(errorOS, msg); if (errorLimit == 0 || errorCount < errorLimit) { - printHeader("error: ", raw_ostream::RED, msg); - *errorOS << msg << "\n"; + *errorOS << sep << getLocation(msg) << ": " << Colors::RED + << "error: " << Colors::RESET << msg << "\n"; } else if (errorCount == errorLimit) { - printHeader("error: ", raw_ostream::RED, msg); - *errorOS << errorLimitExceededMsg << "\n"; + *errorOS << sep << getLocation(msg) << ": " << Colors::RED + << "error: " << Colors::RESET << errorLimitExceededMsg << "\n"; if (exitEarly) exitLld(1); } + sep = getSeparator(msg); ++errorCount; } diff --git a/Common/Strings.cpp b/Common/Strings.cpp index 0bf06626cc7a..627435f141da 100644 --- a/Common/Strings.cpp +++ b/Common/Strings.cpp @@ -18,39 +18,17 @@ using namespace llvm; using namespace lld; -// Returns the demangled C++ symbol name for Name. -Optional<std::string> lld::demangleItanium(StringRef name) { +// Returns the demangled C++ symbol name for name. +std::string lld::demangleItanium(StringRef name) { // itaniumDemangle can be used to demangle strings other than symbol // names which do not necessarily start with "_Z". Name can be - // either a C or C++ symbol. Don't call itaniumDemangle if the name + // either a C or C++ symbol. Don't call demangle if the name // does not look like a C++ symbol name to avoid getting unexpected // result for a C symbol that happens to match a mangled type name. if (!name.startswith("_Z")) - return None; + return name; - char *buf = itaniumDemangle(name.str().c_str(), nullptr, nullptr, nullptr); - if (!buf) - return None; - std::string s(buf); - free(buf); - return s; -} - -Optional<std::string> lld::demangleMSVC(StringRef name) { - std::string prefix; - if (name.consume_front("__imp_")) - prefix = "__declspec(dllimport) "; - - // Demangle only C++ names. - if (!name.startswith("?")) - return None; - - char *buf = microsoftDemangle(name.str().c_str(), nullptr, nullptr, nullptr); - if (!buf) - return None; - std::string s(buf); - free(buf); - return prefix + s; + return demangle(name); } StringMatcher::StringMatcher(ArrayRef<StringRef> pat) { @@ -96,7 +74,7 @@ bool lld::isValidCIdentifier(StringRef s) { // Write the contents of the a buffer to a file void lld::saveBuffer(StringRef buffer, const Twine &path) { std::error_code ec; - raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::F_None); + raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::OF_None); if (ec) error("cannot create " + path + ": " + ec.message()); os << buffer; diff --git a/Common/TargetOptionsCommandFlags.cpp b/Common/TargetOptionsCommandFlags.cpp index d4c29d7f88b8..0137feb63f37 100644 --- a/Common/TargetOptionsCommandFlags.cpp +++ b/Common/TargetOptionsCommandFlags.cpp @@ -26,6 +26,10 @@ llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() { return ::InitTargetOptionsFromCodeGenFlags(); } +llvm::Optional<llvm::Reloc::Model> lld::getRelocModelFromCMModel() { + return getRelocModel(); +} + llvm::Optional<llvm::CodeModel::Model> lld::getCodeModelFromCMModel() { return getCodeModel(); } |