[ELF] Change getSrcMsg to use ELFSyncStream. NFC

This commit is contained in:
Fangrui Song 2024-11-29 17:18:22 -08:00
parent 04ab599363
commit 1f13713dbb
8 changed files with 66 additions and 60 deletions

View File

@ -367,39 +367,6 @@ void elf::parseFiles(Ctx &ctx,
}
// Concatenates arguments to construct a string representing an error location.
static std::string createFileLineMsg(StringRef path, unsigned line) {
std::string filename = std::string(path::filename(path));
std::string lineno = ":" + std::to_string(line);
if (filename == path)
return filename + lineno;
return filename + lineno + " (" + path.str() + lineno + ")";
}
std::string InputFile::getSrcMsg(const InputSectionBase &sec, const Symbol &sym,
uint64_t offset) {
if (kind() != ObjKind)
return "";
// First, look up the DWARF line table.
ArrayRef<InputSectionBase *> sections = getSections();
auto it = llvm::find(sections, &sec);
uint64_t sectionIndex = it != sections.end()
? it - sections.begin()
: object::SectionedAddress::UndefSection;
DWARFCache *dwarf = cast<ELFFileBase>(this)->getDwarf();
if (std::optional<DILineInfo> info =
dwarf->getDILineInfo(offset, sectionIndex))
return createFileLineMsg(info->FileName, info->Line);
// If it failed, look up again as a variable.
if (std::optional<std::pair<std::string, unsigned>> fileLine =
dwarf->getVariableLoc(sym.getName()))
return createFileLineMsg(fileLine->first, fileLine->second);
// File.sourceFile contains STT_FILE symbol, and that is a last resort.
return std::string(cast<ELFFileBase>(this)->sourceFile);
}
StringRef InputFile::getNameForScript() const {
if (archiveName.empty())
return getName();

View File

@ -147,9 +147,6 @@ public:
// True if this is an argument for --just-symbols. Usually false.
bool justSymbols = false;
std::string getSrcMsg(const InputSectionBase &sec, const Symbol &sym,
uint64_t offset);
// On PPC64 we need to keep track of which files contain small code model
// relocations that access the .toc section. To minimize the chance of a
// relocation overflow, files that do contain said relocations should have

View File

@ -16,6 +16,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/DWARF.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
@ -316,15 +317,40 @@ std::string InputSectionBase::getLocation(uint64_t offset) const {
return filename + ":(" + secAndOffset;
}
// This function is intended to be used for constructing an error message.
// The returned message looks like this:
static void printFileLine(const ELFSyncStream &s, StringRef path,
unsigned line) {
StringRef filename = path::filename(path);
s << filename << ':' << line;
if (filename != path)
s << " (" << path << ':' << line << ')';
}
// Print an error message that 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) const {
return file->getSrcMsg(*this, sym, offset);
const ELFSyncStream &elf::operator<<(const ELFSyncStream &s,
InputSectionBase::SrcMsg &&msg) {
auto &sec = msg.sec;
if (sec.file->kind() != InputFile::ObjKind)
return s;
auto &file = cast<ELFFileBase>(*sec.file);
// First, look up the DWARF line table.
ArrayRef<InputSectionBase *> sections = file.getSections();
auto it = llvm::find(sections, &sec);
uint64_t sectionIndex = it != sections.end()
? it - sections.begin()
: object::SectionedAddress::UndefSection;
DWARFCache *dwarf = file.getDwarf();
if (auto info = dwarf->getDILineInfo(msg.offset, sectionIndex))
printFileLine(s, info->FileName, info->Line);
else if (auto fileLine = dwarf->getVariableLoc(msg.sym.getName()))
// If it failed, look up again as a variable.
printFileLine(s, fileLine->first, fileLine->second);
else
// File.sourceFile contains STT_FILE symbol, and that is a last resort.
s << file.sourceFile;
return s;
}
// Returns a filename string along with an optional section name. This

View File

@ -147,6 +147,11 @@ public:
const InputSectionBase *sec;
uint64_t offset;
};
struct SrcMsg {
const InputSectionBase &sec;
const Symbol &sym;
uint64_t offset;
};
template <class ELFT>
InputSectionBase(ObjFile<ELFT> &file, const typename ELFT::Shdr &header,
@ -252,8 +257,10 @@ public:
// Returns a source location string. Used to construct an error message.
std::string getLocation(uint64_t offset) const;
std::string getSrcMsg(const Symbol &sym, uint64_t offset) const;
ObjMsg getObjMsg(uint64_t offset) const { return {this, offset}; }
SrcMsg getSrcMsg(const Symbol &sym, uint64_t offset) const {
return {*this, sym, offset};
}
// Each section knows how to relocate itself. These functions apply
// relocations, assuming that Buf points to this section's copy in
@ -522,6 +529,8 @@ const ELFSyncStream &operator<<(const ELFSyncStream &,
const InputSectionBase *);
const ELFSyncStream &operator<<(const ELFSyncStream &,
InputSectionBase::ObjMsg &&);
const ELFSyncStream &operator<<(const ELFSyncStream &,
InputSectionBase::SrcMsg &&);
} // namespace elf
} // namespace lld

