Index: Common/ErrorHandler.cpp =================================================================== --- Common/ErrorHandler.cpp +++ Common/ErrorHandler.cpp @@ -84,8 +84,10 @@ [&](ErrorInfoBase &EIB) { error(EIB.message()); }); } -void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << LogName << ": "; +void ErrorHandler::print(const Twine &Orig, StringRef S, raw_ostream::Colors C, + const Twine &Msg) { + newline(ErrorOS, Msg); + *ErrorOS << Orig << ": "; if (ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -93,12 +95,13 @@ } else { *ErrorOS << S; } + *ErrorOS << Msg << "\n"; } -void ErrorHandler::log(const Twine &Msg) { +void ErrorHandler::log(const Twine &Orig, const Twine &Msg) { if (Verbose) { std::lock_guard Lock(Mu); - *ErrorOS << LogName << ": " << Msg << "\n"; + *ErrorOS << Orig << ": " << Msg << "\n"; } } @@ -108,28 +111,22 @@ outs().flush(); } -void ErrorHandler::warn(const Twine &Msg) { +void ErrorHandler::warn(const Twine &Orig, const Twine &Msg) { if (FatalWarnings) { - error(Msg); + error(Orig, Msg); return; } - std::lock_guard Lock(Mu); - newline(ErrorOS, Msg); - print("warning: ", raw_ostream::MAGENTA); - *ErrorOS << Msg << "\n"; + print(Orig, "warning: ", raw_ostream::MAGENTA, Msg); } -void ErrorHandler::error(const Twine &Msg) { +void ErrorHandler::error(const Twine &Orig, const Twine &Msg) { std::lock_guard Lock(Mu); - newline(ErrorOS, Msg); - if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << Msg << "\n"; - } else if (ErrorCount == ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << ErrorLimitExceededMsg << "\n"; + if (ErrorLimit == 0 || ErrorCount < ErrorLimit) + print(Orig, "error: ", raw_ostream::RED, Msg); + else if (ErrorCount == ErrorLimit) { + print(LogName, "error: ", raw_ostream::RED, ErrorLimitExceededMsg); if (ExitEarly) exitLld(1); } @@ -137,7 +134,7 @@ ++ErrorCount; } -void ErrorHandler::fatal(const Twine &Msg) { - error(Msg); +void ErrorHandler::fatal(const Twine &Orig, const Twine &Msg) { + error(Orig, Msg); exitLld(1); } Index: ELF/CMakeLists.txt =================================================================== --- ELF/CMakeLists.txt +++ ELF/CMakeLists.txt @@ -22,6 +22,7 @@ Arch/X86.cpp Arch/X86_64.cpp CallGraphSort.cpp + Diagnostics.cpp Driver.cpp DriverUtils.cpp EhFrame.cpp Index: ELF/Diagnostics.h =================================================================== --- /dev/null +++ ELF/Diagnostics.h @@ -0,0 +1,122 @@ +//===- Diagnostics.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_DIAGNOSTICS_H +#define LLD_ELF_DIAGNOSTICS_H + +#include "Config.h" +#include "lld/Common/LLVM.h" +#include "llvm/ADT/Optional.h" + +namespace lld { +namespace elf { + +class Symbol; + +struct ObjLocation { + StringRef Archive; + StringRef File; + StringRef Sec; + uint64_t Off = 0; + std::string Sym; +}; + +ObjLocation makeSymbolObjLocation(StringRef Archive, StringRef File, + StringRef Sym); +ObjLocation makeSectionObjLocation(StringRef Archive, StringRef File, + StringRef Sec, uint64_t Off); + +struct SrcLocation { + std::string Path; // see createFileLineMsg for using of path::filename(Path); + llvm::Optional Line; +}; + +SrcLocation makeSrcLocation(StringRef File, unsigned Line); +SrcLocation makeSrcLocationOnlyFile(StringRef File); + +struct SymbolLocation { + SymbolLocation(const ObjLocation &ObjLoc) : ObjLoc(ObjLoc) {} + SymbolLocation(const ObjLocation &ObjLoc, + const llvm::Optional &SrcLoc) + : ObjLoc(ObjLoc), SrcLoc(SrcLoc) {} + ObjLocation ObjLoc; + llvm::Optional SrcLoc; +}; + +struct ReferencingSymbolLocation { + explicit ReferencingSymbolLocation(const SymbolLocation &SymLoc) + : SymLoc(SymLoc) {} + ReferencingSymbolLocation & + operator=(const ReferencingSymbolLocation &) = delete; + const SymbolLocation &SymLoc; +}; + +struct DefinedSymbolLocation { + explicit DefinedSymbolLocation(const SymbolLocation &SymLoc) + : SymLoc(SymLoc) {} + DefinedSymbolLocation &operator=(const DefinedSymbolLocation &) = delete; + const SymbolLocation &SymLoc; +}; + +inline ReferencingSymbolLocation referencedBy(const SymbolLocation &SymLoc) { + return ReferencingSymbolLocation(SymLoc); +} + +inline DefinedSymbolLocation definedAt(const SymbolLocation &SymLoc) { + return DefinedSymbolLocation(SymLoc); +} + +class DiagnosticCollector { +public: + DiagnosticCollector(const Twine &Msg, const ReferencingSymbolLocation &Loc) + : Msg(Msg), Referenced(&(Loc.SymLoc)) {} + DiagnosticCollector(const Twine &Msg, const DefinedSymbolLocation &Loc) + : Msg(Msg) { + Defined[0] = &(Loc.SymLoc); + } + DiagnosticCollector &operator=(const DiagnosticCollector &) = delete; + + DiagnosticCollector &operator+(const ReferencingSymbolLocation &Loc); + DiagnosticCollector &operator+(const DefinedSymbolLocation &Loc); + + const Twine &Msg; + const SymbolLocation *Referenced = 0; + const SymbolLocation *Defined[2] = {0, 0}; +}; + +inline DiagnosticCollector operator+(const Twine &Msg, + const ReferencingSymbolLocation &Loc) { + return DiagnosticCollector(Msg, Loc); +} + +inline DiagnosticCollector operator+(const Twine &Msg, + const DefinedSymbolLocation &Loc) { + return DiagnosticCollector(Msg, Loc); +} + +class Diagnostics { +public: + bool VSDiagnostics = false; + + void warn(const DiagnosticCollector &Msg); + void error(const DiagnosticCollector &Msg); + void errorOrWarn(const DiagnosticCollector &Msg) { + if (!Config->NoinhibitExec) + error(Msg); + else + warn(Msg); + } +}; + +extern Diagnostics *Diag; + +} // namespace elf +} // namespace lld + +#endif Index: ELF/Diagnostics.cpp =================================================================== --- /dev/null +++ ELF/Diagnostics.cpp @@ -0,0 +1,218 @@ +//===- Diagnostics.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// TBD +// +//===----------------------------------------------------------------------===// + +#include "Diagnostics.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Support/Path.h" + +using namespace lld; +using namespace lld::elf; + +Diagnostics *elf::Diag; + +ObjLocation elf::makeSymbolObjLocation(StringRef Archive, StringRef File, + StringRef Sym) { + ObjLocation Result; + Result.Archive = Archive; + Result.File = File; + Result.Sym = Sym; + return Result; +} + +ObjLocation elf::makeSectionObjLocation(StringRef Archive, StringRef File, + StringRef Sec, uint64_t Off) { + ObjLocation Result; + Result.Archive = Archive; + Result.File = File; + Result.Sec = Sec; + Result.Off = Off; + return Result; +} + +SrcLocation elf::makeSrcLocation(StringRef File, unsigned Line) { + SrcLocation Result; + Result.Path = File.str(); + Result.Line = Line; + return Result; +} + +SrcLocation elf::makeSrcLocationOnlyFile(StringRef File) { + SrcLocation Result; + Result.Path = File.str(); + return Result; +} + +DiagnosticCollector &DiagnosticCollector:: +operator+(const ReferencingSymbolLocation &Loc) { + assert(!Referenced && + "We do not expect to see a referencing location more than once."); + Referenced = &(Loc.SymLoc); + return *this; +} + +DiagnosticCollector &DiagnosticCollector:: +operator+(const DefinedSymbolLocation &Loc) { + assert( + !Defined[1] && + "We are not ready to see a symbol definition location more than twice."); + if (Defined[0]) + Defined[1] = &(Loc.SymLoc); + else + Defined[0] = &(Loc.SymLoc); + return *this; +} + +static unsigned reportCount(const DiagnosticCollector &C) { + if (Diag->VSDiagnostics && C.Defined[1]) + return 2; + return 1; +} + +static bool hasDetails(const ObjLocation &ObjLoc) { + return !ObjLoc.Sym.empty() || !ObjLoc.Sec.empty(); +} + +static bool hasDetails(const SrcLocation &SrcLoc) { + return SrcLoc.Line.hasValue(); +} + +// Based on createFileLineMsg (InputFiles.cpp) +static std::string getNativeSrcLocTxt(const SrcLocation &SrcLoc) { + if (!hasDetails(SrcLoc)) + return SrcLoc.Path; + std::string Filename = llvm::sys::path::filename(SrcLoc.Path); + std::string Lineno = ":" + std::to_string(SrcLoc.Line.getValue()); + if (Filename == SrcLoc.Path) + return Filename + Lineno; + return Filename + Lineno + " (" + SrcLoc.Path + Lineno + ")"; +} + +static std::string getVSSrcLocTxt(const SrcLocation &SrcLoc) { + if (!hasDetails(SrcLoc)) + return SrcLoc.Path; + return SrcLoc.Path + "(" + std::to_string(SrcLoc.Line.getValue()) + ")"; +} + +static std::string getOrig(const DiagnosticCollector &C, unsigned index) { + if (!Diag->VSDiagnostics) + return errorHandler().LogName; + const SymbolLocation *Loc = C.Referenced ? C.Referenced : C.Defined[index]; + if (!Loc || !Loc->SrcLoc || !hasDetails(Loc->SrcLoc.getValue())) + return errorHandler().LogName; + return getVSSrcLocTxt(Loc->SrcLoc.getValue()); +} + +// Based on InputSectionBase::getObjMsg() +static std::string getObjLocTxt(const ObjLocation &ObjLoc) { + std::string Details; + if (!ObjLoc.Sym.empty()) + Details = ":(" + ObjLoc.Sym + ")"; + else if (!ObjLoc.Sec.empty()) + Details = + (":(" + ObjLoc.Sec + "+0x" + llvm::utohexstr(ObjLoc.Off) + ")").str(); + + if (ObjLoc.Archive.empty()) + return (ObjLoc.File + Details).str(); + + if (Details.empty()) + return (ObjLoc.Archive + "(" + ObjLoc.File + ")").str(); + + return (ObjLoc.File + Details + " in archive " + ObjLoc.Archive).str(); +} + +static std::string getNativeDefinedTxt(const SymbolLocation *SymLoc) { + std::string Result; + if (!SymLoc) + return Result; + + if ((SymLoc->SrcLoc && hasDetails(SymLoc->SrcLoc.getValue())) || + (!SymLoc->SrcLoc && hasDetails(SymLoc->ObjLoc))) + Result = "\n>>> defined at "; + else + Result = "\n>>> defined in "; + + if (SymLoc->SrcLoc) + Result += + getNativeSrcLocTxt(SymLoc->SrcLoc.getValue()) + "\n>>> "; + + Result += getObjLocTxt(SymLoc->ObjLoc); + return Result; +} + +static std::string getVSDefinedTxt(const SymbolLocation *SymLoc) { + std::string Result; + if (!SymLoc) + return Result; + + // if the source location with a line number exists, it is already printed + // in the front of the message. + if (SymLoc->SrcLoc && !hasDetails(SymLoc->SrcLoc.getValue())) + Result += "\n>>> defined in " + getVSSrcLocTxt(SymLoc->SrcLoc.getValue()) + + "\n>>> "; + else if (hasDetails(SymLoc->ObjLoc)) + Result = "\n>>> defined at "; + else + Result = "\n>>> defined in "; + + Result += getObjLocTxt(SymLoc->ObjLoc); + return Result; +} + +static std::string getNativeReferencedTxt(const SymbolLocation *SymLoc) { + std::string Result; + if (!SymLoc) + return Result; + + Result = "\n>>> referenced by "; + if (SymLoc->SrcLoc) + Result += + getNativeSrcLocTxt(SymLoc->SrcLoc.getValue()) + "\n>>> "; + Result += getObjLocTxt(SymLoc->ObjLoc); + return Result; +} + +static std::string getVSReferencedTxt(const SymbolLocation *SymLoc) { + std::string Result; + if (!SymLoc) + return Result; + + Result = "\n>>> referenced by "; + // if the source location with a line number exists, it is already printed + // in the front of the message. + if (SymLoc->SrcLoc && !hasDetails(SymLoc->SrcLoc.getValue())) + Result += + getVSSrcLocTxt(SymLoc->SrcLoc.getValue()) + "\n>>> "; + Result += getObjLocTxt(SymLoc->ObjLoc); + return Result; +} + +static std::string getMsg(const DiagnosticCollector &C, unsigned index) { + if (!Diag->VSDiagnostics) + return (C.Msg + getNativeDefinedTxt(C.Defined[0]) + + getNativeDefinedTxt(C.Defined[1]) + + getNativeReferencedTxt(C.Referenced)) + .str(); + return (C.Msg + getVSDefinedTxt(C.Defined[index]) + + getVSReferencedTxt(C.Referenced)) + .str(); +} + +void Diagnostics::warn(const DiagnosticCollector &C) { + for (unsigned I = 0; I < reportCount(C); ++I) + errorHandler().warn(getOrig(C, I), getMsg(C, I)); +} + +void Diagnostics::error(const DiagnosticCollector &C) { + for (unsigned I = 0; I < reportCount(C); ++I) + errorHandler().error(getOrig(C, I), getMsg(C, I)); +} Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -25,6 +25,7 @@ #include "Driver.h" #include "Config.h" +#include "Diagnostics.h" #include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" @@ -91,6 +92,7 @@ SharedFiles.clear(); Config = make(); + Diag = make(); Driver = make(); Script = make(); Symtab = make(); @@ -725,6 +727,7 @@ errorHandler().FatalWarnings = Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + Diag->VSDiagnostics = Args.hasArg(OPT_visual_studio_diagnostics_format); Config->AllowMultipleDefinition = Args.hasFlag(OPT_allow_multiple_definition, Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -11,6 +11,7 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" +#include "Diagnostics.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" @@ -44,6 +45,8 @@ namespace elf { +ObjLocation toObjLoc(const elf::InputFile *F); + using llvm::object::Archive; class Symbol; @@ -106,8 +109,8 @@ // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; - std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, - uint64_t Offset); + llvm::Optional getSrcLoc(const Symbol &Sym, + InputSectionBase &Sec, uint64_t Offset); // True if this is an argument for --just-symbols. Usually false. bool JustSymbols = false; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -79,47 +79,43 @@ return MBRef; } -// Concatenates arguments to construct a string representing an error location. -static std::string createFileLineMsg(StringRef Path, unsigned Line) { - std::string Filename = path::filename(Path); - std::string Lineno = ":" + std::to_string(Line); - if (Filename == Path) - return Filename + Lineno; - return Filename + Lineno + " (" + Path.str() + Lineno + ")"; -} - template -static std::string getSrcMsgAux(ObjFile &File, const Symbol &Sym, - InputSectionBase &Sec, uint64_t Offset) { +static Optional +getSrcLocAux(ObjFile &File, const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset) { // In DWARF, functions and variables are stored to different places. // First, lookup a function for a given offset. if (Optional Info = File.getDILineInfo(&Sec, Offset)) - return createFileLineMsg(Info->FileName, Info->Line); + return makeSrcLocation(Info->FileName, Info->Line); // If it failed, lookup again as a variable. if (Optional> FileLine = File.getVariableLoc(Sym.getName())) - return createFileLineMsg(FileLine->first, FileLine->second); + return makeSrcLocation(FileLine->first, FileLine->second); // File.SourceFile contains STT_FILE symbol, and that is a last resort. - return File.SourceFile; + if (!File.SourceFile.empty()) + return makeSrcLocationOnlyFile(File.SourceFile); + + return None; } -std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, - uint64_t Offset) { +llvm::Optional InputFile::getSrcLoc(const Symbol &Sym, + InputSectionBase &Sec, + uint64_t Offset) { if (kind() != ObjKind) - return ""; + return None; switch (Config->EKind) { default: llvm_unreachable("Invalid kind"); case ELF32LEKind: - return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + return getSrcLocAux(cast>(*this), Sym, Sec, Offset); case ELF32BEKind: - return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + return getSrcLocAux(cast>(*this), Sym, Sec, Offset); case ELF64LEKind: - return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + return getSrcLocAux(cast>(*this), Sym, Sec, Offset); case ELF64BEKind: - return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + return getSrcLocAux(cast>(*this), Sym, Sec, Offset); } } @@ -235,6 +231,16 @@ return F->ToStringCache; } +ObjLocation elf::toObjLoc(const elf::InputFile *F) { + ObjLocation Result; + if (F) { + Result.File = F->getName(); + Result.Archive = F->ArchiveName; + } else + Result.File = ""; + return Result; +} + template ELFFileBase::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { if (ELFT::TargetEndianness == support::little) Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -11,6 +11,7 @@ #define LLD_ELF_INPUT_SECTION_H #include "Config.h" +#include "Diagnostics.h" #include "Relocations.h" #include "Thunks.h" #include "lld/Common/LLVM.h" @@ -176,8 +177,9 @@ // Returns a source location string. Used to construct an error message. template std::string getLocation(uint64_t Offset); - std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); std::string getObjMsg(uint64_t Offset); + SymbolLocation getSymLoc(const Symbol &Sym, uint64_t Offset); + ObjLocation getObjLoc(uint64_t Offset); // Each section knows how to relocate itself. These functions apply // relocations, assuming that Buf points to this section's copy in Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -252,16 +252,6 @@ return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); } -// This function is intended to be used for constructing an error message. -// The returned message looks like this: -// -// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) -// -// Returns an empty string if there's no way to get line info. -std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) { - return File->getSrcMsg(Sym, *this, Offset); -} - // Returns a filename string along with an optional section name. This // function is intended to be used for constructing an error // message. The returned message looks like this: @@ -289,6 +279,21 @@ .str(); } +ObjLocation InputSectionBase::getObjLoc(uint64_t Off) { + // Find a symbol that encloses a given location. + for (Symbol *B : File->getSymbols()) + if (auto *D = dyn_cast(B)) + if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size) + return makeSymbolObjLocation(File->ArchiveName, File->getName(), + toString(*D)); + + return makeSectionObjLocation(File->ArchiveName, File->getName(), Name, Off); +} + +SymbolLocation InputSectionBase::getSymLoc(const Symbol &Sym, uint64_t Off) { + return SymbolLocation(getObjLoc(Off), File->getSrcLoc(Sym, *this, Off)); +} + InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef(), ""); InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type, @@ -694,7 +699,7 @@ case R_TLSLD_GOT_FROM_END: return InX::Got->getTlsIndexOff() + A - InX::Got->getSize(); case R_TLSLD_GOT: - return InX::Got->getTlsIndexOff() + A; + return InX::Got->getTlsIndexOff() + A; case R_TLSLD_PC: return InX::Got->getTlsIndexVA() + A - P; default: @@ -958,8 +963,8 @@ error(lld::toString(this) + ": " + F->getName() + " (with -fsplit-stack) calls " + D->getName() + " (without -fsplit-stack), but couldn't adjust its prologue"); + } } - } switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls); } Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -365,6 +365,9 @@ def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"