/* return if instruction */ bool instr_uses_aflags(instr_t *instr) { uint aflags; aflags = instr_get_arith_flags(instr); if (TESTANY(EFLAGS_READ_6, aflags) || TESTANY(EFLAGS_WRITE_6, aflags)) return true; return false; }
void init_dr_marker(dr_marker_t *marker) { /* not calling memset b/c windbg_cmds is large */ # ifdef DEBUG marker->flags = DR_MARKER_DEBUG_BUILD; # else marker->flags = DR_MARKER_RELEASE_BUILD; # endif # ifdef PROFILE marker->flags = DR_MARKER_PROFILE_BUILD; # endif /* make sure we set one of the above flags and not more then one */ ASSERT(TESTANY(DR_MARKER_BUILD_TYPES, marker->flags) && ((DR_MARKER_BUILD_TYPES & marker->flags) & ((DR_MARKER_BUILD_TYPES & marker->flags) - 1)) == 0); /* TODO : add any additional flags? */ marker->build_num = BUILD_NUMBER; marker->dr_base_addr = get_module_base((app_pc)init_dr_marker); marker->dr_generic_nudge_target = (void *)generic_nudge_target; # ifdef HOT_PATCHING_INTERFACE marker->dr_hotp_policy_status_table = (void *)hotp_policy_status_table; # else marker->dr_hotp_policy_status_table = NULL; # endif marker->dr_marker_version = DR_MARKER_VERSION_CURRENT; marker->stats = get_dr_stats(); dr_marker_magic_init(NT_CURRENT_PROCESS, marker); marker->windbg_cmds[0] = '\0'; }
cache_pc indirect_linkstub_target(dcontext_t *dcontext, fragment_t *f, linkstub_t *l) { // COMPLETEDD #495 indirect_linkstub_target printf("Starting indirect_linkstub_target\n"); ASSERT(LINKSTUB_INDIRECT(l->flags)); ASSERT(!TESTANY(LINK_NI_SYSCALL_ALL, l->flags)); #ifdef WINDOWS if (EXIT_TARGETS_SHARED_SYSCALL(l->flags)) { /* currently this is the only way to distinguish shared_syscall * exit from other indirect exits and from other exits in * a fragment containing ignorable or non-ignorable syscalls */ ASSERT(TEST(FRAG_HAS_SYSCALL, f->flags)); return shared_syscall_routine_ex(dcontext _IF_X64(MODE_OVERRIDE(FRAG_IS_32(f->flags)))); } #endif if (TEST(FRAG_COARSE_GRAIN, f->flags)) { /* Need to target the ibl prefix. Passing in cti works as well as stub, * and avoids a circular dependence where linkstub_unlink_entry_offset() * call this routine to get the target and then this routine asks for * the stub which calls linkstub_unlink_entry_offset()... */ return get_coarse_ibl_prefix(dcontext, EXIT_CTI_PC(f, l), extract_branchtype(l->flags)); } else { return get_ibl_routine_ex(dcontext, IF_X64(TEST(LINK_TRACE_CMP, l->flags) ? IBL_TRACE_CMP :) IBL_LINKED, get_source_fragment_type(dcontext, f->flags), extract_branchtype(l->flags) _IF_X64(MODE_OVERRIDE(FRAG_IS_32(f->flags)))); } }
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; }
bool instr_reads_from_aflags(instr_t *instr) { uint aflags; aflags = instr_get_arith_flags(instr); if (TESTANY(EFLAGS_READ_6, aflags)) return true; return false; }
static bool drsys_iter_arg_cb(drsys_arg_t *arg, void *user_data) { buf_info_t *buf = (buf_info_t *) user_data; ASSERT(arg->valid, "no args should be invalid"); if ((arg->pre && !TEST(DRSYS_PARAM_RETVAL, arg->mode)) || (!arg->pre && TESTANY(DRSYS_PARAM_OUT|DRSYS_PARAM_RETVAL, arg->mode))) print_arg(buf, arg); return true; /* keep going */ }
bool instr_writes_to_any_aflags(instr_t *instr) { uint aflags; aflags = instr_get_arith_flags(instr); if (TESTANY(EFLAGS_WRITE_6, aflags)) return true; return false; }
/* Semi-compatibility with the Windows CRT _access function. */ drfront_status_t drfront_access(const char *fname, drfront_access_mode_t mode, OUT bool *ret) { int r; struct stat st; uid_t euid; if (ret == NULL) return DRFRONT_ERROR_INVALID_PARAMETER; r = stat(fname, &st); if (r == -1) { *ret = false; if (errno == EACCES || errno == ENOENT || errno == ENOTDIR) return DRFRONT_SUCCESS; return DRFRONT_ERROR; } else if (mode == DRFRONT_EXIST) { /* Just checking for existence */ *ret = true; return DRFRONT_SUCCESS; } *ret = false; euid = geteuid(); /* It is assumed that (S_IRWXU >> 6) == DRFRONT_READ | DRFRONT_WRITE | DRFRONT_EXEC */ if (euid == 0) { /* XXX DrMi#1857: we assume that euid == 0 means +rw access to any file, * and +x access to any file with at least one +x bit set. This is * usually true but not always. */ if (TEST(DRFRONT_EXEC, mode)) { *ret = TESTANY((DRFRONT_EXEC << 6) | (DRFRONT_EXEC << 3) | DRFRONT_EXEC, st.st_mode); } else *ret = true; } else if (euid == st.st_uid) { /* Check owner permissions */ *ret = TESTALL(mode << 6, st.st_mode); } else { /* Check other permissions */ *ret = TESTALL(mode, st.st_mode); } if (*ret && S_ISDIR(st.st_mode) && TEST(DRFRONT_WRITE, mode)) { /* We use an actual write try, to avoid failing on a read-only filesystem * (DrMi#1857). */ return drfront_dir_try_writable(fname, ret); } return DRFRONT_SUCCESS; }
/* iterate basic block to check if aflags are dead after (including) where */ static bool bb_aflags_are_dead(instrlist_t *ilist, instr_t *where) { instr_t *instr; uint flags; for (instr = where; instr != NULL; instr = instr_get_next(instr)) { flags = instr_get_arith_flags(instr); if (TESTANY(EFLAGS_READ_6, flags)) return false; if (TESTALL(EFLAGS_WRITE_6, flags)) return true; } 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, *first = instrlist_first(bb), *point = NULL; uint num_instrs; uint flags; uint need_restore; /* count instruction */ for (instr = first, num_instrs = 0; instr != NULL; instr = instr_get_next(instr)) { num_instrs++; } need_restore = 0; flags = instr_get_arith_flags(instr); /* eflags are not dead save eflags to register */ if (!(TESTALL(EFLAGS_WRITE_6, flags) && !TESTANY(EFLAGS_READ_6, flags))) { need_restore = 1; dr_save_reg(drcontext, bb, first, DR_REG_XAX, SPILL_SLOT_1); dr_save_arith_flags_to_xax(drcontext, bb, first); } /* add the instruction count */ instrlist_meta_preinsert (bb, first, INSTR_CREATE_add(drcontext, OPND_CREATE_ABSMEM ((byte *)&global_count, OPSZ_4), OPND_CREATE_INT32(num_instrs))); /* Need to carry since it is a 8 byte variable. */ instrlist_meta_preinsert (bb, first, INSTR_CREATE_adc(drcontext, OPND_CREATE_ABSMEM ((byte *)&global_count + 4, OPSZ_4), OPND_CREATE_INT32(0))); /* resotre eflags */ if (need_restore) { dr_restore_arith_flags_from_xax(drcontext, bb, first); dr_restore_reg(drcontext, bb, first, DR_REG_XAX, SPILL_SLOT_1); } return DR_EMIT_DEFAULT; }
static void print_arg(buf_info_t *buf, drsys_arg_t *arg) { if (arg->ordinal == -1) OUTPUT(buf, "\tretval: "); else OUTPUT(buf, "\targ %d: ", arg->ordinal); if (arg->enum_name != NULL) { if (drstrace_get_arg_symname(buf, arg)) return; } /* XXX: add return value to dr_fprintf so we can more easily align * after PFX vs PIFX w/o having to print to buffer */ switch (arg->type) { case DRSYS_TYPE_VOID: print_simple_value(buf, arg, true); break; case DRSYS_TYPE_POINTER: print_simple_value(buf, arg, true); break; case DRSYS_TYPE_BOOL: print_simple_value(buf, arg, false); break; case DRSYS_TYPE_INT: print_simple_value(buf, arg, false); break; case DRSYS_TYPE_SIGNED_INT: print_simple_value(buf, arg, false); break; case DRSYS_TYPE_UNSIGNED_INT: print_simple_value(buf, arg, false); break; case DRSYS_TYPE_HANDLE: print_simple_value(buf, arg, false); break; case DRSYS_TYPE_NTSTATUS: print_simple_value(buf, arg, false); break; case DRSYS_TYPE_ATOM: print_simple_value(buf, arg, false); break; default: { if (arg->value == 0) { OUTPUT(buf, "<null>"); } else if (arg->pre && !TEST(DRSYS_PARAM_IN, arg->mode)) { OUTPUT(buf, PFX, arg->value); } else { if (!print_known_compound_type(buf, arg->type, (void *) arg->value)) OUTPUT(buf, "<NYI>"); } } } OUTPUT(buf, " (%s%s%stype=%s%s, size="PIFX")\n", (arg->arg_name == NULL) ? "" : "name=", (arg->arg_name == NULL) ? "" : arg->arg_name, (arg->arg_name == NULL) ? "" : ", ", (arg->type_name == NULL) ? "\"\"" : arg->type_name, (arg->type_name == NULL || TESTANY(DRSYS_PARAM_INLINED|DRSYS_PARAM_RETVAL, arg->mode)) ? "" : "*", arg->size); }
/* Passing in stub's info avoids a vmvector lookup */ void unlink_entrance_stub(dcontext_t *dcontext, cache_pc stub, uint flags, coarse_info_t *info /*OPTIONAL*/) { // COMPLETEDD #499 unlink_entrance_stub printf("Starting unlink_enterance_stub\n"); cache_pc tgt; ASSERT(DYNAMO_OPTION(coarse_units)); ASSERT(coarse_is_entrance_stub(stub)); ASSERT(self_owns_recursive_lock(&change_linking_lock)); LOG(THREAD, LOG_LINKS, 5, "unlink_entrance_stub "PFX"\n", stub); if (TESTANY(FRAG_IS_TRACE_HEAD|FRAG_IS_TRACE, flags)) tgt = trace_head_return_coarse_prefix(stub, info); else tgt = fcache_return_coarse_prefix(stub, info); if (patch_coarse_branch(stub, tgt, HOT_PATCHABLE, info)) STATS_INC(pcache_unprot_unlink); }
size_t hashtable_persist_size(void *drcontext, hashtable_t *table, size_t entry_size, void *perscxt, hasthable_persist_flags_t flags) { uint count = 0; if (table->hashtype == HASH_INTPTR && TESTANY(DR_HASHPERS_ONLY_IN_RANGE | DR_HASHPERS_ONLY_PERSISTED, flags)) { /* synch is already provided */ uint i; ptr_uint_t start = 0; size_t size = 0; if (perscxt != NULL) { start = (ptr_uint_t) dr_persist_start(perscxt); size = dr_persist_size(perscxt); } count = 0; for (i = 0; i < HASHTABLE_SIZE(table->table_bits); i++) { hash_entry_t *he; for (he = table->table[i]; he != NULL; he = he->next) { if ((!TEST(DR_HASHPERS_ONLY_IN_RANGE, flags) || key_in_range(table, he, start, size)) && (!TEST(DR_HASHPERS_ONLY_PERSISTED, flags) || dr_fragment_persistable(drcontext, perscxt, he->key))) count++; } } } else count = table->entries; /* we could have an OUT count param that user must pass to hashtable_persist, * but that's actually a pain for the user when persisting multiple tables, * and usage should always call hashtable_persist() right after calling * hashtable_persist_size(). */ table->persist_count = count; return sizeof(count) + (TEST(DR_HASHPERS_REBASE_KEY, flags) ? sizeof(ptr_uint_t) : 0) + count * (entry_size + sizeof(void*)); }
static inline void check_translation(instrlist_t *ilist, instr_t *inst) { if (ilist->translation_target != NULL && instr_get_translation(inst) == NULL) { instr_set_translation(inst, ilist->translation_target); } if (instrlist_get_our_mangling(ilist)) instr_set_our_mangling(inst, true); #if defined(CLIENT_INTERFACE) && defined(ARM) if (instr_is_meta(inst)) { dr_pred_type_t auto_pred = ilist->auto_pred; if (instr_predicate_is_cond(auto_pred)) { CLIENT_ASSERT(!instr_is_cti(inst), "auto-predication does not support cti's"); CLIENT_ASSERT( !TESTANY(EFLAGS_WRITE_NZCV, instr_get_arith_flags(inst, DR_QUERY_INCLUDE_COND_SRCS)), "cannot auto predicate a meta-inst that writes to NZCV"); if (!instr_is_predicated(inst)) instr_set_predicate(inst, auto_pred); } } #endif }
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { int i; const int MAX_INSTR_LEN = 64; char instr_name[MAX_INSTR_LEN]; instr_t *instr, *first = instrlist_first(bb); uint flags; uint cur_flop_count = 0; uint tracked_instr_count[tracked_instrs_len]; for( i = 0; i < tracked_instrs_len; i++ ) tracked_instr_count[i] = 0; #ifdef VERBOSE dr_printf("in dynamorio_basic_block(tag="PFX")\n", tag); # ifdef VERBOSE_VERBOSE instrlist_disassemble(drcontext, tag, bb, STDOUT); # endif #endif /* we use fp ops so we have to save fp state */ byte fp_raw[512 + 16]; byte *fp_align = (byte *) ( (((ptr_uint_t)fp_raw) + 16) & ((ptr_uint_t)-16) ); if (translating) { return DR_EMIT_DEFAULT; } proc_save_fpstate(fp_align); int my_readfrom[DR_REG_LAST_VALID_ENUM+MY_NUM_EFLAGS+1]; int my_writtento[DR_REG_LAST_VALID_ENUM+MY_NUM_EFLAGS+1]; for (i = 0; i < DR_REG_LAST_VALID_ENUM+MY_NUM_EFLAGS+1; i++) { my_readfrom[i] = 0; my_writtento[i] = 0; } t_glob_reg_state glob_reg_state = {0,0,0,0,0,0,my_readfrom,my_writtento}; int my_cur_size = 0; for (instr = instrlist_first(bb); instr != NULL; instr = instr_get_next(instr)) { my_cur_size++; /* ILP Calculations */ glob_reg_state.raw_setnr = 1; glob_reg_state.war_setnr = 1; glob_reg_state.waw_setnr = 1; glob_reg_state.else_setnr = 1; glob_reg_state.final_setnr = 1; calc_set_num(instr, &glob_reg_state); /* Count flop instr */ if( instr_is_floating( instr ) ) { cur_flop_count += 1; } /* Count mul instructions */ instr_disassemble_to_buffer( drcontext, instr, instr_name, MAX_INSTR_LEN ); for( i = 0; i < tracked_instrs_len; i++ ) { if( strncmp( instr_name, tracked_instrs[i], strlen(tracked_instrs[i])) == 0) { tracked_instr_count[i] += 1; } } } //now we can calculate the ILP. float ilp = ((float)my_cur_size) / ((float)(glob_reg_state.num_sets != 0 ? glob_reg_state.num_sets : 1)); dr_mutex_lock(stats_mutex); // Due to lack of memory, we only store the ILPs for the latest MY_MAX_BB // basic blocks. This enables us to run e.g. firefox. int my_cur_num = my_bbcount % MY_MAX_BB; my_bbcount++; if(my_cur_num == 0 && my_bbcount > 1) { dr_printf("Overflow at %d\n", my_bbcount); } my_bbexecs[my_cur_num] = 0; //initialize my_bbsizes[my_cur_num] = my_cur_size; bb_flop_count[my_cur_num] = cur_flop_count; for( i = 0; i < tracked_instrs_len; i++ ) { bb_instr_count[my_cur_num*tracked_instrs_len+i] = tracked_instr_count[i]; } my_bbilp[my_cur_num] = ilp; dr_mutex_unlock(stats_mutex); #ifdef USE_CLEAN_CALL dr_insert_clean_call(drcontext, bb, instrlist_first(bb), clean_call, false, 1, OPND_CREATE_INT32(my_cur_num)); #else #ifdef INSERT_AT_END instr = NULL; #else // Find place to insert inc instruction for (instr = first; instr != NULL; instr = instr_get_next(instr)) { flags = instr_get_arith_flags(instr); if (TESTALL(EFLAGS_WRITE_6, flags) && !TESTANY(EFLAGS_READ_6, flags)) break; } #endif if (instr == NULL) { // no suitable place found, save regs dr_save_reg(drcontext, bb, first, DR_REG_XAX, SPILL_SLOT_1); dr_save_arith_flags_to_xax(drcontext, bb, first); } // Increment my_bbexecs[my_current_bb] using the lock prefix instrlist_meta_preinsert (bb, (instr == NULL) ? first : instr, LOCK(INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM ((byte *)&(my_bbexecs[my_cur_num]), OPSZ_4)))); if (instr == NULL) { // no suitable place found earlier, restore regs dr_restore_arith_flags_from_xax(drcontext, bb, first); dr_restore_reg(drcontext, bb, first, DR_REG_XAX, SPILL_SLOT_1); } #endif proc_restore_fpstate(fp_align); #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; }
static void print_arg(drsys_arg_t *arg) { if (arg->ordinal == -1) OUTPUT("\tretval: "); else OUTPUT("\targ %d: ", arg->ordinal); /* XXX: add return value to dr_fprintf so we can more easily align * after PFX vs PIFX w/o having to print to buffer */ switch (arg->type) { case DRSYS_TYPE_VOID: print_simple_value(arg, true); break; case DRSYS_TYPE_POINTER: print_simple_value(arg, true); break; case DRSYS_TYPE_BOOL: print_simple_value(arg, false); break; case DRSYS_TYPE_INT: print_simple_value(arg, false); break; case DRSYS_TYPE_SIGNED_INT: print_simple_value(arg, false); break; case DRSYS_TYPE_UNSIGNED_INT: print_simple_value(arg, false); break; case DRSYS_TYPE_HANDLE: print_simple_value(arg, false); break; case DRSYS_TYPE_NTSTATUS: print_simple_value(arg, false); break; case DRSYS_TYPE_ATOM: print_simple_value(arg, false); break; default: { if (arg->value == 0) { OUTPUT("<null>"); } else if (arg->pre && !TEST(DRSYS_PARAM_IN, arg->mode)) { OUTPUT(PFX, arg->value); } else { switch (arg->type) { case DRSYS_TYPE_UNICODE_STRING: { print_unicode_string((UNICODE_STRING *) arg->value); break; } case DRSYS_TYPE_OBJECT_ATTRIBUTES: { OBJECT_ATTRIBUTES *oa = (OBJECT_ATTRIBUTES *) arg->value; OUTPUT("len="PIFX", root="PIFX", name=", oa->Length, oa->RootDirectory); print_unicode_string(oa->ObjectName); OUTPUT(", att="PIFX", sd="PFX", sqos="PFX, oa->Attributes, oa->SecurityDescriptor, oa->SecurityQualityOfService); break; } case DRSYS_TYPE_IO_STATUS_BLOCK: { IO_STATUS_BLOCK *io = (IO_STATUS_BLOCK *) arg->value; OUTPUT("status="PIFX", info="PIFX"", io->StatusPointer.Status, io->Information); break; } case DRSYS_TYPE_LARGE_INTEGER: { LARGE_INTEGER *li = (LARGE_INTEGER *) arg->value; OUTPUT("0x"HEX64_FORMAT_STRING, li->QuadPart); break; } default: { /* FIXME i#1089: add the other types */ OUTPUT("<NYI>"); } } /* XXX: we want KEY_VALUE_PARTIAL_INFORMATION, etc. like in * syscall_diagnostics. Add drsyscall types for those, or hardcode here? */ } } } OUTPUT(" (%s%s%stype=%s%s, size="PIFX")\n", (arg->arg_name == NULL) ? "" : "name=", (arg->arg_name == NULL) ? "" : arg->arg_name, (arg->arg_name == NULL) ? "" : ", ", (arg->type_name == NULL) ? "\"\"" : arg->type_name, (arg->type_name == NULL || TESTANY(DRSYS_PARAM_INLINED|DRSYS_PARAM_RETVAL, arg->mode)) ? "" : "*", arg->size); }