/* return the branch type of the (branch) inst */ uint instr_branch_type(instr_t *cti_instr) { instr_get_opcode(cti_instr); /* ensure opcode is valid */ if (instr_get_opcode(cti_instr) == OP_blx) { /* To handle the mode switch we go through the ibl. * FIXME i#1551: once we have far linking through stubs we should * remove this and have a faster link through the stub. */ return LINK_INDIRECT|LINK_CALL; } /* We treate a predicated call as a cbr, not a call */ else if (instr_is_cbr_arch(cti_instr) || instr_is_ubr_arch(cti_instr)) return LINK_DIRECT|LINK_JMP; else if (instr_is_call_direct(cti_instr)) return LINK_DIRECT|LINK_CALL; else if (instr_is_call_indirect(cti_instr)) return LINK_INDIRECT|LINK_CALL; else if (instr_is_return(cti_instr)) return LINK_INDIRECT|LINK_RETURN; else if (instr_is_mbr_arch(cti_instr)) return LINK_INDIRECT|LINK_JMP; else CLIENT_ASSERT(false, "instr_branch_type: unknown opcode"); return LINK_INDIRECT; }
DR_EXPORT bool drx_aflags_are_dead(instr_t *where) { instr_t *instr; uint flags; for (instr = where; instr != NULL; instr = instr_get_next(instr)) { /* we treat syscall/interrupt as aflags read */ if (instr_is_syscall(instr) || instr_is_interrupt(instr)) return false; flags = instr_get_arith_flags(instr, DR_QUERY_DEFAULT); if (TESTANY(EFLAGS_READ_ARITH, flags)) return false; if (TESTALL(EFLAGS_WRITE_ARITH, flags)) return true; if (instr_is_cti(instr)) { if (instr_is_app(instr) && (instr_is_ubr(instr) || instr_is_call_direct(instr))) { instr_t *next = instr_get_next(instr); opnd_t tgt = instr_get_target(instr); /* continue on elision */ if (next != NULL && instr_is_app(next) && opnd_is_pc(tgt) && opnd_get_pc(tgt) == instr_get_app_pc(next)) continue; } /* unknown target, assume aflags is live */ return false; } } return false; }
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr, *next_instr; #ifdef VERBOSE dr_printf("in dr_basic_block(tag="PFX")\n", tag); # if VERBOSE_VERBOSE instrlist_disassemble(drcontext, tag, bb, STDOUT); # endif #endif for (instr = instrlist_first_app(bb); instr != NULL; instr = next_instr) { next_instr = instr_get_next_app(instr); if (!instr_opcode_valid(instr)) continue; /* instrument calls and returns -- ignore far calls/rets */ if (instr_is_call_direct(instr)) { dr_insert_call_instrumentation(drcontext, bb, instr, (app_pc)at_call); } else if (instr_is_call_indirect(instr)) { dr_insert_mbr_instrumentation(drcontext, bb, instr, (app_pc)at_call_ind, SPILL_SLOT_1); } else if (instr_is_return(instr)) { dr_insert_mbr_instrumentation(drcontext, bb, instr, (app_pc)at_return, SPILL_SLOT_1); } } return DR_EMIT_DEFAULT; }
static void look_for_usercall(void *dcontext, byte *entry, const char *sym, LOADED_IMAGE *img, const char *modpath) { bool found_push_imm = false; int imm = 0; app_pc pc, pre_pc; instr_t *instr; if (entry == NULL) return; instr = instr_create(dcontext); pc = entry; while (true) { instr_reset(dcontext, instr); pre_pc = pc; pc = decode(dcontext, pc, instr); if (verbose) { instr_set_translation(instr, pre_pc); dr_print_instr(dcontext, STDOUT, instr, ""); } if (pc == NULL || !instr_valid(instr)) break; if (instr_get_opcode(instr) == OP_push_imm) { found_push_imm = true; imm = (int) opnd_get_immed_int(instr_get_src(instr, 0)); } else if (instr_is_call_direct(instr) && found_push_imm) { app_pc tgt = opnd_get_pc(instr_get_target(instr)); bool found = false; int i; for (i = 0; i < NUM_USERCALL; i++) { if (tgt == usercall_addr[i]) { dr_printf("Call #0x%02x to %s at %s+0x%x\n", imm, usercall_names[i], sym, pre_pc - entry); found = true; break; } } if (found) break; } else if (instr_is_return(instr)) break; if (pc - entry > MAX_BYTES_BEFORE_USERCALL) break; } instr_destroy(dcontext, instr); }
static dr_emit_flags_t event_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr, bool for_trace, bool translating, void *user_data) { /* ignore tool-inserted instrumentation */ if (!instr_is_app(instr)) return DR_EMIT_DEFAULT; /* instrument calls and returns -- ignore far calls/rets */ if (instr_is_call_direct(instr)) { insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_direct_calls)); } else if (instr_is_call_indirect(instr)) { insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_indirect_calls)); } else if (instr_is_return(instr)) { insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_returns)); } return DR_EMIT_DEFAULT; }
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { instr_t *instr, *next_instr; #ifdef VERBOSE dr_printf("in dynamorio_basic_block(tag="PFX")\n", tag); # ifdef VERBOSE_VERBOSE instrlist_disassemble(drcontext, tag, bb, STDOUT); # endif #endif for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) { /* grab next now so we don't go over instructions we insert */ next_instr = instr_get_next(instr); /* instrument calls and returns -- ignore far calls/rets */ if (instr_is_call_direct(instr)) { insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_direct_calls)); } else if (instr_is_call_indirect(instr)) { insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_indirect_calls)); } else if (instr_is_return(instr)) { insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_returns)); } } #if defined(VERBOSE) && defined(VERBOSE_VERBOSE) dr_printf("Finished instrumenting dynamorio_basic_block(tag="PFX")\n", tag); instrlist_disassemble(drcontext, tag, bb, STDOUT); #endif return DR_EMIT_DEFAULT; }