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:
2over12
2023-04-05 10:41:31 -04:00
committed by GitHub
parent 4b2d4c0f29
commit db394b3979
15 changed files with 345 additions and 124 deletions
+1 -3
View File
@@ -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;
+17 -5
View File
@@ -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
View File
@@ -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;
};
+3 -2
View File
@@ -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 &,
+7 -3
View File
@@ -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));
+2 -1
View File
@@ -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,
+10 -7
View File
@@ -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
+4 -2
View File
@@ -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
View File
@@ -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,
+54
View File
@@ -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
View File
@@ -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,