rizin/librz/il/theory_effect.c
Rot127 b46e7bd4f2
PPC uplifting to RzIL (#2823)
* Print a warning if config for VM was NULL.
* Add warning if register is not added to VM due to overlap.
* Update PPC register profile.
* Add vector and float registers. As well as some control and system registers.
* Enable to write values 4bit registers.
* PPC: Uplift most common instructions.
* Print warning if reserved SPR instruction is encountered.
* Update PC/LR addresses and add ca32 writes.
* Write cache needs to get flushed so load and store tests don't share the same memory.
* Add missing T/F branch mnemonics.
* Add Move to/from CR/CR0-7
* Fix TA address calculation for branch instructions.
* Add branch tests for branch mnemonics.
* Add XNOP
* NOP cache touch instructions.
* Add undocumented ATTN instruction to the not_implemented group.
* Add isel instruction.
* Implement CRCLR, CRSET, CROR.
* Add CNTLZ instructions.
* Add mcrf instructions.
* Add inacive test for cmpb.
* Add Load bytes reverse instructions.
* Add test and add address alignment to dcbz.
* Add eqv test
* Correct DIV and MUL operations
* Add div tests.
* Add tests and correct MT/MFXER
* Remove register ca32, ov32
* Remove explici setting of cr register because QEMU does not do it. Otherwise we get a mismatch in the trace
* Simplify carry set for add and sub. Sub instructions are exclusivly defined with addition. Hence no sub case needed.
* Unify BD and fix branch instructions. Fix: Check the single bit not the cr reg
* Document Conditional branches and replace NOPs with EMPTY
* Add mulli instruction to double word instructions.
* Fix ca set for shift instructions:
* ca value had to be determined before the shift happened. The wrong ca value was calculated if the src and target reg were the same.
* Replace NOP wit EMPTY.
* Use MSB isntead of SLT.
* Brought fixup of ADD and SUB instructions: The add and sub instructions had several issues which let to incorrect execution.
* The carry was incorrectly if three add operations happened (only the last add were checked, not both).
* The carry was incorrectly set if the src and target register matched.
* Same applies for the CR bit.
* It was too complex. Several local variables were introduced for this.
* Set result in local var, since it would change if src and target reg are the same.
* Remove MTMSR and MFMSR since it is too complex and untestable currently.
* Use unsigned int for shift. Otherwise the 0x1c shift produces a runtime error since 0xf is int as default.
* Fix mtxer: Only write flag bits.
* Let NOT_IMPLEMENTED macro return NULL.
* Mark st[wd]cx and l[wd]cx as not implemented.
* Increase dcache_line_size to 128 bytes.
* Fix cntlz for ppc32. m was set incorrectly, since it is 0 not 32 for 32bit cpus.
* Fix isel: Use op.crx reg instead of imm.
* Unify helper function names: Prependnig `ppc_` mark as IPI
* Add more "Move to SPR" cases.
* MULLI opeartes only on double word on 64bit CPUs.
* Most registers are now assigned the control register type and no longer show up in the ar command.
* Fix xor if dest and src registers match by saving result in local var.
* Fix BE/LE issue for Load BRX instructions.
* Fix shifts: Use only lower 6bits of n.
* User Pure local variables for ROT macros.
* Fix rldimi instructions.
* n was not inverted.
* more than 6 bits of n could be used
* Add 32bit emulateme tests.
* Add 64bit emulateme tests.
* Determine lg(v) in inline function.
* Calculate CR bit in C not in the VM.
* Check if `~mask = 0` and skip mask calculation if yes.
* Check for `sh == 0` and skip rotations where possible.
* Remove `la` instruction. `la` is a mnemonic for `addi`.
* Remove SPR instructions which are not supported by QEMU or not traced yet. For most set/read SPR instructions QEMU segfaults.


In case of SPR 1 (xer), 8 (lr) and 9 (ctr) the assembler resolves them to their mnemonics (mtxer, mtlr etc.). This means the code here is never reached.
To test the get_xer code MFXER was added again. The rz-tracetests will fail for this instructions (due to missing ca32, ov32). But this case is covert in an issue.
2022-08-11 08:41:15 +08:00

136 lines
3.8 KiB
C

// SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_il/rz_il_opcodes.h>
#include <rz_il/rz_il_vm.h>
static RzILEvent *il_event_new_write_from_var(RzILVM *vm, RzILVar *var, RzILVal *new_val) {
rz_return_val_if_fail(vm && var && new_val, NULL);
RzILVal *old_val = rz_il_vm_get_var_value(vm, RZ_IL_VAR_KIND_GLOBAL, var->name);
if (!old_val) {
return NULL;
}
return rz_il_event_var_write_new(var->name, old_val, new_val);
}
static void rz_il_set(RzILVM *vm, const char *var_name, bool is_local, RZ_OWN RzILVal *val) {
if (is_local) {
rz_il_vm_set_local_var(vm, var_name, val);
} else {
RzILVar *var = rz_il_vm_get_var(vm, RZ_IL_VAR_KIND_GLOBAL, var_name);
RzILEvent *evt = il_event_new_write_from_var(vm, var, val);
rz_il_vm_event_add(vm, evt);
rz_il_vm_set_global_var(vm, var_name, val);
}
}
bool rz_il_handler_empty(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RZ_LOG_INFO("Encountered an empty instruction at %s\n", rz_bv_as_string(vm->pc))
return true;
}
bool rz_il_handler_nop(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
return true;
}
bool rz_il_handler_set(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RzILOpArgsSet *set_op = &op->op.set;
RzILVal *val = rz_il_evaluate_val(vm, set_op->x);
if (!val) {
return false;
}
rz_il_set(vm, set_op->v, set_op->is_local, val);
return true;
}
static void perform_jump(RzILVM *vm, RZ_OWN RzBitVector *dst) {
rz_il_vm_event_add(vm, rz_il_event_pc_write_new(vm->pc, dst));
rz_bv_free(vm->pc);
vm->pc = dst;
}
bool rz_il_handler_jmp(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RzBitVector *dst = rz_il_evaluate_bitv(vm, op->op.jmp.dst);
if (!dst) {
return false;
}
perform_jump(vm, dst);
return true;
}
bool rz_il_handler_goto(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RzILOpArgsGoto *op_goto = &op->op.goto_;
const char *lname = op_goto->lbl;
RzILEffectLabel *label = rz_il_vm_find_label_by_name(vm, lname);
if (!label) {
return false;
}
if (label->type == EFFECT_LABEL_SYSCALL || label->type == EFFECT_LABEL_HOOK) {
RzILVmHook internal_hook = (RzILVmHook)label->hook;
internal_hook(vm, op);
} else {
perform_jump(vm, rz_bv_dup(label->addr));
}
return true;
}
bool rz_il_handler_seq(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RzILOpArgsSeq *op_seq = &op->op.seq;
return rz_il_evaluate_effect(vm, op_seq->x) && rz_il_evaluate_effect(vm, op_seq->y);
}
bool rz_il_handler_blk(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RzILOpArgsBlk *op_blk = &op->op.blk;
if (op_blk->label) {
rz_il_vm_create_label(vm, op_blk->label, vm->pc); // create the label if `blk` is labelled
}
return rz_il_evaluate_effect(vm, op_blk->data_eff) && rz_il_evaluate_effect(vm, op_blk->ctrl_eff);
}
bool rz_il_handler_repeat(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, NULL);
RzILOpArgsRepeat *op_repeat = &op->op.repeat;
bool res = true;
RzILBool *condition;
while ((condition = rz_il_evaluate_bool(vm, op_repeat->condition))) {
if (!condition->b) {
break;
}
res = res && rz_il_evaluate_effect(vm, op_repeat->data_eff);
rz_il_bool_free(condition);
}
rz_il_bool_free(condition);
return res;
}
bool rz_il_handler_branch(RzILVM *vm, RzILOpEffect *op) {
rz_return_val_if_fail(vm && op, false);
RzILOpArgsBranch *op_branch = &op->op.branch;
RzILBool *condition = rz_il_evaluate_bool(vm, op_branch->condition);
if (!condition) {
return false;
}
bool ret;
if (condition->b) {
ret = rz_il_evaluate_effect(vm, op_branch->true_eff);
} else {
ret = rz_il_evaluate_effect(vm, op_branch->false_eff);
}
rz_il_bool_free(condition);
return ret;
}