Skip to content

Commit

Permalink
Ian/instruction carry lifter (#615)
Browse files Browse the repository at this point in the history
* add lifter field

* arch has intrinsics

* use insn lifter in trace lifter

* limit default lifters to ops only

* init lifters

* pass arch in tests

* fix bug in swap

* stop using archbase decode in sleigh arches
  • Loading branch information
2over12 authored Aug 12, 2022
1 parent 5f79f40 commit 854c73e
Show file tree
Hide file tree
Showing 23 changed files with 195 additions and 127 deletions.
2 changes: 1 addition & 1 deletion bin/lift/Lift.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ int main(int argc, char *argv[]) {

auto inst_lifter = arch->DefaultLifter(intrinsics);

remill::TraceLifter trace_lifter(*inst_lifter.get(), manager);
remill::TraceLifter trace_lifter(arch.get(), manager);

// Lift all discoverable traces starting from `--entry_address` into
// `module`.
Expand Down
9 changes: 6 additions & 3 deletions include/remill/Arch/Arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/IRBuilder.h>
#include <remill/BC/InstructionLifter.h>
#include <remill/BC/IntrinsicTable.h>

#pragma clang diagnostic pop

Expand Down Expand Up @@ -200,6 +201,8 @@ class Arch {
virtual llvm::StructType *RegisterWindowType(void) const = 0;


virtual const IntrinsicTable *GetInstrinsicTable(void) const = 0;

virtual unsigned RegMdID(void) const = 0;

// Apply `cb` to every register.
Expand Down Expand Up @@ -257,9 +260,9 @@ class Arch {
void PrepareModuleDataLayout(llvm::Module *mod) const;


// TODO(Ian): This is kinda messy but only an arch currently knows if it is
// sleigh or not and sleigh needs different lifting context etc.
virtual InstructionLifter::LifterPtr
// A default lifter does not know how to lift instructions. The default lifter allows
// the user to perform instruction/context independent lifting operations.
virtual OperandLifter::OpLifterPtr
DefaultLifter(const remill::IntrinsicTable &intrinsics) const = 0;

inline void
Expand Down
15 changes: 12 additions & 3 deletions include/remill/Arch/ArchBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ struct Register;

// Internal base architecture for all Remill-internal architectures.
class ArchBase : public remill::Arch {
protected:
virtual bool ArchDecodeInstruction(uint64_t address,
std::string_view instr_bytes,
Instruction &inst) const = 0;

public:
using ArchPtr = std::unique_ptr<const Arch>;

Expand Down Expand Up @@ -64,11 +69,14 @@ class ArchBase : public remill::Arch {
// Return information about a register, given its name.
const Register *RegisterByName(std::string_view name) const final;

const IntrinsicTable *GetInstrinsicTable(void) const final;

unsigned RegMdID(void) const final;

// TODO(Ian): This is kinda messy but only an arch currently knows if it is
// sleigh or not and sleigh needs different lifting context etc.
InstructionLifter::LifterPtr
virtual bool DecodeInstruction(uint64_t address, std::string_view instr_bytes,
Instruction &inst) const override;

OperandLifter::OpLifterPtr
DefaultLifter(const remill::IntrinsicTable &intrinsics) const override;

// Get the state pointer and various other types from the `llvm::LLVMContext`
Expand Down Expand Up @@ -103,6 +111,7 @@ class ArchBase : public remill::Arch {
mutable std::vector<std::unique_ptr<Register>> registers;
mutable std::vector<const Register *> reg_by_offset;
mutable std::unordered_map<std::string, const Register *> reg_by_name;
mutable std::unique_ptr<IntrinsicTable> instrinsics{nullptr};
};

} // namespace remill
8 changes: 8 additions & 0 deletions include/remill/Arch/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#pragma once

#include <remill/BC/InstructionLifter.h>

#include <string>
#include <variant>
#include <vector>
Expand Down Expand Up @@ -349,7 +351,13 @@ class Instruction {
Operand &EmplaceOperand(const Operand::ShiftRegister &op);
Operand &EmplaceOperand(const Operand::Address &op);


const InstructionLifter::LifterPtr &GetLifter();

void SetLifter(InstructionLifter::LifterPtr lifter);

private:
InstructionLifter::LifterPtr lifter;
static constexpr auto kMaxNumExpr = 64u;
OperandExpression exprs[kMaxNumExpr];
unsigned next_expr_index{0};
Expand Down
28 changes: 23 additions & 5 deletions include/remill/BC/InstructionLifter.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,30 @@ enum LiftStatus {
kLiftedInstruction
};

// Instruction independent lifting
class OperandLifter {
public:
using OpLifterPtr = std::shared_ptr<OperandLifter>;

// Load the address of a register.
virtual std::pair<llvm::Value *, llvm::Type *>
LoadRegAddress(llvm::BasicBlock *block, llvm::Value *state_ptr,
std::string_view reg_name) const = 0;

// Load the value of a register.
virtual llvm::Value *LoadRegValue(llvm::BasicBlock *block,
llvm::Value *state_ptr,
std::string_view reg_name) const = 0;

virtual llvm::Type *GetMemoryType() = 0;
};

// Wraps the process of lifting an instruction into a block. This resolves
// the intended instruction target to a function, and ensures that the function
// is called with the appropriate arguments.
class InstructionLifter {
class InstructionLifter : public OperandLifter {
public:
using LifterPtr = std::unique_ptr<InstructionLifter>;
using LifterPtr = std::shared_ptr<InstructionLifter>;

virtual ~InstructionLifter(void);

Expand All @@ -83,17 +101,17 @@ class InstructionLifter {
// Load the address of a register.
std::pair<llvm::Value *, llvm::Type *>
LoadRegAddress(llvm::BasicBlock *block, llvm::Value *state_ptr,
std::string_view reg_name) const;
std::string_view reg_name) const override final;

// Load the value of a register.
llvm::Value *LoadRegValue(llvm::BasicBlock *block, llvm::Value *state_ptr,
std::string_view reg_name) const;
std::string_view reg_name) const override final;

// Clear out the cache of the current register values/addresses loaded.
void ClearCache(void) const;


llvm::Type *GetMemoryType();
virtual llvm::Type *GetMemoryType() override final;

protected:
// Lift an operand to an instruction.
Expand Down
6 changes: 3 additions & 3 deletions include/remill/BC/TraceLifter.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ class TraceLifter {
public:
~TraceLifter(void);

inline TraceLifter(InstructionLifter &inst_lifter_, TraceManager &manager_)
: TraceLifter(&inst_lifter_, &manager_) {}
inline TraceLifter(const Arch *arch_, TraceManager &manager_)
: TraceLifter(arch_, &manager_) {}

TraceLifter(InstructionLifter *inst_lifter_, TraceManager *manager_);
TraceLifter(const Arch *arch_, TraceManager *manager_);

static void NullCallback(uint64_t, llvm::Function *);

Expand Down
4 changes: 2 additions & 2 deletions lib/Arch/AArch32/Arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class AArch32Arch final : public AArch32ArchBase {

virtual ~AArch32Arch(void);

bool DecodeInstruction(uint64_t address, std::string_view inst_bytes,
Instruction &inst) const override;
bool ArchDecodeInstruction(uint64_t address, std::string_view inst_bytes,
Instruction &inst) const override;

private:
AArch32Arch(void) = delete;
Expand Down
Loading

0 comments on commit 854c73e

Please sign in to comment.