bool instr_is_mov_constant(instr_t *instr, ptr_int_t *value) { int opc = instr_get_opcode(instr); if (opc == OP_eor) { /* We include OP_eor for symmetry w/ x86, but on ARM "mov reg, #0" is * just as compact and there's no reason to use an xor. */ if (opnd_same(instr_get_src(instr, 0), instr_get_dst(instr, 0)) && opnd_same(instr_get_src(instr, 0), instr_get_src(instr, 1)) && /* Must be the form with "sh2, i5_7" and no shift */ instr_num_srcs(instr) == 4 && opnd_get_immed_int(instr_get_src(instr, 2)) == DR_SHIFT_NONE && opnd_get_immed_int(instr_get_src(instr, 3)) == 0) { *value = 0; return true; } else return false; } else if (opc == OP_mvn || opc == OP_mvns) { opnd_t op = instr_get_src(instr, 0); if (opnd_is_immed_int(op)) { *value = -opnd_get_immed_int(op); return true; } else return false; } else if (opc == OP_mov || opc == OP_movs || opc == OP_movw) { opnd_t op = instr_get_src(instr, 0); if (opnd_is_immed_int(op)) { *value = opnd_get_immed_int(op); return true; } else return false; } return false; }
/* XXX: exporting this so drwrap can use it but I might prefer to have * this in drutil or the upcoming drsys */ DR_EXPORT int drmgr_decode_sysnum_from_wrapper(app_pc entry) { void *drcontext = dr_get_current_drcontext(); int num = -1; byte *pc = entry; uint opc; instr_t instr; instr_init(drcontext, &instr); do { instr_reset(drcontext, &instr); pc = decode(drcontext, pc, &instr); if (!instr_valid(&instr)) break; /* unknown system call sequence */ opc = instr_get_opcode(&instr); /* sanity check: wrapper should be short */ if (pc - entry > 20) break; /* unknown system call sequence */ if (opc == OP_mov_imm && opnd_is_reg(instr_get_dst(&instr, 0)) && opnd_get_reg(instr_get_dst(&instr, 0)) == DR_REG_EAX && opnd_is_immed_int(instr_get_src(&instr, 0))) { num = (int) opnd_get_immed_int(instr_get_src(&instr, 0)); break; /* success */ } /* stop at call to vsyscall (wow64) or at int itself */ } while (opc != OP_call_ind && opc != OP_int && opc != OP_sysenter && opc != OP_syscall); instr_free(drcontext, &instr); return num; }
static void process_ret(instr_t *instr, syscall_info_t *info) { assert(instr_is_return(instr)); if (opnd_is_immed_int(instr_get_src(instr, 0))) info->num_args = (int) opnd_get_immed_int(instr_get_src(instr, 0)); else info->num_args = 0; }
/* First tried something like this, but we hit too many issues in decode and encode */ bool compare_pages(void *drcontext, byte *start1, byte *start2) { byte *p1 = start1, *p2 = start2; int skipped_bytes = 0, identical_skipped_bytes = 0; while (p1 < start1 + PAGE_SIZE) { int instr_size = decode_sizeof(drcontext, p1, NULL _IF_X64(NULL)); if (p1 + instr_size > start1 + PAGE_SIZE) { /* We're overlapping the end of the page, skip these. */ int end_skip = start1 + PAGE_SIZE - p1; VVERBOSE_PRINT("Passing PAGE_END %d bytes", end_skip); skipped_bytes += end_skip; if (memcmp(p1, p2, end_skip) == 0) identical_skipped_bytes += end_skip; break; } if (decode_sizeof(drcontext, p2, NULL _IF_X64(NULL)) != instr_size) { VVERBOSE_PRINT("Instruction alignment mismatch\n"); return false; } /* assumption - instructions <= 4 bytes in size won't have relocations */ if (instr_size < 5) { if (memcmp(p1, p2, instr_size) != 0) { VVERBOSE_PRINT("Difference found in small instr\n"); return false; } p1 += size; p2 += size; } else { /* guess if there could be a relocation */ instr_t *instr1 = instr_create(drcontext); instr_t *instr2 = instr_create(drcontext); p1 = decode(drcontext, p1, instr1); p2 = decode(drcontext, p2, instr2); if (p1 - start1 != p2 - start2) { VVERBOSE_PRINT("Instruction alignment mismatch on full decode\n"); /* Fixme - free instr, don't expect this to happen */ return false; } if (instr_get_num_srcs(instr1) != instr_get_num_srcs(instr2) || instr_get_num_dsts(instr1) != instr_get_num_dsts(instr2)) { VVERBOSE_PRINT("Full decode operand mismatch"); return false; } for (i = instr_get_num_srcs(instr1); i > 0; i--) { opnd_t opnd = instr_get_src(instr1, i); if (opnd_is_immed_int(opnd) && opnd_get_immed_int(opnd) > 0x10000) { instr_set_src(instr1, i, opnd_create_immed_int(opnd_get_immed_int(opnd), opnd_get_size(opnd))); } } } } }
void modify_instr_for_relocations(void *drcontext, instr_t *inst, ptr_uint_t *immed, ptr_uint_t *disp) { int i; ptr_uint_t limmed = 0, ldisp = 0; for (i = instr_num_srcs(inst) - 1; i >= 0; i--) { opnd_t opnd = instr_get_src(inst, i); if (opnd_is_immed_int(opnd) && opnd_get_immed_int(opnd) > 0x10000) { if (limmed != 0) { ASSERT(false); } else { limmed = opnd_get_immed_int(opnd); } instr_set_src(inst, i, opnd_create_immed_int(0, opnd_get_size(opnd))); } if (opnd_is_base_disp(opnd) && opnd_get_disp(opnd) > 0x10000) { if (ldisp != 0 && ldisp != opnd_get_disp(opnd)) { ASSERT(false); } else { ldisp = opnd_get_disp(opnd); } instr_set_src(inst, i, opnd_create_base_disp(opnd_get_base(opnd), opnd_get_index(opnd), opnd_get_scale(opnd), 0, opnd_get_size(opnd))); } } for (i = instr_num_dsts(inst) - 1; i >= 0; i--) { opnd_t opnd = instr_get_dst(inst, i); ASSERT(!opnd_is_immed(opnd)); if (opnd_is_base_disp(opnd) && opnd_get_disp(opnd) > 0x10000) { if (ldisp != 0 && ldisp != opnd_get_disp(opnd)) { ASSERT(false); } else { ldisp = opnd_get_disp(opnd); } instr_set_dst(inst, i, opnd_create_base_disp(opnd_get_base(opnd), opnd_get_index(opnd), opnd_get_scale(opnd), 0, opnd_get_size(opnd))); } } if (limmed != 0) *immed = limmed; if (ldisp != 0) *disp = ldisp; }
static bool reg_update_is_limited(instr_t *instr, reg_id_t reg) { int opcode; int offset; opcode = instr_get_opcode(instr); if (opcode == OP_inc || opcode == OP_dec) return true; if (opcode == OP_and) /* for 0xffffffd0 & reg => reg */ return true; if ((opcode == OP_add || opcode == OP_sub || opcode == OP_adc || opcode == OP_sbb) && opnd_is_immed_int(instr_get_src(instr, 0))) { offset = opnd_get_immed_int(instr_get_src(instr, 0)); if (offset > PAGE_SIZE || offset < -PAGE_SIZE) return false; return true; } if (reg != DR_REG_XSP) return false; if (opcode >= OP_push && opcode <= OP_popa) { if (opcode == OP_pop && opnd_same(instr_get_dst(instr, 0), opnd_create_reg(DR_REG_XSP))) return false; return true; } if (opcode >= OP_call && opcode <= OP_call_far_ind) return true; if (opcode == OP_ret || opcode == OP_ret_far || opcode == OP_enter || opcode == OP_leave || opcode == OP_pushf || opcode == OP_popf) return true; return false; }
/* prints out the operands / populates the operands in the instrace mode */ static void output_populator_printer(void * drcontext, opnd_t opnd, instr_t * instr, uint64 addr, uint mem_type, operand_t * output){ int value; float float_value; uint width; int i; per_thread_t * data = drmgr_get_tls_field(drcontext,tls_index); if(opnd_is_reg(opnd)){ value = opnd_get_reg(opnd); if (value != DR_REG_NULL){ width = opnd_size_in_bytes(reg_get_size(value)); } else{ width = 0; } #ifdef READABLE_TRACE dr_fprintf(data->outfile,",%u,%u,%u",REG_TYPE, width, value); #else output->type = REG_TYPE; output->width = width; output->value = value; #endif } else if(opnd_is_immed(opnd)){ //DR_ASSERT(opnd_is_immed_float(opnd) == false); if(opnd_is_immed_float(opnd)){ width = opnd_size_in_bytes(opnd_get_size(opnd)); if (instr_get_opcode(instr) == OP_fld1){ dr_fprintf(data->outfile, ",%u,%u,1", IMM_FLOAT_TYPE, width); } else if (instr_get_opcode(instr) == OP_fldz){ dr_fprintf(data->outfile, ",%u,%u,0", IMM_FLOAT_TYPE, width); } else{ dr_messagebox("immediate float unknown\n"); dr_abort(); } //float_value = opnd_get_immed_float(opnd); #ifdef READABLE_TRACE //dr_fprintf(data->outfile,",%u,%u,%.4f",IMM_FLOAT_TYPE,width,float_value); #else output->type = IMM_FLOAT_TYPE; output->width = width; output->float_value = float_value; #endif } if(opnd_is_immed_int(opnd)){ width = opnd_size_in_bytes(opnd_get_size(opnd)); value = opnd_get_immed_int(opnd); #ifdef READABLE_TRACE dr_fprintf(data->outfile,",%u,%u,%d",IMM_INT_TYPE,width,value); #else output->type = IMM_INT_TYPE; output->width = width; output->value = value; #endif } } else if(opnd_is_memory_reference(opnd)){ width = drutil_opnd_mem_size_in_bytes(opnd,instr); #ifdef READABLE_TRACE dr_fprintf(data->outfile, ",%u,%u,%llu",mem_type,width,addr); #else output->type = mem_type; output->width = width; output->float_value = addr; #endif } }