View File

@ -91,9 +91,10 @@ static void printLocation(ELFSyncStream &s, InputSectionBase &sec,
const Symbol &sym, uint64_t off) {
printDefinedLocation(s, sym);
s << "\n>>> referenced by ";
std::string src = sec.getSrcMsg(sym, off);
if (!src.empty())
s << src << "\n>>> ";
auto tell = s.tell();
s << sec.getSrcMsg(sym, off);
if (tell != s.tell())
s << "\n>>> ";
s << sec.getObjMsg(off);
}
@ -738,9 +739,12 @@ static void reportUndefinedSymbol(Ctx &ctx, const UndefinedDiag &undef,
// In the absence of line number information, utilize DW_TAG_variable (if
// present) for the enclosing symbol (e.g. var in `int *a[] = {&undef};`).
Symbol *enclosing = sec.getEnclosingSymbol(offset);
std::string src = sec.getSrcMsg(enclosing ? *enclosing : sym, offset);
if (!src.empty())
msg << src << "\n>>> ";
ELFSyncStream msg1(ctx, DiagLevel::None);
auto tell = msg.tell();
msg << sec.getSrcMsg(enclosing ? *enclosing : sym, offset);
if (tell != msg.tell())
msg << "\n>>> ";
msg << sec.getObjMsg(offset);
}

View File

@ -543,16 +543,17 @@ void elf::reportDuplicate(Ctx &ctx, const Symbol &sym, const InputFile *newFile,
// >>> defined at baz.c:563
// >>> baz.o in archive libbaz.a
auto *sec1 = cast<InputSectionBase>(d->section);
std::string src1 = sec1->getSrcMsg(sym, d->value);
std::string src2 = errSec->getSrcMsg(sym, errOffset);
auto diag = Err(ctx);
diag << "duplicate symbol: " << &sym << "\n>>> defined at ";
if (!src1.empty())
diag << src1 << "\n>>> ";
auto tell = diag.tell();
diag << sec1->getSrcMsg(sym, d->value);
if (tell != diag.tell())
diag << "\n>>> ";
diag << sec1->getObjMsg(d->value) << "\n>>> defined at ";
if (!src2.empty())
diag << src2 << "\n>>> ";
tell = diag.tell();
diag << errSec->getSrcMsg(sym, errOffset);
if (tell != diag.tell())
diag << "\n>>> ";
diag << errSec->getObjMsg(errOffset);
}

View File

@ -106,10 +106,11 @@ ErrorPlace elf::getErrorPlace(Ctx &ctx, const uint8_t *loc) {
if (isecLoc <= loc && loc < isecLoc + isec->getSize()) {
std::string objLoc = isec->getLocation(loc - isecLoc);
// Return object file location and source file location.
// TODO: Refactor getSrcMsg not to take a variable.
Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0);
return {isec, objLoc + ": ",
isec->file ? isec->getSrcMsg(dummy, loc - isecLoc) : ""};
ELFSyncStream msg(ctx, DiagLevel::None);
if (isec->file)
msg << isec->getSrcMsg(dummy, loc - isecLoc);
return {isec, objLoc + ": ", std::string(msg.str())};
}
}
return {};

View File

@ -167,6 +167,7 @@ public:
SyncStream(SyncStream &&o) : e(o.e), level(o.level), buf(std::move(o.buf)) {}
~SyncStream();
StringRef str() { return os.str(); }
uint64_t tell() { return os.tell(); }
};
[[noreturn]] void exitLld(int val);