// vim: sw=2 et /* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: context.cpp 1502 2007-04-15 07:54:20Z itsme $ */ #include "regeval.hpp" #include "context.hpp" //------------- eval_constant_t::eval_constant_t(ea_t ea) : m_ea(ea) { } evaltree_t* eval_constant_t::MakeNode(ea_t ea) { return new eval_constant_t(ea); } ea_t eval_constant_t::GetConstant() { return m_ea; } std::string eval_constant_t::Evaluate(evalcontext_t* /* context */) { deb(8, "eval_constant_t::Evaluate\n"); std::string value; value.resize(64); value.resize(qsnprintf(&value[0], value.size(), "0x%08lx", m_ea)); return value; } //------------- eval_register_t::eval_register_t(int reg) : m_reg(reg) { } evaltree_t* eval_register_t::MakeNode(int reg) { return new eval_register_t(reg); } int eval_register_t::GetRegister() { return m_reg; } std::string eval_register_t::Evaluate(evalcontext_t* /* context */) { deb(8, "eval_register_t::Evaluate\n"); std::string value; value.resize(10); value.resize(qsnprintf(&value[0], value.size(), "R%d", m_reg)); return value; } //------------- eval_binary_operator_t::eval_binary_operator_t(ushort itype, evaltree_t* left, evaltree_t* right) : m_itype(itype), m_left(left), m_right(right) { } evaltree_t* eval_binary_operator_t::MakeNode(ushort itype, evaltree_t* left, evaltree_t* right) { return new eval_binary_operator_t(itype, left, right); } ushort eval_binary_operator_t::GetOperation() { return m_itype; } evaltree_t*eval_binary_operator_t::GetLeft() { return m_left; } evaltree_t*eval_binary_operator_t::GetRight() { return m_right; } std::string eval_binary_operator_t::GetOperatorString() { switch(m_itype) { case ARM_and: return "&"; case ARM_bic: return "&~"; case ARM_eor: return "^"; case ARM_orr: return "|"; case ARM_adc: case ARM_add: return "+"; case ARM_rsc: case ARM_rsb: case ARM_sbc: case ARM_sub: return "-"; case ARM_mul: return "*"; // ARM_cmn, ARM_cmp, ARM_teq, ARM_tst default: std::string str; str.resize(16); str.resize(qsnprintf(&str[0], str.size(), "binop_%d", m_itype)); return str; } } std::string eval_binary_operator_t::Evaluate(evalcontext_t* context) { deb(8, "eval_binary_operator_t::Evaluate\n"); std::string expr; if (m_itype==ARM_rsb || m_itype==ARM_rsc) expr = m_right->Evaluate(context)+GetOperatorString()+m_left->Evaluate(context); else expr= m_left->Evaluate(context)+GetOperatorString()+m_right->Evaluate(context); if (m_itype==ARM_rsc || m_itype==ARM_sbc) expr += "-C"; else if (m_itype==ARM_adc) expr += "+C"; return "("+expr+")"; } //------------- eval_unary_operator_t::eval_unary_operator_t(ushort itype, evaltree_t* arg) : m_itype(itype), m_arg(arg) { } evaltree_t* eval_unary_operator_t::MakeNode(ushort itype, evaltree_t* arg) { return new eval_unary_operator_t(itype, arg); } ushort eval_unary_operator_t::GetOperation() { return m_itype; } evaltree_t* eval_unary_operator_t::GetArg() { return m_arg; } std::string eval_unary_operator_t::GetOperatorString() { switch(m_itype) { case ARM_ldr: return "ldr"; default: std::string str; str.resize(16); str.resize(qsnprintf(&str[0], str.size(), "unop_%d", m_itype)); return str; } } std::string eval_unary_operator_t::Evaluate(evalcontext_t* context) { deb(8, "eval_unary_operator_t::Evaluate\n"); return GetOperatorString()+"("+m_arg->Evaluate(context)+")"; } //------------- //------------- evalcontext_t::evalcontext_t(ea_t ea) { m_ea= ea; m_registers.resize(16); m_registers[PC]= eval_constant_t::MakeNode(ea+(getSR(ea, T)?4:8)); m_pfn= get_func(ea); TraceBack(); } void deletevector(evaltree_vector& v) { for (size_t i=0 ; iEvaluate(this); } void evalcontext_t::Assign(evaltree_t *dst, evaltree_t *src) { if (eval_register_t *reg= dynamic_cast(dst)) { m_registers[reg->GetRegister()]= src; } else if (eval_unary_operator_t *op= dynamic_cast(dst)) { if (op->GetOperation()!=ARM_ldr) { deb(8, "don't know how to handle dst\n"); } else if (eval_binary_operator_t *op2= dynamic_cast(op->GetArg())) { if (eval_register_t *reg= dynamic_cast(op2->GetLeft())) { if (reg->GetRegister()==SP) { if (eval_constant_t *ofs= dynamic_cast(op2->GetRight())) { int n; if (op->GetOperation()==ARM_add) n= ofs->GetConstant(); else if (op->GetOperation()==ARM_sub) n= -ofs->GetConstant(); else { deb(8, "can't handle unknown operation with SP\n"); return; } if (n>0) { deb(8, "can't handle [sp+ofs] variables\n"); return; } else if (n&3) { deb(8, "can't handle non aligned variables\n"); return; } else { m_stackargs[n/4]= src; } } } else { deb(8, "don't know how to assign memory yet\n"); } } } else if (eval_register_t *reg= dynamic_cast(dst)) { if (reg->GetRegister()==SP) { m_stackargs[0]= src; } else { deb(8, "don't know how to assign memory yet\n"); } } } else { deb(8, "don't know how to assign\n"); } } evaltree_t *evalcontext_t::GetRegister(int reg) { if (m_registers[reg]==NULL) m_registers[reg]=eval_register_t::MakeNode(reg); return m_registers[reg]; } evaltree_t *evalcontext_t::GetOperandExpression(const op_t& op) { // todo: change o_displ into ARM_ldr(ARM_add(reg, const)) switch(op.type) { case o_reg: if ( cmd.auxpref & aux_wbackldm ) { deb(8, "! not yet supported\n"); } return GetRegister(op.reg); case o_imm: return eval_constant_t::MakeNode(op.value); case o_mem: { flags_t f2 = getFlags(cmd.ea); if ( (isDwrd(f2) && op.dtyp==dt_dword ) || (isWord(f2) && op.dtyp==dt_word) ) { return eval_constant_t::MakeNode(isDwrd(f2) ? get_long(op.addr) : get_word(op.addr)); } return eval_unary_operator_t::MakeNode(ARM_ldr, eval_constant_t::MakeNode(op.addr)); } case o_shreg: if ((cmd.auxpref & aux_regsh)==0 && op.shtype==LSL && op.shcnt==0) return GetRegister(op.reg); deb(8, "shreg Shifts not yet supported\n"); break; case o_phrase: // [Rreg + shifted(Rsecreg)] if ((cmd.auxpref & aux_postidx)!=0 || (cmd.auxpref & aux_wback)!=0 ) deb(8, "post/wback indexing ignored\n"); if ((cmd.auxpref & aux_regsh)==0 && op.shtype==LSL && op.shcnt==0) return eval_unary_operator_t::MakeNode(ARM_ldr, eval_binary_operator_t::MakeNode( ( cmd.auxpref & aux_negoff )!=0 ? ARM_sub : ARM_add, GetRegister(op.reg), GetRegister(op.secreg))); deb(8, "phrase Shifts not yet supported\n"); break; case o_displ: // [Rreg, #imm] if ((cmd.auxpref & aux_postidx)!=0 || (cmd.auxpref & aux_wback)!=0 ) deb(8, "post/wback indexing ignored\n"); return eval_unary_operator_t::MakeNode(ARM_ldr, eval_binary_operator_t::MakeNode( ARM_add, GetRegister(op.reg), eval_constant_t::MakeNode(op.addr))); default: deb(8, "don't know how to handle operand yet\n"); return NULL; } deb(8, "could not convert opnd to expression\n"); return NULL; } void evalcontext_t::TraceBack() { cmd.ea= m_ea; deb(8, "tracing back from %08lx\n", m_ea); // find start of tracable instruction sequence. while (true) { flags_t F = getFlags(cmd.ea); if ( hasRef(F) || !isFlow(F) || decode_prev_insn(cmd.ea) == BADADDR ) break; } deb(8, "traced back to %08lx\n", cmd.ea); while (cmd.ea < m_ea) { switch(cmd.itype) { case ARM_ldr: case ARM_mov: case ARM_movl: Assign(GetOperandExpression(cmd.Op1), GetOperandExpression(cmd.Op2)); break; case ARM_str: Assign(GetOperandExpression(cmd.Op2), GetOperandExpression(cmd.Op1)); break; case ARM_asr: case ARM_lsl: case ARM_lsr: case ARM_and: case ARM_eor: case ARM_sub: case ARM_rsb: case ARM_add: case ARM_adc: case ARM_sbc: case ARM_rsc: case ARM_orr: case ARM_bic: case ARM_mul: case ARM_mla: case ARM_smull: case ARM_smlal: case ARM_umull: case ARM_umlal: Assign(GetOperandExpression(cmd.Op1), eval_binary_operator_t::MakeNode(cmd.itype, GetOperandExpression(cmd.Op2), GetOperandExpression(cmd.Op3))); break; case ARM_stm: case ARM_ldm: break; case ARM_mvn: case ARM_ror: case ARM_neg: Assign(GetOperandExpression(cmd.Op1), eval_unary_operator_t::MakeNode(cmd.itype, GetOperandExpression(cmd.Op2))); break; case ARM_tst: case ARM_teq: case ARM_cmp: case ARM_cmn: break; case ARM_swp: case ARM_pop: case ARM_push: case ARM_adr: case ARM_clz: case ARM_mrs: case ARM_msr: break; case ARM_nop: break; case ARM_swi: case ARM_bx : case ARM_bkpt: case ARM_blx1: case ARM_blx2: case ARM_ret: case ARM_b: case ARM_bl: default: deb(8, "ERROR: can't handle break in execution flow yet\n"); break; } ua_ana0(cmd.ea+cmd.size); } deb(8, "done getting context\n"); }