mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
Fix bug in rendering actual PC from NEXT_PC with thumb preffix/suffix instructions (#661)
* use context to figure out mode in thumb for insn size * add patches for inst_next based on curr isamode * add decoding context constant injection in lifting * allocate registers to repr context and insert belief about context registers as first value * add regression test * fix imports * add comment
This commit is contained in:
@@ -45,11 +45,9 @@ class AArch32Arch final : public AArch32ArchBase {
|
||||
|
||||
// Maximum number of bytes in an instruction for this particular architecture.
|
||||
uint64_t MaxInstructionSize(const DecodingContext &, bool) const override;
|
||||
|
||||
|
||||
private:
|
||||
static bool IsThumb(const DecodingContext &context);
|
||||
|
||||
private:
|
||||
sleighthumb2::SleighAArch32ThumbDecoder thumb_decoder;
|
||||
bool DecodeAArch32(uint64_t address, std::string_view instr_bytes,
|
||||
Instruction &inst, DecodingContext context) const;
|
||||
|
||||
@@ -211,7 +211,7 @@ bool SleighDecoder::DecodeInstruction(uint64_t address,
|
||||
|
||||
SleighDecoder::SleighDecoder(
|
||||
const remill::Arch &arch_, std::string sla_name, std::string pspec_name,
|
||||
std::unordered_map<std::string, std::string> context_reg_map_,
|
||||
ContextRegMappings context_reg_map_,
|
||||
std::unordered_map<std::string, std::string> state_reg_map_)
|
||||
: sleigh_ctx(sla_name, pspec_name),
|
||||
sla_name(std::move(sla_name)),
|
||||
@@ -222,8 +222,7 @@ SleighDecoder::SleighDecoder(
|
||||
state_reg_remappings(std::move(state_reg_map_)) {}
|
||||
|
||||
|
||||
const std::unordered_map<std::string, std::string> &
|
||||
SleighDecoder::GetContextRegisterMapping() const {
|
||||
const ContextRegMappings &SleighDecoder::GetContextRegisterMapping() const {
|
||||
return this->context_reg_mapping;
|
||||
}
|
||||
|
||||
@@ -273,8 +272,9 @@ SleighDecoder::DecodeInstructionImpl(uint64_t address,
|
||||
uint64_t fallthrough = address + *instr_len;
|
||||
inst.next_pc = fallthrough;
|
||||
|
||||
ControlFlowStructureAnalysis analysis(this->context_reg_mapping,
|
||||
this->sleigh_ctx.GetEngine());
|
||||
ControlFlowStructureAnalysis analysis(
|
||||
this->context_reg_mapping.GetInternalRegMapping(),
|
||||
this->sleigh_ctx.GetEngine());
|
||||
|
||||
|
||||
auto cat =
|
||||
@@ -385,6 +385,17 @@ Overload(Ts...) -> Overload<Ts...>;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
const std::unordered_map<std::string, size_t> &
|
||||
ContextRegMappings::GetSizeMapping() const {
|
||||
return this->vnode_size_mapping;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::string> &
|
||||
ContextRegMappings::GetInternalRegMapping() const {
|
||||
return this->context_reg_mapping;
|
||||
}
|
||||
|
||||
void SleighDecoder::ApplyFlowToInstruction(remill::Instruction &inst) const {
|
||||
|
||||
|
||||
@@ -493,4 +504,5 @@ void SetContextRegisterValueInSleigh(
|
||||
ctxt.GetAddressFromOffset(addr), value);
|
||||
}
|
||||
|
||||
|
||||
} // namespace remill::sleigh
|
||||
|
||||
+27
-7
@@ -95,13 +95,34 @@ class SingleInstructionSleighContext {
|
||||
std::vector<std::string> getUserOpNames();
|
||||
};
|
||||
|
||||
struct ContextRegMappings {
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> context_reg_mapping;
|
||||
// Stores the size of the context register in bytes.
|
||||
// We need to allocate space for an instruction to manipulate a
|
||||
// Context reg as needed. This space is also populated with the incoming value.
|
||||
std::unordered_map<std::string, size_t> vnode_size_mapping;
|
||||
|
||||
public:
|
||||
ContextRegMappings(
|
||||
std::unordered_map<std::string, std::string> context_reg_mapping,
|
||||
std::unordered_map<std::string, size_t> vnode_size_mapping)
|
||||
: context_reg_mapping(std::move(context_reg_mapping)),
|
||||
vnode_size_mapping(std::move(vnode_size_mapping)) {}
|
||||
|
||||
const std::unordered_map<std::string, size_t> &GetSizeMapping() const;
|
||||
|
||||
const std::unordered_map<std::string, std::string> &
|
||||
GetInternalRegMapping() const;
|
||||
};
|
||||
|
||||
class SleighDecoder {
|
||||
public:
|
||||
SleighDecoder() = delete;
|
||||
SleighDecoder(
|
||||
const remill::Arch &arch, std::string sla_name, std::string pspec_name,
|
||||
std::unordered_map<std::string, std::string> context_reg_mapping,
|
||||
ContextRegMappings context_reg_mapping,
|
||||
std::unordered_map<std::string, std::string> state_reg_remappings);
|
||||
const std::string &GetSLAName() const;
|
||||
|
||||
@@ -112,17 +133,16 @@ class SleighDecoder {
|
||||
const ContextValues &) const = 0;
|
||||
|
||||
|
||||
virtual llvm::Value *LiftPcFromCurrPc(llvm::IRBuilder<> &bldr,
|
||||
llvm::Value *curr_pc,
|
||||
size_t curr_insn_size) const = 0;
|
||||
virtual llvm::Value *
|
||||
LiftPcFromCurrPc(llvm::IRBuilder<> &bldr, llvm::Value *curr_pc,
|
||||
size_t curr_insn_size, const DecodingContext &) const = 0;
|
||||
|
||||
|
||||
bool DecodeInstruction(uint64_t address, std::string_view instr_bytes,
|
||||
Instruction &inst, DecodingContext context) const;
|
||||
|
||||
// Gets the context registers that are required to be set in order to decode, maps pcode context reg names to remill context reg names.
|
||||
const std::unordered_map<std::string, std::string> &
|
||||
GetContextRegisterMapping() const;
|
||||
const ContextRegMappings &GetContextRegisterMapping() const;
|
||||
|
||||
// Maps pcode registers to their names in the remill state structure for the given arch (if a renaming is required.)
|
||||
const std::unordered_map<std::string, std::string> &
|
||||
@@ -148,7 +168,7 @@ class SleighDecoder {
|
||||
|
||||
mutable std::shared_ptr<remill::SleighLifter> lifter;
|
||||
const remill::Arch &arch;
|
||||
std::unordered_map<std::string, std::string> context_reg_mapping;
|
||||
ContextRegMappings context_reg_mapping;
|
||||
std::unordered_map<std::string, std::string> state_reg_remappings;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <remill/Arch/Context.h>
|
||||
#include <remill/Arch/Name.h>
|
||||
#include <remill/BC/ABI.h>
|
||||
#include <remill/BC/Util.h>
|
||||
@@ -30,8 +31,8 @@ class SleighPPCDecoder final : public remill::sleigh::SleighDecoder {
|
||||
public:
|
||||
SleighPPCDecoder(const remill::Arch &);
|
||||
|
||||
llvm::Value *LiftPcFromCurrPc(llvm::IRBuilder<> &, llvm::Value *,
|
||||
size_t) const override;
|
||||
llvm::Value *LiftPcFromCurrPc(llvm::IRBuilder<> &, llvm::Value *, size_t,
|
||||
const DecodingContext &) const override;
|
||||
|
||||
void InitializeSleighContext(uint64_t addr,
|
||||
remill::sleigh::SingleInstructionSleighContext &,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Arch.h"
|
||||
#include "PPC.h"
|
||||
|
||||
#define INCLUDED_FROM_REMILL
|
||||
@@ -26,12 +27,15 @@ namespace sleighppc {
|
||||
static constexpr auto kPPCVLERegName = "VLEReg";
|
||||
|
||||
SleighPPCDecoder::SleighPPCDecoder(const remill::Arch &arch)
|
||||
: SleighDecoder(arch, "ppc_64_isa_vle_be.sla", "ppc_64.pspec",
|
||||
{{"vle", kPPCVLERegName}}, {}) {}
|
||||
: SleighDecoder(
|
||||
arch, "ppc_64_isa_vle_be.sla", "ppc_64.pspec",
|
||||
sleigh::ContextRegMappings({{"vle", kPPCVLERegName}}, {{"vle", 1}}),
|
||||
{}) {}
|
||||
|
||||
llvm::Value *SleighPPCDecoder::LiftPcFromCurrPc(llvm::IRBuilder<> &bldr,
|
||||
llvm::Value *curr_pc,
|
||||
size_t curr_insn_size) const {
|
||||
size_t curr_insn_size,
|
||||
const DecodingContext &) const {
|
||||
// PC on thumb points to the next instructions next.
|
||||
return bldr.CreateAdd(
|
||||
curr_pc, llvm::ConstantInt::get(curr_pc->getType(), curr_insn_size));
|
||||
|
||||
@@ -20,7 +20,8 @@ class SleighAArch32ThumbDecoder final : public remill::sleigh::SleighDecoder {
|
||||
|
||||
|
||||
virtual llvm::Value *LiftPcFromCurrPc(llvm::IRBuilder<> &bldr, llvm::Value *,
|
||||
size_t curr_insn_size) const final;
|
||||
size_t curr_insn_size,
|
||||
const DecodingContext &) const final;
|
||||
|
||||
void
|
||||
InitializeSleighContext(uint64_t addr,
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
#include <remill/Arch/AArch32/AArch32Base.h>
|
||||
#include <remill/Arch/AArch32/ArchContext.h>
|
||||
#include <remill/Arch/AArch32/Runtime/State.h>
|
||||
#include <remill/Arch/Context.h>
|
||||
#include <remill/Arch/Name.h>
|
||||
#include <remill/BC/ABI.h>
|
||||
#include <remill/BC/Util.h>
|
||||
#include <remill/BC/Version.h>
|
||||
#include <remill/OS/OS.h>
|
||||
|
||||
#include "AArch32Arch.h"
|
||||
#include "Arch.h"
|
||||
#include "Thumb.h"
|
||||
|
||||
@@ -33,7 +35,9 @@ namespace sleighthumb2 {
|
||||
// TODO(Ian): support different arm versions
|
||||
SleighAArch32ThumbDecoder::SleighAArch32ThumbDecoder(const remill::Arch &arch)
|
||||
: SleighDecoder(arch, "ARM8_le.sla", "ARMtTHUMB.pspec",
|
||||
{{"ISAModeSwitch", std::string(kThumbModeRegName)}},
|
||||
sleigh::ContextRegMappings(
|
||||
{{"ISAModeSwitch", std::string(kThumbModeRegName)}},
|
||||
{{"ISAModeSwitch", 1}}),
|
||||
{{"CY", "C"}, {"NG", "N"}, {"ZR", "Z"}, {"OV", "V"}}) {}
|
||||
|
||||
|
||||
@@ -44,14 +48,13 @@ void SleighAArch32ThumbDecoder::InitializeSleighContext(
|
||||
addr, std::string(kThumbModeRegName).c_str(), "TMode", 1, ctxt, values);
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
SleighAArch32ThumbDecoder::LiftPcFromCurrPc(llvm::IRBuilder<> &bldr,
|
||||
llvm::Value *curr_pc,
|
||||
size_t curr_insn_size) const {
|
||||
|
||||
llvm::Value *SleighAArch32ThumbDecoder::LiftPcFromCurrPc(
|
||||
llvm::IRBuilder<> &bldr, llvm::Value *curr_pc, size_t curr_insn_size,
|
||||
const DecodingContext &context) const {
|
||||
// PC on thumb points to the next instructions next.
|
||||
return bldr.CreateAdd(
|
||||
curr_pc, llvm::ConstantInt::get(curr_pc->getType(), curr_insn_size * 2));
|
||||
curr_pc, llvm::ConstantInt::get(curr_pc->getType(),
|
||||
(AArch32Arch::IsThumb(context) ? 4 : 8)));
|
||||
}
|
||||
|
||||
//TODO(Ian): this has code duplication with SleighX86Arch couldnt come up with a way to share implementation and not run into more
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <remill/Arch/Context.h>
|
||||
#include <remill/Arch/Name.h>
|
||||
#include <remill/Arch/X86/X86Base.h>
|
||||
#include <remill/BC/ABI.h>
|
||||
@@ -39,7 +40,7 @@ class SleighX86Decoder final : public SleighDecoder {
|
||||
: SleighDecoder(
|
||||
arch, kArchX86_SLEIGH == arch.arch_name ? "x86.sla" : "x86-64.sla",
|
||||
kArchX86_SLEIGH == arch.arch_name ? "x86.pspec" : "x86-64.pspec",
|
||||
{}, {}) {}
|
||||
ContextRegMappings({}, {}), {}) {}
|
||||
|
||||
// The x86 default context is sufficient. No context register assignments are required.
|
||||
void
|
||||
@@ -48,7 +49,8 @@ class SleighX86Decoder final : public SleighDecoder {
|
||||
const ContextValues &) const override {}
|
||||
|
||||
llvm::Value *LiftPcFromCurrPc(llvm::IRBuilder<> &bldr, llvm::Value *curr_pc,
|
||||
size_t curr_insn_size) const final {
|
||||
size_t curr_insn_size,
|
||||
const DecodingContext &) const final {
|
||||
|
||||
// PC on thumb points to the next instructions next.
|
||||
return bldr.CreateAdd(
|
||||
|
||||
+95
-14
@@ -19,13 +19,17 @@
|
||||
#include <lib/Arch/Sleigh/ControlFlowStructuring.h>
|
||||
#include <llvm/ADT/StringExtras.h>
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Value.h>
|
||||
#include <llvm/IR/Verifier.h>
|
||||
#include <remill/Arch/Context.h>
|
||||
#include <remill/Arch/Name.h>
|
||||
#include <remill/Arch/Runtime/HyperCall.h>
|
||||
#include <remill/BC/ABI.h>
|
||||
#include <remill/BC/InstructionLifter.h>
|
||||
#include <remill/BC/IntrinsicTable.h>
|
||||
#include <remill/BC/PCodeCFG.h>
|
||||
#include <remill/BC/SleighLifter.h>
|
||||
@@ -35,12 +39,12 @@
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
#include <sleigh/pcoderaw.hh>
|
||||
#include <sleigh/sleigh.hh>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
|
||||
#include "remill/BC/InstructionLifter.h"
|
||||
|
||||
|
||||
namespace remill {
|
||||
|
||||
@@ -133,7 +137,68 @@ class SleighLifter::PcodeToLLVMEmitIntoBlock {
|
||||
|
||||
using ParamPtr = std::shared_ptr<Parameter>;
|
||||
|
||||
public:
|
||||
class DecodingContextConstants {
|
||||
private:
|
||||
const sleigh::ContextRegMappings &sleigh_to_remill_reg;
|
||||
llvm::LLVMContext &context;
|
||||
const ContextValues &context_values;
|
||||
std::unordered_map<std::string, llvm::Value *> regptrs;
|
||||
|
||||
|
||||
void PrepareEntryBlock(llvm::BasicBlock *entry) {
|
||||
llvm::IRBuilder<> builder(entry);
|
||||
|
||||
for (const auto &[k, v] : this->sleigh_to_remill_reg.GetSizeMapping()) {
|
||||
auto ity = llvm::IntegerType::get(this->context, v * 8);
|
||||
auto reg_ptr = builder.CreateAlloca(ity, nullptr, k);
|
||||
regptrs.emplace(k, reg_ptr);
|
||||
|
||||
|
||||
auto maybe_reg =
|
||||
this->sleigh_to_remill_reg.GetInternalRegMapping().find(k);
|
||||
|
||||
if (maybe_reg ==
|
||||
this->sleigh_to_remill_reg.GetInternalRegMapping().end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto maybe_value = context_values.find(maybe_reg->second);
|
||||
if (maybe_value == context_values.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.CreateStore(llvm::ConstantInt::get(ity, maybe_value->second),
|
||||
reg_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DecodingContextConstants(
|
||||
const sleigh::ContextRegMappings &sleigh_to_remill_reg,
|
||||
llvm::LLVMContext &context, const ContextValues &context_values,
|
||||
llvm::BasicBlock *target_block)
|
||||
: sleigh_to_remill_reg(sleigh_to_remill_reg),
|
||||
context(context),
|
||||
context_values(context_values) {
|
||||
this->PrepareEntryBlock(target_block);
|
||||
}
|
||||
|
||||
|
||||
std::optional<ParamPtr>
|
||||
LiftRegisterFromDecodingContext(std::string target_reg,
|
||||
VarnodeData target_vnode) {
|
||||
auto maybe_reg = this->regptrs.find(target_reg);
|
||||
if (maybe_reg == this->regptrs.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
return RegisterValue::CreateRegister(maybe_reg->second);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
class RegisterValue : public Parameter {
|
||||
private:
|
||||
llvm::Value *register_pointer;
|
||||
@@ -350,6 +415,8 @@ class SleighLifter::PcodeToLLVMEmitIntoBlock {
|
||||
|
||||
std::unordered_map<size_t, llvm::BasicBlock *> start_index_to_block;
|
||||
|
||||
DecodingContextConstants context_reg_lifter;
|
||||
|
||||
|
||||
void UpdateStatus(LiftStatus new_status, OpCode opc) {
|
||||
if (new_status != LiftStatus::kLiftedInstruction) {
|
||||
@@ -381,12 +448,12 @@ class SleighLifter::PcodeToLLVMEmitIntoBlock {
|
||||
return newblk;
|
||||
}
|
||||
|
||||
PcodeToLLVMEmitIntoBlock(llvm::BasicBlock *target_block,
|
||||
llvm::Value *state_pointer, const Instruction &insn,
|
||||
SleighLifter &insn_lifter_parent,
|
||||
std::vector<std::string> user_op_names_,
|
||||
llvm::BasicBlock *exit_block_,
|
||||
const sleigh::MaybeBranchTakenVar &to_lift_btaken_)
|
||||
PcodeToLLVMEmitIntoBlock(
|
||||
llvm::BasicBlock *target_block, llvm::Value *state_pointer,
|
||||
const Instruction &insn, SleighLifter &insn_lifter_parent,
|
||||
std::vector<std::string> user_op_names_, llvm::BasicBlock *exit_block_,
|
||||
const sleigh::MaybeBranchTakenVar &to_lift_btaken_,
|
||||
PcodeToLLVMEmitIntoBlock::DecodingContextConstants context_reg_lifter)
|
||||
: target_block(target_block),
|
||||
state_pointer(state_pointer),
|
||||
context(target_block->getContext()),
|
||||
@@ -399,7 +466,8 @@ class SleighLifter::PcodeToLLVMEmitIntoBlock {
|
||||
entry_block(target_block),
|
||||
exit_block(exit_block_),
|
||||
curr_id(0),
|
||||
to_lift_btaken(to_lift_btaken_) {}
|
||||
to_lift_btaken(to_lift_btaken_),
|
||||
context_reg_lifter(std::move(context_reg_lifter)) {}
|
||||
|
||||
|
||||
ParamPtr CreateMemoryAddress(llvm::Value *offset) {
|
||||
@@ -443,6 +511,11 @@ class SleighLifter::PcodeToLLVMEmitIntoBlock {
|
||||
return *res;
|
||||
}
|
||||
|
||||
if (auto res = this->context_reg_lifter.LiftRegisterFromDecodingContext(
|
||||
reg_name, target_vnode)) {
|
||||
return *res;
|
||||
}
|
||||
|
||||
// Uniques must be allocated in the entry block
|
||||
llvm::IRBuilder<> entry_bldr(entry_block);
|
||||
|
||||
@@ -1616,9 +1689,17 @@ SleighLifter::LiftIntoInternalBlockWithSleighState(
|
||||
|
||||
auto cfg = sleigh::CreateCFG(pcode_record.ops);
|
||||
|
||||
|
||||
SleighLifter::PcodeToLLVMEmitIntoBlock::DecodingContextConstants
|
||||
decoding_context_lifter(this->decoder.GetContextRegisterMapping(),
|
||||
target_mod->getContext(), context_values,
|
||||
target_block);
|
||||
|
||||
SleighLifter::PcodeToLLVMEmitIntoBlock lifter(
|
||||
target_block, internal_state_pointer, inst, *this,
|
||||
this->sleigh_context->getUserOpNames(), exit_block, btaken);
|
||||
this->sleigh_context->getUserOpNames(), exit_block, btaken,
|
||||
std::move(decoding_context_lifter));
|
||||
|
||||
|
||||
for (auto blk : cfg.blocks) {
|
||||
lifter.VisitBlock(blk.second);
|
||||
@@ -1675,10 +1756,10 @@ LiftStatus SleighLifter::LiftIntoBlockWithSleighState(
|
||||
intoblock_builer.CreateLoad(this->GetWordType(), next_pc_ref);
|
||||
|
||||
|
||||
intoblock_builer.CreateStore(
|
||||
this->decoder.LiftPcFromCurrPc(intoblock_builer, next_pc,
|
||||
inst.bytes.size()),
|
||||
pc_ref);
|
||||
intoblock_builer.CreateStore(this->decoder.LiftPcFromCurrPc(
|
||||
intoblock_builer, next_pc, inst.bytes.size(),
|
||||
DecodingContext(context_values)),
|
||||
pc_ref);
|
||||
intoblock_builer.CreateStore(
|
||||
intoblock_builer.CreateAdd(
|
||||
next_pc,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
From e3103b7e5e1b1eca4e175f833fa43dced2298de1 Mon Sep 17 00:00:00 2001
|
||||
From: 2over12 <ian.smith@trailofbits.com>
|
||||
Date: Tue, 4 Apr 2023 12:26:56 -0400
|
||||
Subject: [PATCH] ARM
|
||||
|
||||
---
|
||||
Ghidra/Processors/ARM/data/languages/ARM.sinc | 17 ++++++++++++++++-
|
||||
1 file changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Ghidra/Processors/ARM/data/languages/ARM.sinc b/Ghidra/Processors/ARM/data/languages/ARM.sinc
|
||||
index 5869bfe29..76e810e1a 100644
|
||||
--- a/Ghidra/Processors/ARM/data/languages/ARM.sinc
|
||||
+++ b/Ghidra/Processors/ARM/data/languages/ARM.sinc
|
||||
@@ -2,6 +2,13 @@
|
||||
# The following boolean defines control specific support: T_VARIANT, VERSION_5, VERSION_5E
|
||||
|
||||
define endian=$(ENDIAN);
|
||||
+# so the trick here is to define an INST_NEXT_PTR that works in either context
|
||||
+# subtracting tmode from 2 means if it is 1 get 1 *4 which is the correct normalization for thumb, if it is 0
|
||||
+# we get 8
|
||||
+
|
||||
+@define INST_NEXT_PTR "(pc-((2 - zext(ISAModeSwitch))*4)) + remill_insn_size"
|
||||
+define pcodeop claim_eq;
|
||||
+
|
||||
define alignment=2;
|
||||
|
||||
define space ram type=ram_space size=4 default;
|
||||
@@ -238,6 +245,9 @@ macro ALUWritePC(addr) {
|
||||
|
||||
@if defined(T_VARIANT)
|
||||
|
||||
+
|
||||
+remill_insn_size: calculated_size is epsilon [calculated_size= inst_next-inst_start; ] { local insn_size_hinted:4=calculated_size;
|
||||
+ export insn_size_hinted; }
|
||||
ItCond: is TMode=1 { }
|
||||
CheckInIT_CZNO: is TMode=1 { CY = tmpCY; ZR = tmpZR; NG = tmpNG; OV = tmpOV; } # in older, arms always affect flags
|
||||
CheckInIT_CZN: is TMode=1 { CY = tmpCY; ZR = tmpZR; NG = tmpNG; } # in older, arms always affect flags
|
||||
@@ -274,7 +284,12 @@ ItCond: "."thfcc is TMode=1 & itmode=0 & cond_mask & thfcc [ itmode=1; globa
|
||||
|
||||
# last ITBlock then/else case - the condition being tested is modified by the shift below
|
||||
ItCond: "."thfcc is TMode=1 & itmode=0 & cond_mask=8 & thfcc
|
||||
- { if (!thfcc) goto inst_next; }
|
||||
+ ; remill_insn_size {
|
||||
+remill_please_dont_use_this_temp_name29:4=inst_next;
|
||||
+claim_eq(remill_please_dont_use_this_temp_name29, $(INST_NEXT_PTR));
|
||||
+ if (!thfcc) goto inst_next;
|
||||
+ }
|
||||
+
|
||||
|
||||
# certain Thumb instructions don't affect all flags in the IT block
|
||||
CheckInIT_CZNO: is TMode=1 & itmode=1 & cond_mask { } # Do nothing to the flag bits
|
||||
--
|
||||
2.39.2 (Apple Git-143)
|
||||
|
||||
@@ -1,34 +1,17 @@
|
||||
From 32ae2981ed8033a08b7be56387275f84edfee2b3 Mon Sep 17 00:00:00 2001
|
||||
From 302ca3885c87bad3eb00f956db937ec50564d50d Mon Sep 17 00:00:00 2001
|
||||
From: 2over12 <ian.smith@trailofbits.com>
|
||||
Date: Sat, 8 Oct 2022 09:22:46 -0400
|
||||
Subject: [PATCH] ARMThumbPcRel
|
||||
Date: Tue, 4 Apr 2023 12:26:56 -0400
|
||||
Subject: [PATCH] ARMTHUMBinstructions
|
||||
|
||||
---
|
||||
.../data/languages/ARMTHUMBinstructions.sinc | 503 +++++++++++++-----
|
||||
1 file changed, 373 insertions(+), 130 deletions(-)
|
||||
.../data/languages/ARMTHUMBinstructions.sinc | 497 +++++++++++++-----
|
||||
1 file changed, 367 insertions(+), 130 deletions(-)
|
||||
|
||||
diff --git a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
|
||||
index daf705731..a97c86b60 100644
|
||||
index daf705731..48efb70e0 100644
|
||||
--- a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
|
||||
+++ b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
|
||||
@@ -1,3 +1,6 @@
|
||||
+
|
||||
+@define INST_NEXT_PTR "(pc-2)"
|
||||
+define pcodeop claim_eq;
|
||||
# Specification for the THUMB Version 2
|
||||
# This closely follows
|
||||
# "Architecture Reference Manual" Second Edition Edited by David Seal
|
||||
@@ -266,6 +269,9 @@ macro th_affectflags() {
|
||||
|
||||
# conditionals for the branch instruction
|
||||
|
||||
+
|
||||
+remill_insn_size: calculated_size is epsilon [calculated_size= inst_next-inst_start; ] { local insn_size_hinted:4=calculated_size;
|
||||
+ export insn_size_hinted; }
|
||||
thcc: "eq" is thcond=0 { tmp:1 = (ZR!=0); export tmp; }
|
||||
thcc: "ne" is thcond=1 { tmp:1 = (ZR==0); export tmp; }
|
||||
thcc: "cs" is thcond=2 { tmp:1 = (CY!=0); export tmp; }
|
||||
@@ -350,15 +356,33 @@ thSBIT_ZN: "s" is thc0404=1 { ZR = tmpZR; NG = tmpNG; }
|
||||
@@ -350,15 +350,33 @@ thSBIT_ZN: "s" is thc0404=1 { ZR = tmpZR; NG = tmpNG; }
|
||||
|
||||
Hrd0002: Rd0002 is Rd0002 & h1=0 { export Rd0002; }
|
||||
Hrd0002: hrd0002 is hrd0002 & h1=1 { export hrd0002; }
|
||||
@@ -65,7 +48,7 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
@if defined(VERSION_6T2) || defined(VERSION_7)
|
||||
Immed8_4: "#"^immval is immed8 [ immval = immed8 * 4; ] { export *[const]:4 immval; }
|
||||
@@ -369,19 +393,25 @@ Immed8: "#"^immed8 is immed8 { export *[const]:4 immed8; }
|
||||
@@ -369,19 +387,25 @@ Immed8: "#"^immed8 is immed8 { export *[const]:4 immed8; }
|
||||
Immed3: "#"^immed3 is immed3 { export *[const]:4 immed3; }
|
||||
|
||||
Pcrel8: [reloc] is immed8
|
||||
@@ -99,7 +82,7 @@ index daf705731..a97c86b60 100644
|
||||
@endif # defined(VERSION_6T2) || defined(VERSION_7)
|
||||
|
||||
|
||||
@@ -405,29 +435,41 @@ Immed16: "#"^immed16 is immed12_i & sop0003; immed12_imm3 & immed12_imm8
|
||||
@@ -405,29 +429,41 @@ Immed16: "#"^immed16 is immed12_i & sop0003; immed12_imm3 & immed12_imm8
|
||||
}
|
||||
|
||||
PcrelImmed12Addr: reloc is immed12_i; immed12_imm3 & immed12_imm8
|
||||
@@ -157,7 +140,7 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
@endif # defined(VERSION_6T2) || defined(VERSION_7)
|
||||
|
||||
@@ -532,64 +574,91 @@ thshift2: Rm0003, "ror #"^shftval is imm3_shft & imm2_shft & thc0405=3 & Rm0003
|
||||
@@ -532,64 +568,91 @@ thshift2: Rm0003, "ror #"^shftval is imm3_shft & imm2_shft & thc0405=3 & Rm0003
|
||||
@endif # VERSION_6T2 || VERSION_7
|
||||
|
||||
Addr5: reloc is imm5 & thc0909
|
||||
@@ -285,7 +268,7 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
@endif # VERSION_5
|
||||
|
||||
@@ -844,7 +913,13 @@ thldrlist_dec: { thrldec1 } is thc0000=0 & thrldec1 { }
|
||||
@@ -844,7 +907,13 @@ thldrlist_dec: { thrldec1 } is thc0000=0 & thrldec1 { }
|
||||
@endif # defined(VERSION_6T2) || defined(VERSION_7)
|
||||
|
||||
# thstrlist_dec is the list of registers to be pushed
|
||||
@@ -300,7 +283,7 @@ index daf705731..a97c86b60 100644
|
||||
thsdec15: is thc1515=0 { }
|
||||
thsdec14: lr thsdec15 is thc1414=1 & thsdec15 & lr & thc1515=0 { * mult_addr=lr; mult_addr = mult_addr - 4; }
|
||||
thsdec14: lr^"," thsdec15 is thc1414=1 & thsdec15 & lr { * mult_addr=lr; mult_addr = mult_addr - 4; }
|
||||
@@ -931,10 +1006,13 @@ RnIndirect1: [Rn0305,"#"^immed5] is Rn0305 & immed5 { local tmp = Rn0305 + immed
|
||||
@@ -931,10 +1000,13 @@ RnIndirect1: [Rn0305,"#"^immed5] is Rn0305 & immed5 { local tmp = Rn0305 + immed
|
||||
RnRmIndirect: [Rn0305,Rm0608] is Rn0305 & Rm0608 { local tmp = Rn0305 + Rm0608; export tmp; }
|
||||
|
||||
Pcrel8Indirect: [reloc] is immed8
|
||||
@@ -318,13 +301,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
Sprel8Indirect: [sp,"#"^immval] is sp & immed8 [ immval = immed8 * 4; ] { local tmp = sp + immval; export tmp; }
|
||||
|
||||
@@ -1435,12 +1513,19 @@ macro th_set_carry_for_asr(op1,shift_count) {
|
||||
@@ -1435,12 +1507,19 @@ macro th_set_carry_for_asr(op1,shift_count) {
|
||||
@endif # VERSION_5
|
||||
|
||||
:bl^ItCond ThAddr24 is TMode=1 & ItCond & (op11=0x1e; part2c1415=3 & part2c1212=1) & ThAddr24
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+remill_please_dont_use_this_temp_name31b:4=inst_next;
|
||||
+claim_eq(remill_please_dont_use_this_temp_name31b, $(INST_NEXT_PTR));
|
||||
@@ -341,13 +324,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
@ifndef VERSION_6T2
|
||||
|
||||
@@ -1470,12 +1555,19 @@ macro th_set_carry_for_asr(op1,shift_count) {
|
||||
@@ -1470,12 +1549,19 @@ macro th_set_carry_for_asr(op1,shift_count) {
|
||||
@endif
|
||||
|
||||
:bl^ItCond ThAddr24 is TMode=1 & CALLoverride=1 & ItCond & (op11=0x1e; part2c1415=3 & part2c1212=1) & ThAddr24
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+remill_please_dont_use_this_temp_name31d:4=inst_next;
|
||||
+claim_eq(remill_please_dont_use_this_temp_name31d, $(INST_NEXT_PTR));
|
||||
@@ -364,13 +347,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
bxns: "" is thc0003 { }
|
||||
bxns: "ns" is thc0002=0b100 { }
|
||||
@@ -1508,13 +1600,21 @@ bxns: "ns" is thc0002=0b100 { }
|
||||
@@ -1508,13 +1594,21 @@ bxns: "ns" is thc0002=0b100 { }
|
||||
}
|
||||
|
||||
:blx^bxns^ItCond Hrm0305 is TMode=1 & ItCond & op7=0x08f & Hrm0305 & bxns
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
BXWritePC(Hrm0305);
|
||||
@@ -389,13 +372,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
@endif # VERSION_5
|
||||
|
||||
@@ -1592,13 +1692,22 @@ bxns: "ns" is thc0002=0b100 { }
|
||||
@@ -1592,13 +1686,22 @@ bxns: "ns" is thc0002=0b100 { }
|
||||
define pcodeop IndexCheck;
|
||||
|
||||
:chka^ItCond Hrn0002,Rm0306 is TMode=1 & ItCond & TEEMode=1 & op8=0xca & Rm0306 & Hrn0002
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Hrn0002 <= Rm0306;
|
||||
@@ -415,13 +398,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
:clrex^ItCond is TMode=1 & ItCond & op0=0xf3bf; op0=0x8f2f
|
||||
{
|
||||
@@ -2691,24 +2800,40 @@ primask: "primask" is epsilon {}
|
||||
@@ -2691,24 +2794,40 @@ primask: "primask" is epsilon {}
|
||||
basepri: "basepri" is epsilon {}
|
||||
|
||||
:mrs^ItCond Rd0811,basepri is TMode=1 & ItCond & op0=0xf3ef; op12=0x8 & Rd0811 & sysm=17 & basepri
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
Rd0811 = 0;
|
||||
@@ -443,7 +426,7 @@ index daf705731..a97c86b60 100644
|
||||
:mrs^ItCond Rd0811,basepri_max is TMode=1 & ItCond & op0=0xf3ef; op12=0x8 & Rd0811 & sysm=18 & basepri_max
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
Rd0811 = 0;
|
||||
@@ -462,13 +445,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
faultmask: "faultmask" is epsilon {}
|
||||
|
||||
@@ -2781,20 +2906,34 @@ define pcodeop setProcessStackPointer;
|
||||
@@ -2781,20 +2900,34 @@ define pcodeop setProcessStackPointer;
|
||||
define pcodeop setBasePriority;
|
||||
|
||||
:msr^ItCond msp,Rn0003 is TMode=1 & ItCond & op4=0xf38 & Rn0003; op12=0x8 & th_psrmask=8 & sysm=8 & msp
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
b:1 = isCurrentModePrivileged();
|
||||
@@ -486,7 +469,7 @@ index daf705731..a97c86b60 100644
|
||||
:msr^ItCond psp,Rn0003 is TMode=1 & ItCond & op4=0xf38 & Rn0003; op12=0x8 & th_psrmask=8 & sysm=9 & psp
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
b:1 = isCurrentModePrivileged();
|
||||
@@ -503,13 +486,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
:msr^ItCond primask,Rn0003 is TMode=1 & ItCond & op4=0xf38 & Rn0003; op12=0x8 & th_psrmask=8 & sysm=16 & primask
|
||||
{
|
||||
@@ -2805,12 +2944,19 @@ define pcodeop setBasePriority;
|
||||
@@ -2805,12 +2938,19 @@ define pcodeop setBasePriority;
|
||||
}
|
||||
|
||||
:msr^ItCond basepri,Rn0003 is TMode=1 & ItCond & op4=0xf38 & Rn0003; op12=0x8 & th_psrmask=8 & sysm=17 & basepri
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
b:1 = isCurrentModePrivileged();
|
||||
@@ -526,13 +509,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
:msr^ItCond basepri_max,Rn0003 is TMode=1 & ItCond & op4=0xf38 & Rn0003; op12=0x8 & th_psrmask=8 & sysm=18 & basepri_max
|
||||
{
|
||||
@@ -2825,12 +2971,19 @@ define pcodeop setBasePriority;
|
||||
@@ -2825,12 +2965,19 @@ define pcodeop setBasePriority;
|
||||
}
|
||||
|
||||
:msr^ItCond faultmask,Rn0003 is TMode=1 & ItCond & op4=0xf38 & Rn0003; op12=0x8 & th_psrmask=8 & sysm=19 & faultmask
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
b:1 = isCurrentModePrivileged();
|
||||
@@ -549,13 +532,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
define pcodeop setStackMode;
|
||||
|
||||
@@ -4446,56 +4599,100 @@ thumbEndianNess: "BE" is op0=0xb658 { export 1:1; }
|
||||
@@ -4446,56 +4593,100 @@ thumbEndianNess: "BE" is op0=0xb658 { export 1:1; }
|
||||
}
|
||||
|
||||
:strex^ItCond Rd0811,Rt1215,[Rn0003,Immed8_4] is TMode=1 & ItCond & op4=0xe84 & Rn0003; Rt1215 & Rd0811 & Immed8_4
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Rn0003 + Immed8_4;
|
||||
@@ -583,7 +566,7 @@ index daf705731..a97c86b60 100644
|
||||
:strexb^ItCond Rd0003,Rt1215,[Rn0003] is TMode=1 & ItCond & op4=0xe8c & Rn0003; Rt1215 & thc0811=15 & thc0407=4 & Rd0003
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Rn0003;
|
||||
@@ -609,7 +592,7 @@ index daf705731..a97c86b60 100644
|
||||
:strexh^ItCond Rd0003,Rt1215,[Rn0003] is TMode=1 & ItCond & op4=0xe8c & Rn0003; Rt1215 & thc0811=15 & thc0407=5 & Rd0003
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Rn0003;
|
||||
@@ -635,7 +618,7 @@ index daf705731..a97c86b60 100644
|
||||
:strexd^ItCond Rd0003,Rt1215,Rt0811,[Rn0003] is TMode=1 & ItCond & op4=0xe8c & Rn0003; Rt1215 & Rt0811 & thc0407=7 & Rd0003
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Rn0003;
|
||||
@@ -662,13 +645,13 @@ index daf705731..a97c86b60 100644
|
||||
|
||||
@endif # VERSION_7
|
||||
|
||||
@@ -4746,49 +4943,95 @@ thumbEndianNess: "BE" is op0=0xb658 { export 1:1; }
|
||||
@@ -4746,49 +4937,95 @@ thumbEndianNess: "BE" is op0=0xb658 { export 1:1; }
|
||||
@if defined(VERSION_6T2) || defined(VERSION_7)
|
||||
|
||||
:tbb^ItCond [Rn0003,Rm0003] is TMode=1 & ItCond & op4=0xe8d & Rn0003; op8=0xf0 & thc0507=0 & thc0404=0 & Rm0003
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Rn0003 + Rm0003;
|
||||
@@ -690,7 +673,7 @@ index daf705731..a97c86b60 100644
|
||||
:tbh^ItCond [Rn0003,Rm0003] is TMode=1 & ItCond & op4=0xe8d & Rn0003; op8=0xf0 & thc0507=0 & thc0404=1 & Rm0003
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
local tmp = Rn0003 + (Rm0003 * 2);
|
||||
@@ -717,7 +700,7 @@ index daf705731..a97c86b60 100644
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+Pcrel: [cloc,Rm0003] is Rm0003 & thc0404=0 [ cloc = inst_next; ] {
|
||||
+Pcrel: [cloc,Rm0003] is Rm0003 & thc0404=0 ; remill_insn_size [ cloc = inst_next; ] {
|
||||
+ local tmp = Rm0003;
|
||||
+remill_please_dont_use_this_temp_name5cb:4=cloc;
|
||||
+claim_eq(remill_please_dont_use_this_temp_name5cb, $(INST_NEXT_PTR));
|
||||
@@ -728,7 +711,7 @@ index daf705731..a97c86b60 100644
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+Pcrel: [cloc,Rm0003] is Rm0003 & thc0404=1 [ cloc = inst_next; ] {
|
||||
+Pcrel: [cloc,Rm0003] is Rm0003 & thc0404=1 ; remill_insn_size [ cloc = inst_next; ] {
|
||||
+ local tmp = Rm0003;
|
||||
+remill_please_dont_use_this_temp_name5ce:4=cloc;
|
||||
+claim_eq(remill_please_dont_use_this_temp_name5ce, $(INST_NEXT_PTR));
|
||||
@@ -743,7 +726,7 @@ index daf705731..a97c86b60 100644
|
||||
:tbb^ItCond Pcrel is TMode=1 & ItCond & op4=0xe8d & thc0003=15; op8=0xf0 & thc0507=0 & thc0404=0 & Pcrel
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
SetThumbMode(1);
|
||||
@@ -761,7 +744,7 @@ index daf705731..a97c86b60 100644
|
||||
:tbh^ItCond Pcrel is TMode=1 & ItCond & op4=0xe8d & thc0003=15; op8=0xf0 & thc0507=0 & thc0404=1 & Pcrel
|
||||
-{
|
||||
- build ItCond;
|
||||
+ {
|
||||
+ ; remill_insn_size {
|
||||
+ build ItCond;
|
||||
+
|
||||
SetThumbMode(1);
|
||||
@@ -779,5 +762,5 @@ index daf705731..a97c86b60 100644
|
||||
@endif # VERSION_6T2 || VERSION_7
|
||||
|
||||
--
|
||||
2.37.0 (Apple Git-136)
|
||||
2.39.2 (Apple Git-143)
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
@define INST_NEXT_PTR "(pc-2)"
|
||||
# so the trick here is to define an INST_NEXT_PTR that works in either context
|
||||
# subtracting tmode from 2 means if it is 1 get 1 *4 which is the correct normalization for thumb, if it is 0
|
||||
# we get 8
|
||||
|
||||
@define INST_NEXT_PTR "(pc-((2 - zext(ISAModeSwitch))*4)) + remill_insn_size"
|
||||
@@ -93,7 +93,7 @@ class InstNextReplacer(ExpressionReplacer):
|
||||
|
||||
@property
|
||||
def required_invisible_operands(self) -> List[str]:
|
||||
return []
|
||||
return [REMILL_INSN_SIZE_NAME]
|
||||
|
||||
|
||||
class Environment:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <test_runner/TestRunner.h>
|
||||
|
||||
#include <any>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -29,8 +30,9 @@
|
||||
namespace test_runner {
|
||||
|
||||
using MemoryModifier = std::function<void(MemoryHandler &)>;
|
||||
using RegisterValue = std::variant<uint64_t, uint8_t>;
|
||||
using RegisterValue = std::variant<uint64_t, uint32_t, uint8_t>;
|
||||
using RegisterValueRef = std::variant<std::reference_wrapper<uint64_t>,
|
||||
std::reference_wrapper<uint32_t>,
|
||||
std::reference_wrapper<uint8_t>>;
|
||||
|
||||
struct RegisterCondition {
|
||||
|
||||
+73
-17
@@ -43,17 +43,29 @@
|
||||
#include <variant>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test_runner/TestOutputSpec.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
const static std::unordered_map<std::string,
|
||||
std::function<uint32_t &(AArch32State &)>>
|
||||
const static std::unordered_map<
|
||||
std::string, std::function<test_runner::RegisterValueRef(AArch32State &)>>
|
||||
reg_to_accessor = {
|
||||
{"r15",
|
||||
[](AArch32State &st) -> uint32_t & { return st.gpr.r15.dword; }},
|
||||
{"sp", [](AArch32State &st) -> uint32_t & { return st.gpr.r13.dword; }},
|
||||
{"r1", [](AArch32State &st) -> uint32_t & { return st.gpr.r1.dword; }}};
|
||||
[](AArch32State &st) -> test_runner::RegisterValueRef {
|
||||
return st.gpr.r15.dword;
|
||||
}},
|
||||
{"sp",
|
||||
[](AArch32State &st) -> test_runner::RegisterValueRef {
|
||||
return st.gpr.r13.dword;
|
||||
}},
|
||||
{"r1",
|
||||
[](AArch32State &st) -> test_runner::RegisterValueRef {
|
||||
return st.gpr.r1.dword;
|
||||
}},
|
||||
{"z", [](AArch32State &st) -> test_runner::RegisterValueRef {
|
||||
return st.sr.z;
|
||||
}}};
|
||||
|
||||
|
||||
std::optional<remill::Instruction> GetFlows(std::string_view bytes,
|
||||
@@ -83,7 +95,7 @@ using MemoryModifier = std::function<void(test_runner::MemoryHandler &)>;
|
||||
|
||||
struct RegisterPrecondition {
|
||||
std::string register_name;
|
||||
uint32_t enforced_value;
|
||||
test_runner::RegisterValue enforced_value;
|
||||
};
|
||||
|
||||
class TestOutputSpec {
|
||||
@@ -97,20 +109,47 @@ class TestOutputSpec {
|
||||
std::vector<RegisterPrecondition> register_postconditions;
|
||||
std::vector<MemoryModifier> initial_memory_conditions;
|
||||
|
||||
template <typename T>
|
||||
void ApplyCondWithAcc(
|
||||
T value,
|
||||
std::function<test_runner::RegisterValueRef(AArch32State &)> accessor,
|
||||
AArch32State &state) const {
|
||||
std::get<std::reference_wrapper<T>>(accessor(state)).get() = value;
|
||||
}
|
||||
|
||||
void ApplyCondition(AArch32State &state, std::string reg,
|
||||
uint32_t value) const {
|
||||
test_runner::RegisterValue value) const {
|
||||
auto accessor = reg_to_accessor.find(reg);
|
||||
if (accessor != reg_to_accessor.end()) {
|
||||
accessor->second(state) = value;
|
||||
|
||||
if (accessor == reg_to_accessor.end()) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "applying for " << reg;
|
||||
|
||||
std::visit(
|
||||
[&](auto arg) { ApplyCondWithAcc(arg, accessor->second, state); },
|
||||
value);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void CheckRegEq(
|
||||
T value,
|
||||
std::function<test_runner::RegisterValueRef(AArch32State &)> accessor,
|
||||
AArch32State &state) const {
|
||||
auto sval = std::get<std::reference_wrapper<T>>(accessor(state)).get();
|
||||
LOG(INFO) << "state value: " << sval;
|
||||
CHECK_EQ(sval, value);
|
||||
}
|
||||
|
||||
void CheckCondition(AArch32State &state, std::string reg,
|
||||
uint32_t value) const {
|
||||
test_runner::RegisterValue value) const {
|
||||
auto accessor = reg_to_accessor.find(reg);
|
||||
if (accessor != reg_to_accessor.end()) {
|
||||
CHECK_EQ(accessor->second(state), value);
|
||||
if (accessor == reg_to_accessor.end()) {
|
||||
return;
|
||||
}
|
||||
std::visit([&](auto arg) { CheckRegEq(arg, accessor->second, state); },
|
||||
value);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -230,9 +269,9 @@ TEST(ThumbRandomizedLifts, PopPC) {
|
||||
|
||||
llvm::LLVMContext curr_context;
|
||||
std::string insn_data("\x00\xbd", 2);
|
||||
TestOutputSpec spec(0x12, insn_data,
|
||||
remill::Instruction::Category::kCategoryFunctionReturn,
|
||||
{{"r15", 12}, {"sp", 10}}, {{"r15", 16}});
|
||||
TestOutputSpec spec(
|
||||
0x12, insn_data, remill::Instruction::Category::kCategoryFunctionReturn,
|
||||
{{"r15", uint32_t(12)}, {"sp", uint32_t(10)}}, {{"r15", uint32_t(16)}});
|
||||
spec.AddPrecWrite<uint32_t>(10, 16);
|
||||
llvm::LLVMContext context;
|
||||
|
||||
@@ -246,7 +285,7 @@ TEST(ArmRandomizedLifts, RelPcTest) {
|
||||
std::string insn_data("\x0c\x10\x9f\xe5", 4);
|
||||
TestOutputSpec spec(0x12, insn_data,
|
||||
remill::Instruction::Category::kCategoryNormal,
|
||||
{{"r15", 0x12}}, {{"r1", 0xdeadc0de}});
|
||||
{{"r15", uint32_t(0x12)}}, {{"r1", 0xdeadc0de}});
|
||||
// So ok instruction is at 18 which means pc is = 26
|
||||
spec.AddPrecWrite<uint32_t>(38, 0xdeadc0de);
|
||||
llvm::LLVMContext context;
|
||||
@@ -261,7 +300,7 @@ TEST(ThumbRandomizedLifts, RelPcTest) {
|
||||
std::string insn_data("\x03\x49", 2);
|
||||
TestOutputSpec spec(0x12, insn_data,
|
||||
remill::Instruction::Category::kCategoryNormal,
|
||||
{{"r15", 0x12}}, {{"r1", 0xdeadc0de}});
|
||||
{{"r15", uint32_t(0x12)}}, {{"r1", 0xdeadc0de}});
|
||||
// So ok instruction is at 18 which means pc is = 22
|
||||
spec.AddPrecWrite<uint32_t>(32, 0xdeadc0de);
|
||||
llvm::LLVMContext context;
|
||||
@@ -270,6 +309,23 @@ TEST(ThumbRandomizedLifts, RelPcTest) {
|
||||
runner.RunTestSpec(spec);
|
||||
}
|
||||
|
||||
TEST(RegressionTests, RegressionPreffixSuffixInsn) {
|
||||
|
||||
llvm::LLVMContext curr_context;
|
||||
std::string insn_data("\x3f\xf4\x53\xaf", 4);
|
||||
TestOutputSpec spec(
|
||||
0x00014182, insn_data,
|
||||
remill::Instruction::Category::kCategoryConditionalBranch,
|
||||
{{"z", uint8_t(1)}, {"r15", uint32_t(0x14186)}},
|
||||
// since we jump to 0001402c we are going to be 4 bytes ahead at 0x14030
|
||||
{{"r15", uint32_t(0x14030)}});
|
||||
|
||||
llvm::LLVMContext context;
|
||||
|
||||
TestSpecRunner runner(context, remill::ArchName::kArchThumb2LittleEndian);
|
||||
runner.RunTestSpec(spec);
|
||||
}
|
||||
|
||||
TEST(RegressionTests, AARCH64RegSize) {
|
||||
llvm::LLVMContext context;
|
||||
auto arch = remill::Arch::Build(&context, remill::OSName::kOSLinux,
|
||||
|
||||
Reference in New Issue
Block a user