Index: Common/ErrorHandler.cpp =================================================================== --- Common/ErrorHandler.cpp +++ Common/ErrorHandler.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "lld/Common/ErrorHandler.h" - #include "lld/Common/Threads.h" +#include "llvm/Support/Path.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticInfo.h" @@ -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,190 @@ ++ErrorCount; } -void ErrorHandler::fatal(const Twine &Msg) { - error(Msg); +void ErrorHandler::fatal(const Twine &Orig, const Twine &Msg) { + error(Orig, Msg); exitLld(1); } + +ObjLocation lld::makeScriptObjLocation(StringRef Script) { + ObjLocation Result; + Result.File = Script; + return Result; +} + +ObjLocation lld::makeSymbolObjLocation(StringRef Archive, StringRef File, + StringRef Sym) { + ObjLocation Result; + Result.Archive = Archive; + Result.File = File; + Result.Sym = Sym; + return Result; +} + +ObjLocation lld::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 lld::makeSrcLocation(StringRef File, unsigned Line) { + SrcLocation Result; + Result.Path = File.str(); + Result.Line = Line; + return Result; +} + +SrcLocation lld::makeSrcLocationOnlyFile(StringRef File) { + SrcLocation Result; + Result.Path = File.str(); + return Result; +} + +static bool hasLineNumber(const ObjLocation &ObjLoc) { + return !ObjLoc.Sym.empty() || !ObjLoc.Sec.empty(); +} + +static bool hasLineNumber(const SrcLocation &SrcLoc) { + return SrcLoc.Line.hasValue(); +} + +// Based on createFileLineMsg (InputFiles.cpp) +static std::string getNativeSrcLocTxt(const SrcLocation &SrcLoc) { + if (!hasLineNumber(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 (!hasLineNumber(SrcLoc)) + return SrcLoc.Path; + return SrcLoc.Path + "(" + std::to_string(SrcLoc.Line.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 && hasLineNumber(SymLoc->SrcLoc.getValue())) || + (!SymLoc->SrcLoc && hasLineNumber(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 && !hasLineNumber(SymLoc->SrcLoc.getValue())) + Result += "\n>>> defined in " + getVSSrcLocTxt(SymLoc->SrcLoc.getValue()) + + "\n>>> "; + else if (hasLineNumber(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 && !hasLineNumber(SymLoc->SrcLoc.getValue())) + Result += + getVSSrcLocTxt(SymLoc->SrcLoc.getValue()) + "\n>>> "; + Result += getObjLocTxt(SymLoc->ObjLoc); + return Result; +} + +static std::string getMsg(const Diagnostic &C, unsigned index) { + if (!errorHandler().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(); +} + +static std::string getOrig(const Diagnostic &C, unsigned index) { + if (!errorHandler().VSDiagnostics) + return errorHandler().LogName; + const SymbolLocation *Loc = C.Referenced ? C.Referenced : C.Defined[index]; + if (!Loc || !Loc->SrcLoc || !hasLineNumber(Loc->SrcLoc.getValue())) + return errorHandler().LogName; + return getVSSrcLocTxt(Loc->SrcLoc.getValue()); +} + +static unsigned reportCount(const Diagnostic &diagnostic) { + if (errorHandler().VSDiagnostics && diagnostic.Defined[1]) + return 2; + return 1; +} + +void lld::warn(Diagnostic const &C) { + for (unsigned I = 0; I < reportCount(C); ++I) + errorHandler().warn(getOrig(C, I), getMsg(C, I)); +} + +void lld::error(Diagnostic const &C) { + for (unsigned I = 0; I < reportCount(C); ++I) + errorHandler().error(getOrig(C, I), getMsg(C, I)); +} Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -303,6 +303,13 @@ else warn(Msg); } + +static inline void errorOrWarn(const Diagnostic &diagnostic) { + if (!Config->NoinhibitExec) + error(diagnostic); + else + warn(diagnostic); +} } // namespace elf } // namespace lld Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -751,6 +751,7 @@ errorHandler().FatalWarnings = Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + errorHandler().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 @@ -43,6 +43,8 @@ namespace elf { +ObjLocation toObjLoc(const elf::InputFile *F); + using llvm::object::Archive; class Symbol; @@ -108,8 +110,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 @@ -78,47 +78,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); } } @@ -230,6 +226,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 @@ -175,8 +175,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 @@ -312,16 +312,6 @@ return (SrcFile + ":(" + SecAndOffset + ")"); } -// 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: @@ -349,6 +339,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, Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -390,6 +390,9 @@ def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"