ELF: Support detection of relocation errors during processing

At the moment errors in relocation processing such as out of range
values are not detected or at best trapped by asserts which will not
be present in release builds. This patch adds support for checking
error return values from applyRelocation() calls and printing an
appropriate error message. It also adds support for printing multiple
errors rather than just the first one.

llvm-svn: 226557
This commit is contained in:
Will Newton 2015-01-20 10:37:40 +00:00
parent ea6de1f81d
commit a8c4d48478
19 changed files with 64 additions and 55 deletions

View File

@ -462,7 +462,7 @@ std::error_code AArch64TargetRelocationHandler::applyRelocation(
targetVAddress, ref.addend());
break;
default:
unhandledReferenceType(*atom._atom, ref);
return make_unhandled_reloc_error();
}
return std::error_code();

View File

@ -20,9 +20,6 @@ template <class ELFT> class AArch64TargetLayout;
class AArch64TargetRelocationHandler final : public TargetRelocationHandler {
public:
AArch64TargetRelocationHandler(ELFLinkingContext &targetInfo)
: TargetRelocationHandler(targetInfo) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,
const Reference &) const override;

View File

@ -19,7 +19,7 @@ using namespace elf;
AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &context)
: _context(context),
_AArch64TargetLayout(new AArch64TargetLayout<AArch64ELFType>(context)),
_AArch64RelocationHandler(new AArch64TargetRelocationHandler(context)) {}
_AArch64RelocationHandler(new AArch64TargetRelocationHandler()) {}
void AArch64TargetHandler::registerRelocationNames(Registry &registry) {
registry.addKindTable(Reference::KindNamespace::ELF,

View File

@ -344,7 +344,7 @@ std::error_code HexagonTargetRelocationHandler::applyRelocation(
break;
default:
unhandledReferenceType(*atom._atom, ref);
return make_unhandled_reloc_error();
}
return std::error_code();

View File

@ -20,9 +20,8 @@ class HexagonTargetHandler;
class HexagonTargetRelocationHandler final : public TargetRelocationHandler {
public:
HexagonTargetRelocationHandler(HexagonTargetLayout<HexagonELFType> &layout,
ELFLinkingContext &targetInfo)
: TargetRelocationHandler(targetInfo), _hexagonTargetLayout(layout) {}
HexagonTargetRelocationHandler(HexagonTargetLayout<HexagonELFType> &layout)
: _hexagonTargetLayout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,

View File

@ -23,7 +23,7 @@ HexagonTargetHandler::HexagonTargetHandler(HexagonLinkingContext &context)
_hexagonRuntimeFile(new HexagonRuntimeFile<HexagonELFType>(context)),
_hexagonTargetLayout(new HexagonTargetLayout<HexagonELFType>(context)),
_hexagonRelocationHandler(new HexagonTargetRelocationHandler(
*_hexagonTargetLayout.get(), context)) {}
*_hexagonTargetLayout.get())) {}
std::unique_ptr<Writer> HexagonTargetHandler::getWriter() {
switch (_hexagonLinkingContext.getOutputELFType()) {

View File

@ -341,7 +341,7 @@ std::error_code MipsTargetRelocationHandler::applyRelocation(
// Do nothing.
break;
default:
unhandledReferenceType(*atom._atom, ref);
return make_unhandled_reloc_error();
}
if (shuffle)

View File

@ -18,9 +18,8 @@ class MipsTargetHandler;
class MipsTargetRelocationHandler final : public TargetRelocationHandler {
public:
MipsTargetRelocationHandler(MipsTargetLayout<Mips32ElELFType> &layout,
ELFLinkingContext &targetInfo)
: TargetRelocationHandler(targetInfo), _mipsTargetLayout(layout) {}
MipsTargetRelocationHandler(MipsTargetLayout<Mips32ElELFType> &layout)
: _mipsTargetLayout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,

View File

@ -21,8 +21,7 @@ typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ElELFType;
MipsTargetHandler::MipsTargetHandler(MipsLinkingContext &ctx)
: _ctx(ctx), _runtimeFile(new MipsRuntimeFile<Mips32ElELFType>(ctx)),
_targetLayout(new MipsTargetLayout<Mips32ElELFType>(ctx)),
_relocationHandler(new MipsTargetRelocationHandler(*_targetLayout, ctx)) {
}
_relocationHandler(new MipsTargetRelocationHandler(*_targetLayout)) {}
std::unique_ptr<Writer> MipsTargetHandler::getWriter() {
switch (_ctx.getOutputELFType()) {

View File

@ -52,7 +52,7 @@ std::error_code PPCTargetRelocationHandler::applyRelocation(
break;
default:
unhandledReferenceType(*atom._atom, ref);
return make_unhandled_reloc_error();
}
return std::error_code();
@ -61,7 +61,7 @@ std::error_code PPCTargetRelocationHandler::applyRelocation(
PPCTargetHandler::PPCTargetHandler(PPCLinkingContext &context)
: _ppcLinkingContext(context),
_ppcTargetLayout(new PPCTargetLayout<PPCELFType>(context)),
_ppcRelocationHandler(new PPCTargetRelocationHandler(context)) {}
_ppcRelocationHandler(new PPCTargetRelocationHandler()) {}
void PPCTargetHandler::registerRelocationNames(Registry &registry) {
registry.addKindTable(Reference::KindNamespace::ELF,

View File

@ -25,9 +25,6 @@ public:
class PPCTargetRelocationHandler final : public TargetRelocationHandler {
public:
PPCTargetRelocationHandler(ELFLinkingContext &context)
: TargetRelocationHandler(context) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,
const Reference &) const override;

View File

@ -28,6 +28,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
#include <memory>
#include <mutex>
namespace lld {
namespace elf {
@ -269,6 +270,31 @@ protected:
int32_t _contentPermissions;
bool _isLoadedInMemory;
std::vector<lld::AtomLayout *> _atoms;
mutable std::mutex _outputMutex;
void printError(const std::string &errorStr, const AtomLayout &atom,
const Reference &ref) const {
StringRef kindValStr;
if (!this->_context.registry().referenceKindToString(ref.kindNamespace(),
ref.kindArch(),
ref.kindValue(),
kindValStr)) {
kindValStr = "unknown";
}
std::string errStr = (Twine(errorStr) + " in file " +
atom._atom->file().path() +
": reference from " + atom._atom->name() +
"+" + Twine(ref.offsetInAtom()) +
" to " + ref.target()->name() +
"+" + Twine(ref.addend()) +
" of type " + Twine(ref.kindValue()) +
" (" + kindValStr + ")\n").str();
// Take the lock to prevent output getting interleaved between threads
std::lock_guard<std::mutex> lock(_outputMutex);
llvm::errs() << errStr;
}
};
/// Align the offset to the required modulus defined by the atom alignment
@ -377,6 +403,7 @@ template <class ELFT>
void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
llvm::FileOutputBuffer &buffer) {
uint8_t *chunkBuffer = buffer.getBufferStart();
bool success = true;
parallel_for_each(_atoms.begin(), _atoms.end(), [&](lld::AtomLayout * ai) {
DEBUG_WITH_TYPE("Section",
llvm::dbgs() << "Writing atom: " << ai->_atom->name()
@ -393,9 +420,16 @@ void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
std::memcpy(atomContent, content.data(), contentSize);
const TargetRelocationHandler &relHandler =
this->_context.template getTargetHandler<ELFT>().getRelocationHandler();
for (const auto ref : *definedAtom)
relHandler.applyRelocation(*writer, buffer, *ai, *ref);
for (const auto ref : *definedAtom) {
if (std::error_code ec = relHandler.applyRelocation(*writer, buffer,
*ai, *ref)) {
printError(ec.message(), *ai, *ref);
success = false;
}
}
});
if (!success)
llvm::report_fatal_error("relocating output");
}
/// \brief A OutputSection represents a set of sections grouped by the same

View File

@ -43,32 +43,12 @@ template <class ELFT> class TargetLayout;
class TargetRelocationHandler {
public:
/// Constructor
TargetRelocationHandler(ELFLinkingContext &targetInfo) : _ctx(targetInfo) {}
TargetRelocationHandler() {}
virtual ~TargetRelocationHandler() {}
virtual std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,
const Reference &) const = 0;
protected:
void unhandledReferenceType(const Atom &atom, const Reference &ref) const {
llvm::errs() << "Unhandled reference type in file " << atom.file().path()
<< ": reference from " << atom.name() << "+"
<< ref.offsetInAtom() << " to " << ref.target()->name() << "+"
<< ref.addend() << " of type ";
StringRef kindValStr;
if (!_ctx.registry().referenceKindToString(
ref.kindNamespace(), ref.kindArch(), ref.kindValue(), kindValStr)) {
kindValStr = "unknown";
}
llvm::errs() << ref.kindValue() << " (" << kindValStr << ")\n";
llvm::report_fatal_error("unhandled reference type");
}
private:
ELFLinkingContext &_ctx;
};
/// \brief TargetHandler contains all the information responsible to handle a
@ -91,6 +71,15 @@ public:
/// How does the target deal with writing ELF output.
virtual std::unique_ptr<Writer> getWriter() = 0;
};
inline std::error_code make_unhandled_reloc_error() {
return make_dynamic_error_code(Twine("Unhandled reference type"));
}
inline std::error_code make_out_of_range_reloc_error() {
return make_dynamic_error_code(Twine("Relocation out of range"));
}
} // end namespace elf
} // end namespace lld

View File

@ -52,7 +52,7 @@ std::error_code X86TargetRelocationHandler::applyRelocation(
relocPC32(location, relocVAddress, targetVAddress, ref.addend());
break;
default:
unhandledReferenceType(*atom._atom, ref);
return make_unhandled_reloc_error();
}
return std::error_code();

View File

@ -18,9 +18,6 @@ typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
class X86TargetRelocationHandler final : public TargetRelocationHandler {
public:
X86TargetRelocationHandler(ELFLinkingContext &targetInfo)
: TargetRelocationHandler(targetInfo) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,
const Reference &) const override;

View File

@ -50,4 +50,4 @@ void X86TargetHandler::registerRelocationNames(Registry &registry) {
X86TargetHandler::X86TargetHandler(X86LinkingContext &context)
: _x86LinkingContext(context),
_x86TargetLayout(new X86TargetLayout<X86ELFType>(context)),
_x86RelocationHandler(new X86TargetRelocationHandler(context)) {}
_x86RelocationHandler(new X86TargetRelocationHandler()) {}

View File

@ -123,7 +123,7 @@ std::error_code X86_64TargetRelocationHandler::applyRelocation(
case R_X86_64_DTPOFF64:
break;
default:
unhandledReferenceType(*atom._atom, ref);
return make_unhandled_reloc_error();
}
return std::error_code();

View File

@ -20,10 +20,8 @@ template <class ELFT> class X86_64TargetLayout;
class X86_64TargetRelocationHandler final : public TargetRelocationHandler {
public:
X86_64TargetRelocationHandler(X86_64TargetLayout<X86_64ELFType> &layout,
ELFLinkingContext &targetInfo)
: TargetRelocationHandler(targetInfo), _tlsSize(0),
_x86_64Layout(layout) {}
X86_64TargetRelocationHandler(X86_64TargetLayout<X86_64ELFType> &layout)
: _tlsSize(0), _x86_64Layout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const lld::AtomLayout &,

View File

@ -20,7 +20,7 @@ X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &context)
: _context(context),
_x86_64TargetLayout(new X86_64TargetLayout<X86_64ELFType>(context)),
_x86_64RelocationHandler(new X86_64TargetRelocationHandler(
*_x86_64TargetLayout.get(), context)) {}
*_x86_64TargetLayout.get())) {}
void X86_64TargetHandler::registerRelocationNames(Registry &registry) {
registry.addKindTable(Reference::KindNamespace::ELF,