185 lines
6.5 KiB
C
185 lines
6.5 KiB
C
|
//===---- RuntimeDyldChecker.h - RuntimeDyld tester framework -----*- C++ -*-=//
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#ifndef LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
|
||
|
#define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
|
||
|
|
||
|
#include "llvm/ADT/DenseMap.h"
|
||
|
#include "llvm/ADT/Optional.h"
|
||
|
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||
|
#include "llvm/Support/Endian.h"
|
||
|
|
||
|
#include <cstdint>
|
||
|
#include <memory>
|
||
|
#include <string>
|
||
|
#include <utility>
|
||
|
|
||
|
namespace llvm {
|
||
|
|
||
|
class StringRef;
|
||
|
class MCDisassembler;
|
||
|
class MemoryBuffer;
|
||
|
class MCInstPrinter;
|
||
|
class RuntimeDyld;
|
||
|
class RuntimeDyldCheckerImpl;
|
||
|
class raw_ostream;
|
||
|
|
||
|
/// RuntimeDyld invariant checker for verifying that RuntimeDyld has
|
||
|
/// correctly applied relocations.
|
||
|
///
|
||
|
/// The RuntimeDyldChecker class evaluates expressions against an attached
|
||
|
/// RuntimeDyld instance to verify that relocations have been applied
|
||
|
/// correctly.
|
||
|
///
|
||
|
/// The expression language supports basic pointer arithmetic and bit-masking,
|
||
|
/// and has limited disassembler integration for accessing instruction
|
||
|
/// operands and the next PC (program counter) address for each instruction.
|
||
|
///
|
||
|
/// The language syntax is:
|
||
|
///
|
||
|
/// check = expr '=' expr
|
||
|
///
|
||
|
/// expr = binary_expr
|
||
|
/// | sliceable_expr
|
||
|
///
|
||
|
/// sliceable_expr = '*{' number '}' load_addr_expr [slice]
|
||
|
/// | '(' expr ')' [slice]
|
||
|
/// | ident_expr [slice]
|
||
|
/// | number [slice]
|
||
|
///
|
||
|
/// slice = '[' high-bit-index ':' low-bit-index ']'
|
||
|
///
|
||
|
/// load_addr_expr = symbol
|
||
|
/// | '(' symbol '+' number ')'
|
||
|
/// | '(' symbol '-' number ')'
|
||
|
///
|
||
|
/// ident_expr = 'decode_operand' '(' symbol ',' operand-index ')'
|
||
|
/// | 'next_pc' '(' symbol ')'
|
||
|
/// | 'stub_addr' '(' stub-container-name ',' symbol ')'
|
||
|
/// | 'got_addr' '(' stub-container-name ',' symbol ')'
|
||
|
/// | symbol
|
||
|
///
|
||
|
/// binary_expr = expr '+' expr
|
||
|
/// | expr '-' expr
|
||
|
/// | expr '&' expr
|
||
|
/// | expr '|' expr
|
||
|
/// | expr '<<' expr
|
||
|
/// | expr '>>' expr
|
||
|
///
|
||
|
class RuntimeDyldChecker {
|
||
|
public:
|
||
|
class MemoryRegionInfo {
|
||
|
public:
|
||
|
MemoryRegionInfo() = default;
|
||
|
|
||
|
/// Constructor for symbols/sections with content.
|
||
|
MemoryRegionInfo(StringRef Content, JITTargetAddress TargetAddress)
|
||
|
: ContentPtr(Content.data()), Size(Content.size()),
|
||
|
TargetAddress(TargetAddress) {}
|
||
|
|
||
|
/// Constructor for zero-fill symbols/sections.
|
||
|
MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress)
|
||
|
: Size(Size), TargetAddress(TargetAddress) {}
|
||
|
|
||
|
/// Returns true if this is a zero-fill symbol/section.
|
||
|
bool isZeroFill() const {
|
||
|
assert(Size && "setContent/setZeroFill must be called first");
|
||
|
return !ContentPtr;
|
||
|
}
|
||
|
|
||
|
/// Set the content for this memory region.
|
||
|
void setContent(StringRef Content) {
|
||
|
assert(!ContentPtr && !Size && "Content/zero-fill already set");
|
||
|
ContentPtr = Content.data();
|
||
|
Size = Content.size();
|
||
|
}
|
||
|
|
||
|
/// Set a zero-fill length for this memory region.
|
||
|
void setZeroFill(uint64_t Size) {
|
||
|
assert(!ContentPtr && !this->Size && "Content/zero-fill already set");
|
||
|
this->Size = Size;
|
||
|
}
|
||
|
|
||
|
/// Returns the content for this section if there is any.
|
||
|
StringRef getContent() const {
|
||
|
assert(!isZeroFill() && "Can't get content for a zero-fill section");
|
||
|
return StringRef(ContentPtr, static_cast<size_t>(Size));
|
||
|
}
|
||
|
|
||
|
/// Returns the zero-fill length for this section.
|
||
|
uint64_t getZeroFillLength() const {
|
||
|
assert(isZeroFill() && "Can't get zero-fill length for content section");
|
||
|
return Size;
|
||
|
}
|
||
|
|
||
|
/// Set the target address for this region.
|
||
|
void setTargetAddress(JITTargetAddress TargetAddress) {
|
||
|
assert(!this->TargetAddress && "TargetAddress already set");
|
||
|
this->TargetAddress = TargetAddress;
|
||
|
}
|
||
|
|
||
|
/// Return the target address for this region.
|
||
|
JITTargetAddress getTargetAddress() const { return TargetAddress; }
|
||
|
|
||
|
private:
|
||
|
const char *ContentPtr = 0;
|
||
|
uint64_t Size = 0;
|
||
|
JITTargetAddress TargetAddress = 0;
|
||
|
};
|
||
|
|
||
|
using IsSymbolValidFunction = std::function<bool(StringRef Symbol)>;
|
||
|
using GetSymbolInfoFunction =
|
||
|
std::function<Expected<MemoryRegionInfo>(StringRef SymbolName)>;
|
||
|
using GetSectionInfoFunction = std::function<Expected<MemoryRegionInfo>(
|
||
|
StringRef FileName, StringRef SectionName)>;
|
||
|
using GetStubInfoFunction = std::function<Expected<MemoryRegionInfo>(
|
||
|
StringRef StubContainer, StringRef TargetName)>;
|
||
|
using GetGOTInfoFunction = std::function<Expected<MemoryRegionInfo>(
|
||
|
StringRef GOTContainer, StringRef TargetName)>;
|
||
|
|
||
|
RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid,
|
||
|
GetSymbolInfoFunction GetSymbolInfo,
|
||
|
GetSectionInfoFunction GetSectionInfo,
|
||
|
GetStubInfoFunction GetStubInfo,
|
||
|
GetGOTInfoFunction GetGOTInfo,
|
||
|
support::endianness Endianness,
|
||
|
MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
|
||
|
raw_ostream &ErrStream);
|
||
|
~RuntimeDyldChecker();
|
||
|
|
||
|
/// Check a single expression against the attached RuntimeDyld
|
||
|
/// instance.
|
||
|
bool check(StringRef CheckExpr) const;
|
||
|
|
||
|
/// Scan the given memory buffer for lines beginning with the string
|
||
|
/// in RulePrefix. The remainder of the line is passed to the check
|
||
|
/// method to be evaluated as an expression.
|
||
|
bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
|
||
|
|
||
|
/// Returns the address of the requested section (or an error message
|
||
|
/// in the second element of the pair if the address cannot be found).
|
||
|
///
|
||
|
/// if 'LocalAddress' is true, this returns the address of the section
|
||
|
/// within the linker's memory. If 'LocalAddress' is false it returns the
|
||
|
/// address within the target process (i.e. the load address).
|
||
|
std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName,
|
||
|
StringRef SectionName,
|
||
|
bool LocalAddress);
|
||
|
|
||
|
/// If there is a section at the given local address, return its load
|
||
|
/// address, otherwise return none.
|
||
|
Optional<uint64_t> getSectionLoadAddress(void *LocalAddress) const;
|
||
|
|
||
|
private:
|
||
|
std::unique_ptr<RuntimeDyldCheckerImpl> Impl;
|
||
|
};
|
||
|
|
||
|
} // end namespace llvm
|
||
|
|
||
|
#endif
|