static print_base_disp_for_lea(file_t file, opnd_t opnd){ /* [base + index * scale + disp] */ dr_fprintf(file, " base - %d %s\n", opnd_get_base(opnd), get_register_name(opnd_get_base(opnd))); dr_fprintf(file, " index - %d %s\n", opnd_get_index(opnd), get_register_name(opnd_get_index(opnd))); dr_fprintf(file, "reg - %d\n", opnd_is_reg(opnd_create_reg(opnd_get_index(opnd)))); dr_fprintf(file, " scale - %d\n", opnd_get_scale(opnd)); dr_fprintf(file, " disp - %d\n", opnd_get_disp(opnd)); }
static inline void collect_regs( unsigned long *regs, instr_t *instr, int (*num_ops)(instr_t *), opnd_t (*get_op)(instr_t *, uint) ) { int i; opnd_t opnd; // make sure these regs are always seen as "used" *regs |= (1 << DR_REG_NULL); for(i=0; i < num_ops(instr); i++) { opnd = get_op(instr, i); if(opnd_is_reg(opnd)) { collect_reg(regs, opnd_get_reg(opnd)); } else if(opnd_is_base_disp(opnd)) { collect_reg(regs, opnd_get_base(opnd)); collect_reg(regs, opnd_get_index(opnd)); } } collect_reg(regs, DR_REG_RSP); collect_reg(regs, DR_REG_RBP); collect_reg(regs, DR_REG_RAX); collect_reg(regs, DR_REG_RDX); }
bool ref_is_stack_mem(basic_block_t *bb, mem_ref_t *ref) { if (!opnd_is_base_disp(ref->opnd)) return false; if (opnd_get_base(ref->opnd) == DR_REG_XSP) return true; return false; }
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; }
bool instr_is_pop(instr_t *instr) { opnd_t memop; if (instr_num_srcs(instr) == 0) return false; memop = instr_get_src(instr, 0); if (!opnd_is_base_disp(memop)) return false; return opnd_get_base(memop) == DR_REG_SP; }
/* returns whether found a syscall * - found_eax: whether the caller has seen "mov imm => %eax" * - found_edx: whether the caller has seen "mov $0x7ffe0300 => %edx", * xref the comment below about "mov $0x7ffe0300 => %edx". */ static bool process_syscall_instr(void *dcontext, instr_t *instr, bool found_eax, bool found_edx) { /* ASSUMPTION: a mov imm of 0x7ffe0300 into edx followed by an * indirect call via edx is a system call on XP and later * On XP SP1 it's call *edx, while on XP SP2 it's call *(edx) * For wow it's a call through fs. * FIXME - core exports various is_*_syscall routines (such as * instr_is_wow64_syscall()) which we could use here instead of * duplicating if they were more flexible about when they could * be called (instr_is_wow64_syscall() for ex. asserts if not * in a wow process). */ if (/* int 2e or x64 or win8 sysenter */ (instr_is_syscall(instr) && found_eax && (expect_int2e || expect_x64 || expect_sysenter)) || /* sysenter case */ (expect_sysenter && found_edx && found_eax && instr_is_call_indirect(instr) && /* XP SP{0,1}, 2003 SP0: call *edx */ ((opnd_is_reg(instr_get_target(instr)) && opnd_get_reg(instr_get_target(instr)) == REG_EDX) || /* XP SP2, 2003 SP1: call *(edx) */ (opnd_is_base_disp(instr_get_target(instr)) && opnd_get_base(instr_get_target(instr)) == REG_EDX && opnd_get_index(instr_get_target(instr)) == REG_NULL && opnd_get_disp(instr_get_target(instr)) == 0))) || /* wow case * we don't require found_ecx b/c win8 does not use ecx */ (expect_wow && found_eax && instr_is_call_indirect(instr) && ((opnd_is_far_base_disp(instr_get_target(instr)) && opnd_get_base(instr_get_target(instr)) == REG_NULL && opnd_get_index(instr_get_target(instr)) == REG_NULL && opnd_get_segment(instr_get_target(instr)) == SEG_FS) || /* win10 has imm in edx and a near call */ found_edx))) return true; return false; }
void check_opnd(opnd_t opnd, void *pc, int read, void *drcontext, dr_mcontext_t *mctx, void *prev_pc) { if (opnd_is_memory_reference(opnd) && opnd_is_base_disp(opnd)) add_hit(pc, opnd_size_in_bytes(opnd_get_size(opnd)), opnd_get_disp(opnd) + (void *)reg_get_value(opnd_get_base(opnd), mctx), read, drcontext, prev_pc); else if (opnd_is_memory_reference(opnd) && opnd_get_addr(opnd)) add_hit(pc, opnd_size_in_bytes(opnd_get_size(opnd)), opnd_get_addr(opnd), read, drcontext, prev_pc); // for now no other kind of memory reference was noticed to access heap data else if (opnd_is_memory_reference(opnd)) dr_printf("need to implem other memory ref\n"); }
static bool opnd_uses_memory_we_track(opnd_t opnd) { /* PR 553724: by default assume esp always points to stack and that user * doesn't care about staleness of any stacks allocated in the heap. * * FIXME PR 553724: track ebp and ignore refs when ebp is clearly * used as a frame ptr */ return (opnd_is_memory_reference(opnd) && (!options.stale_ignore_sp || !opnd_is_base_disp(opnd) || reg_to_pointer_sized(opnd_get_base(opnd)) != REG_XSP || opnd_get_index(opnd) != REG_NULL || opnd_is_far_memory_reference(opnd))); }
/* prints the trace and empties the instruction buffer */ static void ins_trace(void *drcontext) { per_thread_t *data; int num_refs; instr_trace_t *instr_trace; instr_t * instr; int i; int j; #ifdef READABLE_TRACE char disassembly[SHORT_STRING_LENGTH]; #else output_t * output; #endif data = drmgr_get_tls_field(drcontext, tls_index); instr_trace = (instr_trace_t *)data->buf_base; num_refs = (int)((instr_trace_t *)data->buf_ptr - instr_trace); uint mem_type; uint64 mem_addr; opnd_t opnd; #ifdef READABLE_TRACE //TODO for (i = 0; i < num_refs; i++) { instr = instr_trace->static_info_instr; instr_disassemble_to_buffer(drcontext,instr,disassembly,SHORT_STRING_LENGTH); dr_fprintf(data->outfile,"%u",instr_get_opcode(instr)); dr_fprintf(data->outfile,",%u",calculate_operands(instr,DST_TYPE)); for(j=0; j<instr_num_dsts(instr); j++){ get_address(instr_trace, j, DST_TYPE, &mem_type, &mem_addr); output_populator_printer(drcontext,instr_get_dst(instr,j),instr,mem_addr,mem_type,NULL); } dr_fprintf(data->outfile,",%u",calculate_operands(instr,SRC_TYPE)); for(j=0; j<instr_num_srcs(instr); j++){ get_address(instr_trace, j, SRC_TYPE, &mem_type, &mem_addr); opnd = instr_get_src(instr, j); if (instr_get_opcode(instr) == OP_lea && opnd_is_base_disp(opnd)){ /* four operands here for [base + index * scale + disp] */ output_populator_printer(drcontext, opnd_create_reg(opnd_get_base(opnd)), instr, mem_addr, mem_type, NULL); output_populator_printer(drcontext, opnd_create_reg(opnd_get_index(opnd)), instr, mem_addr, mem_type, NULL); output_populator_printer(drcontext, opnd_create_immed_int(opnd_get_scale(opnd),OPSZ_PTR), instr, mem_addr, mem_type, NULL); output_populator_printer(drcontext, opnd_create_immed_int(opnd_get_disp(opnd), OPSZ_PTR), instr, mem_addr, mem_type, NULL); } else{ output_populator_printer(drcontext, opnd, instr, mem_addr, mem_type, NULL); } } dr_fprintf(data->outfile,",%u,%u\n",instr_trace->eflags,instr_trace->pc); ++instr_trace; } #else /* we need to fill up the output array here */ for(i = 0; i< num_refs; i++){ instr = instr_trace->static_info_instr; output = &data->output_array[i]; //opcode output->opcode = instr_get_opcode(instr); output->num_dsts = 0; output->num_srcs = 0; for(j=0; j<instr_num_dsts(instr); j++){ output_populator_printer(drcontext,instr_get_dst(instr,j),instr,get_address(instr_trace,j,DST_TYPE),&output->dsts[output->num_dsts]); output->num_dsts++; } for(j=0; j<instr_num_srcs(instr); j++){ output_populator_printer(drcontext,instr_get_src(instr,j),instr,get_address(instr_trace,j,SRC_TYPE),&output->srcs[output->num_srcs]); output->num_srcs++; } output->eflags = instr_trace->eflags; ++instr_trace; } dr_write_file(data->outfile,data->output_array,num_refs * sizeof(output_t)); #endif memset(data->buf_base, 0, INSTR_BUF_SIZE); data->num_refs += num_refs; data->buf_ptr = data->buf_base; }
static void test_instr_opnds(void *dc) { /* Verbose disasm looks like this: * 32-bit: * 0x080f1ae0 ff 25 e7 1a 0f 08 jmp 0x080f1ae7 * 0x080f1ae6 b8 ef be ad de mov $0xdeadbeef -> %eax * 0x080f1ae0 a0 e6 1a 0f 08 mov 0x080f1ae6 -> %al * 0x080f1ae5 b8 ef be ad de mov $0xdeadbeef -> %eax * 64-bit: * 0x00000000006b8de0 ff 25 02 00 00 00 jmp <rel> 0x00000000006b8de8 * 0x00000000006b8de6 48 b8 ef be ad de 00 mov $0x00000000deadbeef -> %rax * 00 00 00 * 0x00000000006b8de0 8a 05 02 00 00 00 mov <rel> 0x00000000006b8de8 -> %al * 0x00000000006b8de6 48 b8 ef be ad de 00 mov $0x00000000deadbeef -> %rax * 00 00 00 */ instrlist_t *ilist; instr_t *tgt, *instr; byte *pc; short disp; ilist = instrlist_create(dc); /* test mem instr as ind jmp target */ tgt = INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_immed_int(0xdeadbeef, OPSZ_PTR)); /* skip rex+opcode */ disp = IF_X64_ELSE(2,1); instrlist_append(ilist, INSTR_CREATE_jmp_ind (dc, opnd_create_mem_instr(tgt, disp, OPSZ_PTR))); instrlist_append(ilist, tgt); pc = instrlist_encode(dc, ilist, buf, true/*instr targets*/); ASSERT(pc != NULL); instrlist_clear(dc, ilist); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif pc = buf; instr = instr_create(dc); pc = decode(dc, pc, instr); ASSERT(pc != NULL); ASSERT(instr_get_opcode(instr) == OP_jmp_ind); #ifdef X64 ASSERT(opnd_is_rel_addr(instr_get_src(instr, 0))); ASSERT(opnd_get_addr(instr_get_src(instr, 0)) == pc + disp); #else ASSERT(opnd_is_base_disp(instr_get_src(instr, 0))); ASSERT(opnd_get_base(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_index(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_disp(instr_get_src(instr, 0)) == (ptr_int_t)pc + disp); #endif /* test mem instr as TYPE_O */ tgt = INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_immed_int(0xdeadbeef, OPSZ_PTR)); /* skip rex+opcode */ disp = IF_X64_ELSE(2,1); instrlist_append(ilist, INSTR_CREATE_mov_ld (dc, opnd_create_reg(DR_REG_AL), opnd_create_mem_instr(tgt, disp, OPSZ_1))); instrlist_append(ilist, tgt); pc = instrlist_encode(dc, ilist, buf, true/*instr targets*/); ASSERT(pc != NULL); instrlist_clear(dc, ilist); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif pc = buf; instr_reset(dc, instr); pc = decode(dc, pc, instr); ASSERT(pc != NULL); ASSERT(instr_get_opcode(instr) == OP_mov_ld); #ifdef X64 ASSERT(opnd_is_rel_addr(instr_get_src(instr, 0))); ASSERT(opnd_get_addr(instr_get_src(instr, 0)) == pc + disp); #else ASSERT(opnd_is_base_disp(instr_get_src(instr, 0))); ASSERT(opnd_get_base(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_index(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_disp(instr_get_src(instr, 0)) == (ptr_int_t)pc + disp); #endif instr_free(dc, instr); instrlist_destroy(dc, ilist); }
static instr_t * analyze_client_code(void *drcontext, instrlist_t *ilist, instr_t *where, ref_info_t *ref_info) { instr_t *next, *lea, *and, *cmp, *jcc, *sub; opnd_t ref, opnd; ref_cache_t *cache; reg_id_t reg; int pos, i; next = instr_get_next(where); if (next == NULL) return NULL; if (instr_get_opcode(where) != OP_lea) return next; /* lea [ref] => r1 */ ref = instr_get_src(where, 0); if (!opnd_is_base_disp(ref) || opnd_get_index(ref) != DR_REG_NULL) return next; lea = where; and = next; cmp = instr_get_next(and); jcc = instr_get_next(cmp); if (instr_get_app_pc(and) == NULL && instr_get_opcode(and) == OP_and && instr_get_app_pc(cmp) == NULL && instr_get_opcode(cmp) == OP_cmp && instr_get_app_pc(jcc) == NULL && instr_get_opcode(jcc) == OP_jz) { /* find pattern of * lea [ref] => reg * and 0xffffffff00000000 reg * cmp cache->tag reg * jz */ opnd = instr_get_src(cmp, 1); cache = opnd_get_addr(opnd) - offsetof(ref_cache_t, tag); for (i = 0; i < 10; ) { lea = instr_get_next(lea); if (!instr_is_label(lea)) i++; } DR_ASSERT(instr_get_opcode(lea) == OP_lea); } else if (instr_get_app_pc(next) == NULL && instr_get_opcode(next) == OP_sub) { opnd = instr_get_src(next, 0); cache = opnd_get_addr(opnd) - offsetof(ref_cache_t, offset); } else { return next; } reg = opnd_get_base(ref); UMBRA_REG_TO_POS(reg, pos); if (ref_info[pos].cache == NULL) { ref_info[pos].cache = cache; } else { sub = instr_get_next(lea); DR_ASSERT(instr_get_opcode(sub) == OP_sub); while (lea != where) { next = instr_get_next(where); instrlist_remove(ilist, where); instr_destroy(drcontext, where); where = next; } opnd = OPND_CREATE_ABSMEM((void *)(reg_t)ref_info[pos].cache + offsetof(ref_cache_t, offset), OPSZ_PTR); instr_set_src(sub, 0, opnd); if (proc_info.client.app_unit_bits > 0 && proc_info.client.shd_unit_bits != 0) next = instr_get_next(sub); /* reg & mask => reg */ if (proc_info.client.orig_addr) { next = instr_get_next(next); /* mov reg => r2 */ next = instr_get_next(next); /* r2 & bit_mask => r2 */ } } next = instr_get_next(lea); return instr_get_next(next); }
void watchpoint_indirect_call_event(dcontext_t *drcontext, instrlist_t *ilist, instr_t *instr, instr_t *next_instr, bool mangle_calls, uint flags) { opnd_t instr_opnd; reg_id_t base_reg; unsigned long used_registers = 0; app_pc pc; struct memory_operand_modifier ops = {0}; instr_t *begin_instrumenting = INSTR_CREATE_label(drcontext); instr_t *done_instrumenting = INSTR_CREATE_label(drcontext); instr_t *nop = INSTR_CREATE_nop(drcontext); instr_t *emulated; memset(&ops, 0, sizeof(struct memory_operand_modifier)); if(instr_reads_memory(instr)) { instr_opnd = instr_get_src(instr, 0); if (opnd_is_rel_addr(instr_opnd) || opnd_is_abs_addr(instr_opnd)) { }else if (opnd_is_base_disp(instr_opnd)) { for_each_src_operand(instr, &ops, (opnd_callback_t *) memory_src_operand_finder); // base_reg = opnd_get_reg(instr_opnd); switch(ops.found_operand.value.base_disp.base_reg) { case DR_REG_RSP: case DR_REG_ESP: case DR_REG_SP: case DR_REG_RBP: case DR_REG_EBP: case DR_REG_BP: return; default: break; } collect_regs(&used_registers, instr, instr_num_srcs, instr_get_src ); collect_regs(&used_registers, instr, instr_num_dsts, instr_get_dst ); reg_id_t reg_watched_addr = get_next_free_reg(&used_registers); opnd_t opnd_watched_addr = opnd_create_reg(reg_watched_addr); reg_id_t reg_unwatched_addr = get_next_free_reg(&used_registers); opnd_t opnd_unwatched_addr = opnd_create_reg(reg_unwatched_addr); PRE(ilist, instr, begin_instrumenting); PRE(ilist, instr, INSTR_CREATE_push(drcontext, opnd_watched_addr)); PRE(ilist, instr, INSTR_CREATE_push(drcontext, opnd_unwatched_addr)); PRE(ilist, instr, INSTR_CREATE_pushf(drcontext)); PRE(ilist, instr, INSTR_CREATE_lea(drcontext, opnd_watched_addr, opnd_create_base_disp(opnd_get_base(ops.found_operand), opnd_get_index(ops.found_operand), opnd_get_scale(ops.found_operand), opnd_get_disp(ops.found_operand), OPSZ_lea))); PRE(ilist, instr, INSTR_CREATE_mov_imm(drcontext, opnd_unwatched_addr, OPND_CREATE_INT64(WATCHPOINT_INDEX_MASK))); PRE(ilist, instr, INSTR_CREATE_or(drcontext, opnd_unwatched_addr, opnd_watched_addr)); emulated = instr_clone(drcontext, instr); emulated->translation = 0; ops.replacement_operand = opnd_create_base_disp( reg_unwatched_addr, DR_REG_NULL,1, 0 , ops.found_operand.size); for_each_operand(emulated, &ops, (opnd_callback_t *) memory_operand_replacer); PRE(ilist, instr, INSTR_CREATE_popf(drcontext)); PRE(ilist, instr, emulated); PRE(ilist, instr, INSTR_CREATE_pop(drcontext, opnd_unwatched_addr)); PRE(ilist, instr, INSTR_CREATE_pop(drcontext, opnd_watched_addr)); PRE(ilist, instr, INSTR_CREATE_jmp_short(drcontext, opnd_create_instr(done_instrumenting))); pc = instr->translation; instr->translation = 0; // hack! instr_being_modified(instr, false); instr_set_ok_to_mangle(instr, false); if(NULL != pc){ nop->translation = pc + instr->length; } POST(ilist, instr, nop); POST(ilist, instr, done_instrumenting); } } }
/* returns false on failure */ static bool decode_syscall_num(void *dcontext, byte *entry, syscall_info_t *info) { /* FIXME: would like to fail gracefully rather than have a DR assertion * on non-code! => use DEBUG=0 INTERNAL=1 DR build! */ bool found_syscall = false, found_eax = false, found_edx = false, found_ecx = false; bool found_ret = false; byte *pc; int num_instr = 0; instr_t *instr; if (entry == NULL) return false; info->num_args = -1; /* if find sysnum but not args */ info->sysnum = -1; info->fixup_index = -1; instr = instr_create(dcontext); pc = entry; /* FIXME - we don't support decoding 64bit instructions in 32bit mode, but I want * this to work on 32bit machines. Hack fix based on the wrapper pattern, we skip * the first instruction (mov r10, rcx) here, the rest should decode ok. * Xref PR 236203. */ if (expect_x64 && *pc == 0x4c && *(pc+1) == 0x8b && *(pc+2) == 0xd1) pc += 3; while (true) { instr_reset(dcontext, instr); pc = decode(dcontext, pc, instr); if (verbose) dr_print_instr(dcontext, STDOUT, instr, ""); if (pc == NULL || !instr_valid(instr)) break; /* ASSUMPTION: a mov imm of 0x7ffe0300 into edx followed by an * indirect call via edx is a system call on XP and later * On XP SP1 it's call *edx, while on XP SP2 it's call *(edx) * For wow it's a call through fs. * FIXME - core exports various is_*_syscall routines (such as * instr_is_wow64_syscall()) which we could use here instead of * duplicating if they were more flexible about when they could * be called (instr_is_wow64_syscall() for ex. asserts if not * in a wow process). */ if (/* int 2e or x64 or win8 sysenter */ (instr_is_syscall(instr) && found_eax && (expect_int2e || expect_x64 || expect_sysenter)) || /* sysenter case */ (expect_sysenter && found_edx && found_eax && instr_is_call_indirect(instr) && /* XP SP{0,1}, 2003 SP0: call *edx */ ((opnd_is_reg(instr_get_target(instr)) && opnd_get_reg(instr_get_target(instr)) == REG_EDX) || /* XP SP2, 2003 SP1: call *(edx) */ (opnd_is_base_disp(instr_get_target(instr)) && opnd_get_base(instr_get_target(instr)) == REG_EDX && opnd_get_index(instr_get_target(instr)) == REG_NULL && opnd_get_disp(instr_get_target(instr)) == 0))) || /* wow case * we don't require found_ecx b/c win8 does not use ecx */ (expect_wow && found_eax && instr_is_call_indirect(instr) && opnd_is_far_base_disp(instr_get_target(instr)) && opnd_get_base(instr_get_target(instr)) == REG_NULL && opnd_get_index(instr_get_target(instr)) == REG_NULL && opnd_get_segment(instr_get_target(instr)) == SEG_FS)) { found_syscall = true; } else if (instr_is_return(instr)) { if (!found_ret) { process_ret(instr, info); found_ret = true; } break; } else if (instr_is_cti(instr)) { if (instr_get_opcode(instr) == OP_call) { /* handle win8 x86 which has sysenter callee adjacent-"inlined" * ntdll!NtYieldExecution: * 77d7422c b801000000 mov eax,1 * 77d74231 e801000000 call ntdll!NtYieldExecution+0xb (77d74237) * 77d74236 c3 ret * 77d74237 8bd4 mov edx,esp * 77d74239 0f34 sysenter * 77d7423b c3 ret */ byte *tgt; assert(opnd_is_pc(instr_get_target(instr))); tgt = opnd_get_pc(instr_get_target(instr)); /* we expect only ret or ret imm, and possibly some nops (in gdi32). * XXX: what about jmp to shared ret (seen in the past on some syscalls)? */ if (tgt > pc && tgt <= pc + 16) { bool ok = false; do { if (pc == tgt) { ok = true; break; } instr_reset(dcontext, instr); pc = decode(dcontext, pc, instr); if (verbose) dr_print_instr(dcontext, STDOUT, instr, ""); if (instr_is_return(instr)) { process_ret(instr, info); found_ret = true; } else if (!instr_is_nop(instr)) break; num_instr++; } while (num_instr <= MAX_INSTRS_BEFORE_SYSCALL); if (ok) continue; } } /* assume not a syscall wrapper if we hit a cti */ break; /* give up gracefully */ } else if ((!found_eax || !found_edx || !found_ecx) && instr_get_opcode(instr) == OP_mov_imm && opnd_is_reg(instr_get_dst(instr, 0))) { if (!found_eax && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX) { info->sysnum = (int) opnd_get_immed_int(instr_get_src(instr, 0)); found_eax = true; } else if (!found_edx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EDX) { int imm = (int) opnd_get_immed_int(instr_get_src(instr, 0)); if (imm == 0x7ffe0300) found_edx = true; } else if (!found_ecx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) { found_ecx = true; info->fixup_index = (int) opnd_get_immed_int(instr_get_src(instr, 0)); } } else if (instr_get_opcode(instr) == OP_xor && opnd_is_reg(instr_get_src(instr, 0)) && opnd_get_reg(instr_get_src(instr, 0)) == REG_ECX && opnd_is_reg(instr_get_dst(instr, 0)) && opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) { /* xor to 0 */ found_ecx = true; info->fixup_index = 0; } num_instr++; if (num_instr > MAX_INSTRS_BEFORE_SYSCALL) /* wrappers should be short! */ break; /* avoid weird cases like NPXEMULATORTABLE */ } instr_destroy(dcontext, instr); return found_syscall; }