Example #1
0
static dr_emit_flags_t
bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;
    int opcode;
    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);
        opcode = instr_get_opcode(instr);
	if(instr_is_floating(instr)){
   	//	dr_fprintf(logF, "Has seen FPU instruction with opcode %d\n",opcode);
	
	}
	else if(is_SIMD_packed(opcode)){
   	//	dr_fprintf(logF, "Has seen SIMD packed instruction with opcode %d\n",opcode);
	}
//AVX?rcpps?

	else if(is_SIMD_arithm(opcode)){
		int is_single = 0;
//		printf("opcode is   %d\n", opcode);
//    		printf("number of sources  %d\n", instr_num_srcs(instr));  
 //   		printf("number of dests  %d\n", instr_num_dsts(instr));
		//assert(number of sources = 2);
		opnd_t source1 = instr_get_src(instr,0);
		opnd_t source2 = instr_get_src(instr,1);
		opnd_t dest = instr_get_dst(instr,0);
		if(opnd_is_memory_reference(source1)){
	//		dr_print_instr(drcontext, logF, instr, "INSTR: ");
//			dr_print_opnd(drcontext, logF, source1, "OPND1: ");
//			dr_print_opnd(drcontext, logF, source2, "OPND2: ");
			reg_id_t rd = opnd_get_reg(source2);
			reg_id_t rs = opnd_get_reg_used(source1, 0);
			dr_insert_clean_call(drcontext, bb, instr, 
				(void*) callback, true, 5, 
				OPND_CREATE_INTPTR(rs), OPND_CREATE_INTPTR(opnd_get_disp(source1)),
				OPND_CREATE_INTPTR(rd), OPND_CREATE_INTPTR(opcode), OPND_CREATE_INTPTR(instr_get_app_pc(instr)));

		}
		else if(opnd_is_reg(source1) && opnd_is_reg(source2)){
			reg_id_t reg1 = opnd_get_reg(source1);
			reg_id_t reg2 = opnd_get_reg(source2);
			dr_insert_clean_call(drcontext,bb,instr, (void*)getRegReg, 
				true, 4, 
				OPND_CREATE_INTPTR(reg1), OPND_CREATE_INTPTR(reg2)
				,OPND_CREATE_INTPTR(opcode), OPND_CREATE_INTPTR(instr_get_app_pc(instr))
			); 
		}
		else{
		//should not be the case, throw an exception
		}
	        fp_count++; 
      }
    }

    return DR_EMIT_DEFAULT;
}
Example #2
0
static dr_emit_flags_t
event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
                bool for_trace, bool translating, void *user_data)
{
    static int freq;
    reg_id_t reg1 = IF_X86_ELSE(DR_REG_XAX, DR_REG_R0);
    reg_id_t reg2 = IF_X86_ELSE(DR_REG_XCX, DR_REG_R1);

    CHECK(drmgr_is_first_instr(drcontext, instrlist_first_app(bb)), "first incorrect");
    CHECK(!drmgr_is_first_instr(drcontext, instrlist_last(bb)) ||
          instrlist_first_app(bb) == instrlist_last(bb), "first incorrect");
    CHECK(drmgr_is_last_instr(drcontext, instrlist_last(bb)), "last incorrect");
    CHECK(!drmgr_is_last_instr(drcontext, instrlist_first_app(bb)) ||
          instrlist_first_app(bb) == instrlist_last(bb), "last incorrect");

    /* hack to instrument every nth bb.  assumes DR serializes bb events. */
    freq++;
    if (freq % 100 == 0 && inst == (instr_t*)user_data/*first instr*/) {
        /* test read from cache */
        dr_save_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
        drmgr_insert_read_tls_field(drcontext, tls_idx, bb, inst, reg1);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_from_cache,
                             false, 1, opnd_create_reg(reg1));
        drmgr_insert_read_cls_field(drcontext, cls_idx, bb, inst, reg1);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_from_cache,
                             false, 1, opnd_create_reg(reg1));
        dr_restore_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
    }
    if (freq % 300 == 0 && inst == (instr_t*)user_data/*first instr*/) {
        instr_t *first, *second;
        /* test write from cache */
        dr_save_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
        dr_save_reg(drcontext, bb, inst, reg2, SPILL_SLOT_2);
        instrlist_insert_mov_immed_ptrsz(drcontext,
                                         (ptr_int_t)MAGIC_NUMBER_FROM_CACHE,
                                         opnd_create_reg(reg1),
                                         bb, inst, &first, &second);
        instr_set_meta(first);
        if (second != NULL)
            instr_set_meta(second);
        drmgr_insert_write_tls_field(drcontext, tls_idx, bb, inst, reg1, reg2);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_write_from_cache,
                             false, 0);
        drmgr_insert_write_cls_field(drcontext, cls_idx, bb, inst, reg1, reg2);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_write_from_cache,
                             false, 0);
        dr_restore_reg(drcontext, bb, inst, reg2, SPILL_SLOT_2);
        dr_restore_reg(drcontext, bb, inst, reg1, SPILL_SLOT_1);
    }
    return DR_EMIT_DEFAULT;
}
Example #3
0
static dr_emit_flags_t
drmgr_event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
                      bool for_trace, bool translating, void *user_data)
{
    if (instr_get_app_pc(inst) == addr_KiCallback) {
        dr_insert_clean_call(drcontext, bb, inst, (void *)drmgr_cls_stack_push,
                             false, 0);
    }
    if (instr_get_opcode(inst) == OP_int &&
        opnd_get_immed_int(instr_get_src(inst, 0)) == CBRET_INTERRUPT_NUM) {
        dr_insert_clean_call(drcontext, bb, inst, (void *)drmgr_cls_stack_pop,
                             false, 0);
    }
    return DR_EMIT_DEFAULT;
}
Example #4
0
dr_emit_flags_t
memdump_bb_instrumentation(void *drcontext, void *tag, instrlist_t *bb,
instr_t *instr, bool for_trace, bool translating,
void *user_data)
{

	reg_id_t reg1 = DR_REG_XAX;
	reg_id_t reg2 = DR_REG_XBX;
	int i = 0;

	if(filter_bb_level_from_list(app_pc_head, instr)){

		dr_save_reg(drcontext, bb, instr, reg1, SPILL_SLOT_1);
		dr_save_reg(drcontext, bb, instr, reg2, SPILL_SLOT_2);
		
		dr_mutex_lock(mutex);
		DEBUG_PRINT("instrumenting %x pc\n", instr_get_app_pc(instr));

		instr_clones[instr_clone_amount] = instr_clone(drcontext, instr);

		for (i = 0; i < instr_num_srcs(instr); i++){
			if (opnd_is_memory_reference(instr_get_src(instr, i))) {
				drutil_insert_get_mem_addr(drcontext, bb, instr, instr_get_src(instr,i), reg1, reg2);
				dr_insert_clean_call(drcontext, bb, instr, clean_call_mem_information, false, 3, 
					OPND_CREATE_INTPTR(instr_clones[instr_clone_amount]), opnd_create_reg(reg1), OPND_CREATE_INTPTR(false));
			}
		}
		for (i = 0; i < instr_num_dsts(instr); i++){
			if (opnd_is_memory_reference(instr_get_dst(instr, i))) {
				drutil_insert_get_mem_addr(drcontext, bb, instr, instr_get_dst(instr, i), reg1, reg2);
				dr_insert_clean_call(drcontext, bb, instr, clean_call_mem_information, false, 3, 
					OPND_CREATE_INTPTR(instr_clones[instr_clone_amount]), opnd_create_reg(reg1), OPND_CREATE_INTPTR(true));
			}
		}
		

		instr_clone_amount++;

		dr_mutex_unlock(mutex);

		dr_restore_reg(drcontext, bb, instr, reg1, SPILL_SLOT_1);
		dr_restore_reg(drcontext, bb, instr, reg2, SPILL_SLOT_2);


	}

	return DR_EMIT_DEFAULT;
}
Example #5
0
/* This event is called separately for each individual instruction in the bb. */
static dr_emit_flags_t
event_insert_instrumentation(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                             bool for_trace, bool translating, void *user_data)
{
    bool bb_in_app;
    if (dr_fragment_app_pc(tag) >= app_base && dr_fragment_app_pc(tag) < app_end)
        bb_in_app = true;
    else
        bb_in_app = false;

    if (drmgr_is_first_instr(drcontext, instr)) {
        uint num_instrs = (uint)(ptr_uint_t)user_data;
        dr_insert_clean_call(drcontext, bb, instr,
                             (void *)(bb_in_app ? app_update : lib_update),
                             false /* save fpstate */, 1, OPND_CREATE_INT32(num_instrs));
    }

    if (instr_is_mbr(instr) && !instr_is_return(instr)) {
        /* Assuming most of the transfers between app and lib are paired, we
         * instrument indirect branches but not returns for better performance.
         */
        dr_insert_mbr_instrumentation(
            drcontext, bb, instr, (void *)(bb_in_app ? app_mbr : lib_mbr), SPILL_SLOT_1);
    }

    return DR_EMIT_DEFAULT;
}
Example #6
0
dr_emit_flags_t
inscount_bb_instrumentation(void *drcontext, void *tag, instrlist_t *bb,
				instr_t *instr, bool for_trace, bool translating,
				void *user_data)
{

	instr_t *first = instrlist_first(bb);
	uint num_instrs = 0;

	if(instr != first)
		return DR_EMIT_DEFAULT;

	if(filter_from_list(head,instr,client_arg->filter_mode)){
		for(instr = first ; instr!=NULL ; instr = instr_get_next(instr)){
			num_instrs++;
		}
		bbcount++;
	}


	if(num_instrs > 0){
		dr_insert_clean_call(drcontext, bb, instrlist_first(bb),
							(void *)inscount, false /* save fpstate */, 1,
							OPND_CREATE_INT32(num_instrs));
	}







	return DR_EMIT_DEFAULT;
}
Example #7
0
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                  bool for_trace, bool translating)
{
    instr_t *instr;
    uint num_instrs;
    
#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), num_instrs = 0;
         instr != NULL;
         instr = instr_get_next(instr)) {
        num_instrs++;
    }

    dr_insert_clean_call(drcontext, bb, instrlist_first(bb), 
                         (void *)inscount, false /* save fpstate */, 1,
                         OPND_CREATE_INT32(num_instrs));

#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;
}
Example #8
0
/* code cache to hold the call to "clean_call" and return to DR code cache */
static void
code_cache_init(void)
{
    void         *drcontext;
    instrlist_t  *ilist;
    instr_t      *where;
    byte         *end;

    drcontext  = dr_get_current_drcontext();
    code_cache = dr_nonheap_alloc(PAGE_SIZE,
                                  DR_MEMPROT_READ  |
                                  DR_MEMPROT_WRITE |
                                  DR_MEMPROT_EXEC);
    ilist = instrlist_create(drcontext);
    /* The lean procecure simply performs a clean call, and then jump back */
    /* jump back to the DR's code cache */
    where = INSTR_CREATE_jmp_ind(drcontext, opnd_create_reg(DR_REG_XCX));
    instrlist_meta_append(ilist, where);
    /* clean call */
    dr_insert_clean_call(drcontext, ilist, where, (void *)clean_call_ins_trace, false, 0);
    /* Encodes the instructions into memory and then cleans up. */
    end = instrlist_encode(drcontext, ilist, code_cache, false);
    DR_ASSERT((end - code_cache) < PAGE_SIZE);
    instrlist_clear_and_destroy(drcontext, ilist);
    /* set the memory as just +rx now */
    dr_memory_protect(code_cache, PAGE_SIZE, DR_MEMPROT_READ | DR_MEMPROT_EXEC);
}
Example #9
0
/*
 * Function that tests a single operand of an instruction to see if
 * it's a memory reference, and if so, adds a call to log_mem.
 */
static void try_mem_opnd(
    void *drcontext, instrlist_t *bb, instr_t *instr, char **loc,
    opnd_t opnd, bool write)
{
    if (!opnd_is_memory_reference(opnd))
        return;

    instr_format_location(instr, loc);

    reg_id_t r0, r1;
    drreg_status_t st;
    st = drreg_reserve_register(drcontext, bb, instr, NULL, &r0);
    DR_ASSERT(st == DRREG_SUCCESS);
    st = drreg_reserve_register(drcontext, bb, instr, NULL, &r1);
    DR_ASSERT(st == DRREG_SUCCESS);

    bool ok = drutil_insert_get_mem_addr(drcontext, bb, instr, opnd, r0, r1);
    DR_ASSERT(ok);

    uint size = drutil_opnd_mem_size_in_bytes(opnd, instr);

    dr_insert_clean_call(
        drcontext, bb, instr, (void *)log_mem, false,
        4, opnd_create_reg(r0), OPND_CREATE_INT32(size),
        OPND_CREATE_INT32(write), OPND_CREATE_INTPTR(*loc));

    st = drreg_unreserve_register(drcontext, bb, instr, r1);
    DR_ASSERT(st == DRREG_SUCCESS);
    st = drreg_unreserve_register(drcontext, bb, instr, r0);
    DR_ASSERT(st == DRREG_SUCCESS);
}
Example #10
0
static dr_emit_flags_t
bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    app_pc pc = dr_fragment_app_pc(tag);

    if (pc == start_pc) {
        dr_fprintf(STDERR, "starting syscall monitoring\n");
        monitoring = true;
    }
    else if (pc == stop_pc) {
        dr_fprintf(STDERR, "stopping syscall monitoring\n");
        monitoring = false;
    }
    else {
        instr_t* instr;
        instr_t* next_instr;

        for (instr = instrlist_first(bb);
             instr != NULL;
             instr = next_instr) {

            next_instr = instr_get_next(instr);

            /* Insert a callback to at_syscall before every system call */
            if (instr_is_syscall(instr)) {
                dr_insert_clean_call(drcontext, bb, instr, at_syscall, false, 0);
            }
        }
    }
    return DR_EMIT_DEFAULT;
}
static
dr_emit_flags_t bb_event(void* drcontext, void* tag, instrlist_t* bb, bool for_trace, bool translating)
{
    dr_fprintf(STDERR, "got BB event\n");
    dr_insert_clean_call(drcontext, bb, instrlist_first(bb),
                         (void *)unregister, false, 0);
    return DR_EMIT_DEFAULT;
}
Example #12
0
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    /* if find div, insert a clean call to our instrumentation routine */
    opnd_t opnd;
    if (instr_is_div(instr, &opnd)) {
        dr_insert_clean_call(drcontext, bb, instr, (void *)callback, false /*no fp save*/,
                             2, OPND_CREATE_INTPTR(instr_get_app_pc(instr)), opnd);
    }
    return DR_EMIT_DEFAULT;
}
Example #13
0
dr_emit_flags_t
funcwrap_bb_instrumentation(void *drcontext, void *tag, instrlist_t *bb,
instr_t *instr, bool for_trace, bool translating,
void *user_data)
{

	instr_t * first = instrlist_first(bb);
	app_pc pc = instr_get_app_pc(first);
	module_data_t * module_data;
	per_thread_t * data = drmgr_get_tls_field(dr_get_current_drcontext(), tls_index);
	module_t * md;
	app_pc offset;
	
	
	if (instr != first || data->nesting != 0){
		return DR_EMIT_DEFAULT;
	}

	module_data = dr_lookup_module(pc);
	data = drmgr_get_tls_field(drcontext, tls_index);

	
	if (module_data != NULL){
		md = md_lookup_module(head, module_data->full_path);
		if (md != NULL){
			offset = pc - module_data->start;
			
			for (int i = 1; i <= md->bbs[0].start_addr; i++){
				if (offset == md->bbs[i].start_addr){
					DEBUG_PRINT("bb instrumenting function\n");
					data->filter_func = true;
					dr_insert_clean_call(drcontext, bb, instr, clean_call, false, 1, OPND_CREATE_INTPTR(instr_get_app_pc(instr)));
					wrap_thread_id = dr_get_thread_id(drcontext);
					DEBUG_PRINT("done bb instrumenting function\n");

				}
			}
		}
	}

	

	/*if (data->filter_func){
		instrlist_disassemble(drcontext, instr_get_app_pc(instrlist_first(bb)), bb, logfile);
	}*/

	dr_free_module_data(module_data);


	return DR_EMIT_DEFAULT;

}
Example #14
0
static dr_emit_flags_t
event_app_instruction(void* drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    /* if find div, insert a clean call to our instrumentation routine */
    if (instr_get_opcode(instr) == OP_div) {
        dr_insert_clean_call(drcontext, bb, instr, (void *)callback,
                             false /*no fp save*/, 2,
                             OPND_CREATE_INTPTR(instr_get_app_pc(instr)),
                             instr_get_src(instr, 0) /*divisor is 1st src*/);
    }
    return DR_EMIT_DEFAULT;
}
Example #15
0
static dr_emit_flags_t
event_bb_insert(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
                bool for_trace, bool translating, void *user_data)
{
    /* hack to instrument every nth bb.  assumes DR serializes bb events. */
    static int freq;
    freq++;
    if (freq % 100 == 0 && inst == (instr_t*)user_data/*first instr*/) {
        /* test read from cache */
        dr_save_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1);
        drmgr_insert_read_tls_field(drcontext, tls_idx, bb, inst, DR_REG_XAX);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_from_cache,
                             false, 1, opnd_create_reg(DR_REG_XAX));
        drmgr_insert_read_cls_field(drcontext, cls_idx, bb, inst, DR_REG_XAX);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_from_cache,
                             false, 1, opnd_create_reg(DR_REG_XAX));
        dr_restore_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1);
    }
    if (freq % 300 == 0 && inst == (instr_t*)user_data/*first instr*/) {
        /* test write from cache */
        dr_save_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1);
        dr_save_reg(drcontext, bb, inst, DR_REG_XCX, SPILL_SLOT_2);
        instrlist_meta_preinsert(bb, inst, INSTR_CREATE_mov_imm
                                 (drcontext, opnd_create_reg(DR_REG_EAX),
                                  OPND_CREATE_INT32(MAGIC_NUMBER_FROM_CACHE)));
        drmgr_insert_write_tls_field(drcontext, tls_idx, bb, inst, DR_REG_XAX,
                                     DR_REG_XCX);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_tls_write_from_cache,
                             false, 0);
        drmgr_insert_write_cls_field(drcontext, cls_idx, bb, inst, DR_REG_XAX,
                                     DR_REG_XCX);
        dr_insert_clean_call(drcontext, bb, inst, (void *)check_cls_write_from_cache,
                             false, 0);
        dr_restore_reg(drcontext, bb, inst, DR_REG_XCX, SPILL_SLOT_2);
        dr_restore_reg(drcontext, bb, inst, DR_REG_XAX, SPILL_SLOT_1);
    }
    return DR_EMIT_DEFAULT;
}
Example #16
0
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
                  bool for_trace, bool translating)
{
    instr_t *instr, *mbr = NULL;
    uint num_instrs;
    bool bb_in_app;

#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), num_instrs = 0;
         instr != NULL;
         instr = instr_get_next(instr)) {
        /* only care about app instr */
        if (!instr_ok_to_mangle(instr))
            continue;
        num_instrs++;
        /* Assuming most of the transfers between app and lib are paired, we
         * instrument indirect branches but not returns for better performance.
         */
        if (instr_is_mbr(instr) && !instr_is_return(instr))
            mbr = instr;
    }

    if (dr_fragment_app_pc(tag) >= app_base &&
        dr_fragment_app_pc(tag) <  app_end)
        bb_in_app = true;
    else
        bb_in_app = false;
    dr_insert_clean_call(drcontext, bb, instrlist_first(bb),
                         (void *)(bb_in_app ? app_update : lib_update),
                         false /* save fpstate */, 1,
                         OPND_CREATE_INT32(num_instrs));
    if (mbr != NULL) {
        dr_insert_mbr_instrumentation(drcontext, bb, mbr,
                                      (void *)(bb_in_app ? app_mbr : lib_mbr),
                                      SPILL_SLOT_1);
    }

#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;
}
Example #17
0
static dr_emit_flags_t
bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    static int64 bb_count;
    if (++bb_count % 10 == 0) {
        for (instr_t *inst = instrlist_first(bb); inst != NULL;
             inst = instr_get_next(inst)) {
            if (instr_is_exclusive_store(inst))
                return DR_EMIT_DEFAULT;
        }
        dr_insert_clean_call(drcontext, bb, instrlist_first(bb), (void *)cleancallee,
                             false, 1, OPND_CREATE_INTPTR(tag));
    }
    return DR_EMIT_DEFAULT;
}
Example #18
0
static
dr_emit_flags_t bb_event(void* drcontext, void *tag, instrlist_t *bb,
                         bool for_trace, bool translating)
{
    instr_t *instr;
    if (!translating)
        increment(tag);

    /* I'm looking for a specific BB in the test .exe.  I've marked
     * it with a couple nops.
     */
#ifdef WINDOWS
    if ((app_pc)tag >= start && (app_pc)tag < end) {
#endif
        instr = instrlist_first(bb);

        if (instr_is_nop(instr)) {
            instr_t *next = instr_get_next(instr);

            /* The test app uses two nops as a marker to identify a specific bb.  Since
             * 2 nop instructions in a row aren't that uncommon on Linux (where we can't
             * restrict our search to just the test.exe module) we use an unusual nop
             * for the second one: xchg xbp, xbp */
            if (next != NULL && instr_is_nop(next) &&
                instr_get_opcode(next) == OP_xchg &&
                instr_writes_to_exact_reg(next, REG_XBP, DR_QUERY_DEFAULT)) {

                bb_build_count++;

                if (delay_flush_at_next_build) {
                    delay_flush_at_next_build = false;
                    dr_delay_flush_region((app_pc)tag - 20, 30, callback_count, flush_event);
                }

                dr_insert_clean_call(drcontext, bb, instr, (void *)callback,
                                     false, 2, OPND_CREATE_INTPTR(tag),
                                     OPND_CREATE_INTPTR(instr_get_app_pc(instr)));
            }
        }
#ifdef WINDOWS
    }
#endif
    return DR_EMIT_DEFAULT;
}
Example #19
0
static dr_emit_flags_t
bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;
    int opcode;

    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);
        opcode = instr_get_opcode(instr);

        /* if find div, insert a clean call to our instrumentation routine */
        if (opcode == OP_div) {
            dr_insert_clean_call(drcontext, bb, instr, (void *)callback,
                                 false /*no fp save*/, 2,
                                 OPND_CREATE_INTPTR(instr_get_app_pc(instr)),
                                 instr_get_src(instr, 0) /*divisor is 1st src*/);
        }
    }
    return DR_EMIT_DEFAULT;
}
Example #20
0
/* For each memory reference app instr, we insert inline code to fill the buffer
 * with an instruction entry and memory reference entries.
 */
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    int i;

    if (!instr_is_app(instr))
        return DR_EMIT_DEFAULT;
    if (!instr_reads_memory(instr) && !instr_writes_memory(instr))
        return DR_EMIT_DEFAULT;

    /* insert code to add an entry for app instruction */
    instrument_instr(drcontext, bb, instr);

    /* insert code to add an entry for each memory reference opnd */
    for (i = 0; i < instr_num_srcs(instr); i++) {
        if (opnd_is_memory_reference(instr_get_src(instr, i)))
            instrument_mem(drcontext, bb, instr, instr_get_src(instr, i), false);
    }

    for (i = 0; i < instr_num_dsts(instr); i++) {
        if (opnd_is_memory_reference(instr_get_dst(instr, i)))
            instrument_mem(drcontext, bb, instr, instr_get_dst(instr, i), true);
    }

    /* insert code to call clean_call for processing the buffer */
    if (/* XXX i#1698: there are constraints for code between ldrex/strex pairs,
         * so we minimize the instrumentation in between by skipping the clean call.
         * As we're only inserting instrumentation on a memory reference, and the
         * app should be avoiding memory accesses in between the ldrex...strex,
         * the only problematic point should be before the strex.
         * However, there is still a chance that the instrumentation code may clear the
         * exclusive monitor state.
         * Using a fault to handle a full buffer should be more robust, and the
         * forthcoming buffer filling API (i#513) will provide that.
         */
        IF_AARCHXX_ELSE(!instr_is_exclusive_store(instr), true))
        dr_insert_clean_call(drcontext, bb, instr, (void *)clean_call, false, 0);

    return DR_EMIT_DEFAULT;
}
Example #21
0
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
                      bool for_trace, bool translating, void *user_data)
{
    uint num_instrs;
    /* By default drmgr enables auto-predication, which predicates all instructions with
     * the predicate of the current instruction on ARM.
     * We disable it here because we want to unconditionally execute the following
     * instrumentation.
     */
    drmgr_disable_auto_predication(drcontext, bb);
    if (!drmgr_is_first_instr(drcontext, instr))
        return DR_EMIT_DEFAULT;
    /* Only insert calls for in-app BBs */
    if (user_data == NULL)
        return DR_EMIT_DEFAULT;
    /* Insert clean call */
    num_instrs = (uint)(ptr_uint_t)user_data;
    dr_insert_clean_call(drcontext, bb, instrlist_first_app(bb), (void *)inscount,
                         false /* save fpstate */, 1, OPND_CREATE_INT32(num_instrs));
    return DR_EMIT_DEFAULT;
}
Example #22
0
static dr_emit_flags_t
bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;
    
    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);

        if (instr_is_cbr(instr)) {
            /* Conditional branch.  We can determine the target and
             * fallthrough addresses here, but we want to note the
             * edge if and when it actually executes at runtime.
             * Instead of using dr_insert_cbr_instrumentation(), we'll
             * insert separate instrumentation for the taken and not
             * taken cases and remove the instrumentation for an edge
             * after it executes.
             */
            cbr_state_t state;
            bool insert_taken, insert_not_taken;
            app_pc src = instr_get_app_pc(instr);
            
            /* First look up the state of this branch so we
             * know what instrumentation to insert, if any.
             */
            elem_t *elem = lookup(table, src);
            
            if (elem == NULL) {
                state = CBR_NEITHER;
                insert(table, src, CBR_NEITHER);
            }
            else {
                state = elem->state;
            }
            
            insert_taken = (state & CBR_TAKEN) == 0;
            insert_not_taken = (state & CBR_NOT_TAKEN) == 0;
            
            if (insert_taken || insert_not_taken) {
                app_pc fall = (app_pc)decode_next_pc(drcontext, (byte *)src);
                app_pc targ = instr_get_branch_target_pc(instr);
                
                /* Redirect the existing cbr to jump to a callout for
                 * the 'taken' case.  We'll insert a 'not-taken'
                 * callout at the fallthrough address.
                 */
                instr_t *label = INSTR_CREATE_label(drcontext);
                /* should be meta, and meta-instrs shouldn't have translations */
                instr_set_meta_no_translation(instr);
                /* it may not reach (in particular for x64) w/ our added clean call */
                if (instr_is_cti_short(instr)) {
                    /* if jecxz/loop we want to set the target of the long-taken
                     * so set instr to the return value
                     */
                    instr = instr_convert_short_meta_jmp_to_long(drcontext, bb, instr);
                }
                instr_set_target(instr, opnd_create_instr(label));
                
                if (insert_not_taken) {
                    /* Callout for the not-taken case.  Insert after
                     * the cbr (i.e., 3rd argument is NULL). 
                     */
                    dr_insert_clean_call(drcontext, bb, NULL, 
                                         (void*)at_not_taken,
                                         false /* don't save fp state */, 
                                         2 /* 2 args for at_not_taken */,
                                         OPND_CREATE_INTPTR(src),
                                         OPND_CREATE_INTPTR(fall));
                }
                
                /* After the callout, jump to the original fallthrough
                 * address.  Note that this is an exit cti, and should
                 * not be a meta-instruction.  Therefore, we use
                 * preinsert instead of meta_preinsert, and we must
                 * set the translation field.  On Windows, this jump
                 * and the final jump below never execute since the
                 * at_taken and at_not_taken callouts redirect
                 * execution and never return.  However, since the API
                 * expects clients to produced well-formed code, we
                 * insert explicit exits from the block for Windows as
                 * well as Linux.
                 */
                instrlist_preinsert(bb, NULL,
                                    INSTR_XL8(INSTR_CREATE_jmp
                                              (drcontext, opnd_create_pc(fall)), fall));
                
                /* label goes before the 'taken' callout */
                MINSERT(bb, NULL, label);
                
                if (insert_taken) {
                    /* Callout for the taken case */
                    dr_insert_clean_call(drcontext, bb, NULL,
                                         (void*)at_taken,
                                         false /* don't save fp state */,
                                         2 /* 2 args for at_taken */,
                                         OPND_CREATE_INTPTR(src),
                                         OPND_CREATE_INTPTR(targ));
                }
                
                /* After the callout, jump to the original target
                 * block (this should not be a meta-instruction).
                 */
                instrlist_preinsert(bb, NULL,
                                    INSTR_XL8(INSTR_CREATE_jmp
                                              (drcontext, opnd_create_pc(targ)), targ));
            }
        }
    }
    /* since our added instrumentation is not constant, we ask to store
     * translations now
     */
    return DR_EMIT_STORE_TRANSLATIONS;
}
Example #23
0
static void dynamic_info_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *where,
               instr_t * static_info)
{


	/* 
		issues that may arise
		1. pc and eflags is uint but in 64 bit mode 8 byte transfers are done -> so far no problem (need to see this)
			need to see whether there is a better way
		2. double check all the printing
	*/

	/*
		this function does the acutal instrumentation

		arguments - 

		we get a filled pointer here about the operand types for a given instruction (srcs and dests)
		1) increment the pointer to the instr_trace buffers
		2) add this pointer to instr_trace_t wrapper
		3) check whether any of the srcs and dests have memory operations; if so add a lea instruction and get the dynamic address
			Add this address to instr_trace_t structure
		4) if the buffer is full call a function to dump it to the file and restore the head ptr of the buffer 
			(lean function is used utilizing a code cache to limit code bloat needed for a clean call before every instruction.)
	*/

    instr_t *instr, *call, *restore, *first, *second;
    opnd_t   ref, opnd1, opnd2;
    reg_id_t reg1 = DR_REG_XBX; /* We can optimize it by picking dead reg */
    reg_id_t reg2 = DR_REG_XCX; /* reg2 must be ECX or RCX for jecxz */
	reg_id_t reg3 = DR_REG_XAX;
    per_thread_t *data;
    uint pc;
	uint i;

	module_data_t * module_data;

	if (client_arg->instrace_mode == DISASSEMBLY_TRACE){
		dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0);
		return;
	}

    data = drmgr_get_tls_field(drcontext, tls_index);

    /* Steal the register for memory reference address *
     * We can optimize away the unnecessary register save and restore
     * by analyzing the code and finding the register is dead.
     */

    dr_save_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2);
    dr_save_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3);
	dr_save_reg(drcontext, ilist, where, reg3, SPILL_SLOT_4);

	
	drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2);

    /* Load data->buf_ptr into reg2 */
    opnd1 = opnd_create_reg(reg2);
    opnd2 = OPND_CREATE_MEMPTR(reg2, offsetof(per_thread_t, buf_ptr));
    instr = INSTR_CREATE_mov_ld(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);


	/* buf_ptr->static_info_instr = static_info; */
    /* Move static_info to static_info_instr field of buf (which is a instr_trace_t *) */
    opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, static_info_instr));
	instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)static_info, opnd1, ilist, where, &first, &second);

	/* buf_ptr->num_mem = 0; */
    opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, num_mem));
    
	instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)0, opnd1, ilist, where, &first, &second);

	for (i = 0; i<instr_num_dsts(where); i++){
		if (opnd_is_memory_reference(instr_get_dst(where, i))){
			ref = instr_get_dst(where, i);

			DR_ASSERT(opnd_is_null(ref) == false);


			dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2);
			dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3);

#ifdef DEBUG_MEM_REGS
			dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0);
			dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0);
#endif
			
			drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg1, reg2);

#ifdef DEBUG_MEM_REGS
			dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0);
#endif

#ifdef DEBUG_MEM_STATS
			dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0);
			dr_insert_clean_call(drcontext, ilist, where, clean_call_mem_stats, false, 1, opnd_create_reg(reg1));
#endif

			dr_insert_clean_call(drcontext, ilist, where, clean_call_populate_mem, false, 3, opnd_create_reg(reg1), OPND_CREATE_INT32(i), OPND_CREATE_INT32(DST_TYPE));

		}
	}

	for (i = 0; i<instr_num_srcs(where); i++){
		if (opnd_is_memory_reference(instr_get_src(where, i))){
			ref = instr_get_src(where, i);

			DR_ASSERT(opnd_is_null(ref) == false);			
			
			dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2);
			dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3);

#ifdef DEBUG_MEM_REGS
			dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0);
			dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0);
#endif

			drutil_insert_get_mem_addr(drcontext, ilist, where, ref, reg1, reg2);

#ifdef DEBUG_MEM_REGS

			dr_insert_clean_call(drcontext, ilist, where, clean_call_print_regvalues, false, 0);
#endif

#ifdef DEBUG_MEM_STATS
			dr_insert_clean_call(drcontext, ilist, where, clean_call_disassembly_trace, false, 0);
			dr_insert_clean_call(drcontext, ilist, where, clean_call_mem_stats, false, 1, opnd_create_reg(reg1));
#endif

			dr_insert_clean_call(drcontext, ilist, where, clean_call_populate_mem, false, 3, opnd_create_reg(reg1), OPND_CREATE_INT32(i), OPND_CREATE_INT32(SRC_TYPE));

		}
	}
	

	

	drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg2);
    /* Load data->buf_ptr into reg2 */
    opnd1 = opnd_create_reg(reg2);
    opnd2 = OPND_CREATE_MEMPTR(reg2, offsetof(per_thread_t, buf_ptr));
    instr = INSTR_CREATE_mov_ld(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);

	/* arithmetic flags are saved here for buf_ptr->eflags filling */
	dr_save_arith_flags_to_xax(drcontext, ilist, where);

	/* load the eflags */
	opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, eflags));
	opnd2 = opnd_create_reg(reg3);
    instr = INSTR_CREATE_mov_st(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);


	/* load the app_pc */
	opnd1 = OPND_CREATE_MEMPTR(reg2, offsetof(instr_trace_t, pc));
	module_data = dr_lookup_module(instr_get_app_pc(where));

	//dynamically generated code - module information not available - then just store 0 at the pc slot of the instr_trace data
	if (module_data != NULL){
		pc = instr_get_app_pc(where) - module_data->start;
		dr_free_module_data(module_data);
	}
	else{
		pc = 0;
	}

	instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)pc, opnd1, ilist, where, &first, &second);



	/* buf_ptr++; */
    /* Increment reg value by pointer size using lea instr */
    opnd1 = opnd_create_reg(reg2);
    opnd2 = opnd_create_base_disp(reg2, DR_REG_NULL, 0,
                                  sizeof(instr_trace_t),
                                  OPSZ_lea);
    instr = INSTR_CREATE_lea(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);

    /* Update the data->buf_ptr */
    drmgr_insert_read_tls_field(drcontext, tls_index, ilist, where, reg1);
    opnd1 = OPND_CREATE_MEMPTR(reg1, offsetof(per_thread_t, buf_ptr));
    opnd2 = opnd_create_reg(reg2);
    instr = INSTR_CREATE_mov_st(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);

    /* we use lea + jecxz trick for better performance
     * lea and jecxz won't disturb the eflags, so we won't insert
     * code to save and restore application's eflags.
     */
    /* lea [reg2 - buf_end] => reg2 */
    opnd1 = opnd_create_reg(reg1);
    opnd2 = OPND_CREATE_MEMPTR(reg1, offsetof(per_thread_t, buf_end));
    instr = INSTR_CREATE_mov_ld(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);
    opnd1 = opnd_create_reg(reg2);
    opnd2 = opnd_create_base_disp(reg1, reg2, 1, 0, OPSZ_lea);
    instr = INSTR_CREATE_lea(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);

    /* jecxz call */
    call  = INSTR_CREATE_label(drcontext);
    opnd1 = opnd_create_instr(call);
    instr = INSTR_CREATE_jecxz(drcontext, opnd1);
    instrlist_meta_preinsert(ilist, where, instr);

    /* jump restore to skip clean call */
    restore = INSTR_CREATE_label(drcontext);
    opnd1 = opnd_create_instr(restore);
    instr = INSTR_CREATE_jmp(drcontext, opnd1);
    instrlist_meta_preinsert(ilist, where, instr);

    /* clean call */
    /* We jump to lean procedure which performs full context switch and
     * clean call invocation. This is to reduce the code cache size.
     */
    instrlist_meta_preinsert(ilist, where, call);
    /* mov restore DR_REG_XCX */
    opnd1 = opnd_create_reg(reg2);
    /* this is the return address for jumping back from lean procedure */
    opnd2 = opnd_create_instr(restore);
    /* We could use instrlist_insert_mov_instr_addr(), but with a register
     * destination we know we can use a 64-bit immediate.
     */
    instr = INSTR_CREATE_mov_imm(drcontext, opnd1, opnd2);
    instrlist_meta_preinsert(ilist, where, instr);
    /* jmp code_cache */
    opnd1 = opnd_create_pc(code_cache);
    instr = INSTR_CREATE_jmp(drcontext, opnd1);
    instrlist_meta_preinsert(ilist, where, instr);

    /* restore %reg */
    instrlist_meta_preinsert(ilist, where, restore);

	//dr_restore_arith_flags_from_xax(drcontext, ilist, where);
    dr_restore_reg(drcontext, ilist, where, reg1, SPILL_SLOT_2);
    dr_restore_reg(drcontext, ilist, where, reg2, SPILL_SLOT_3);
	dr_restore_reg(drcontext, ilist, where, reg3, SPILL_SLOT_4);

	//instrlist_disassemble(drcontext, instr_get_app_pc(instrlist_first(ilist)), ilist, logfile);

}
Example #24
0
/*
 * The main function called to instrument each machine instruction.
 */
static dr_emit_flags_t instrument_instr(
    void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
    bool for_trace, bool translating, void *user_data)
{
    char *loc = NULL;

    /*
     * If this instruction is the first in its basic block, call
     * log_pc to record that we're executing this block at all.
     */
    if (drmgr_is_first_instr(drcontext, instr)) {
        instr_format_location(instr, &loc);
        dr_insert_clean_call(
            drcontext, bb, instr, (void *)log_pc, false,
            1, OPND_CREATE_INTPTR(loc));
    }

    /*
     * If the instruction reads or writes memory, log its access.
     */
    if (instr_reads_memory(instr) || instr_writes_memory(instr)) {
        for (int i = 0, limit = instr_num_srcs(instr); i < limit; i++)
            try_mem_opnd(drcontext, bb, instr, &loc,
                         instr_get_src(instr, i), false);
        for (int i = 0, limit = instr_num_dsts(instr); i < limit; i++)
            try_mem_opnd(drcontext, bb, instr, &loc,
                         instr_get_dst(instr, i), false);
    }

    /*
     * Now do opcode-specific checks.
     */
    int opcode = instr_get_opcode(instr);

    switch (opcode) {
      case OP_div:
      case OP_idiv:
        /*
         * x86 hardware divisions. The operand order for DR's
         * representation of these seem to be: 0 = denominator, 1 =
         * numerator MSW, 2 = numerator LSW.
         */
        instr_format_location(instr, &loc);
        dr_insert_clean_call(
            drcontext, bb, instr, (void *)log_div, false,
            3, instr_get_src(instr, 2), instr_get_src(instr, 0),
            OPND_CREATE_INTPTR(loc));
        break;
      case OP_shl:
      case OP_shr:
      case OP_sar:
      case OP_shlx:
      case OP_shrx:
      case OP_sarx:
      case OP_rol:
      case OP_ror:
      case OP_rcl:
      case OP_rcr:
        /*
         * Shift instructions. If they're register-controlled, log the
         * shift count.
         */
        {
            opnd_t shiftcount = instr_get_src(instr, 0);
            if (!opnd_is_immed(shiftcount)) {
                reg_id_t r0;
                drreg_status_t st;
                st = drreg_reserve_register(drcontext, bb, instr, NULL, &r0);
                DR_ASSERT(st == DRREG_SUCCESS);
                opnd_t op_r0 = opnd_create_reg(r0);
                instrlist_preinsert(bb, instr, INSTR_CREATE_movzx(
                                        drcontext, op_r0, shiftcount));
                instr_format_location(instr, &loc);
                dr_insert_clean_call(
                    drcontext, bb, instr, (void *)log_var_shift, false,
                    2, op_r0, OPND_CREATE_INTPTR(loc));
                st = drreg_unreserve_register(drcontext, bb, instr, r0);
                DR_ASSERT(st == DRREG_SUCCESS);
            }
        }
        break;
    }

    return DR_EMIT_DEFAULT;
}
Example #25
0
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
                      bool for_trace, bool translating, void *user_data)
{
    reg_id_t reg_ptr = IF_X86_ELSE(DR_REG_XDX, TEST_REG);
    reg_id_t reg_tmp = IF_X86_ELSE(DR_REG_XCX, DR_REG_R3);
    /* We need a third register on ARM, because updating the buf pointer
     * requires a second scratch reg.
     */
    reg_id_t scratch = IF_X86_ELSE(reg_tmp, DR_REG_R5);
    ptr_int_t subtest = (ptr_int_t) user_data;

    if (!instr_is_label(inst))
        return DR_EMIT_DEFAULT;

#ifdef X86
    scratch = reg_resize_to_opsz(scratch, OPSZ_4);
#endif
    if (subtest == DRX_BUF_TEST_1_C) {
        /* testing fast circular buffer */
        /* test to make sure that on first invocation, the buffer is empty */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1,
                             OPND_CREATE_INTPTR(circular_fast));

        /* load the buf pointer, and then write a garbage element to the buffer */
        drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0);
        drx_buf_insert_update_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr,
                                      reg_tmp, sizeof(int));

        /* verify the buffer was written to */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_dirty, false, 2,
                             OPND_CREATE_INTPTR(circular_fast),
                             opnd_create_reg(scratch));

        /* fast circular buffer: trigger an overflow */
        drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr);
        drx_buf_insert_update_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr,
                                      reg_tmp, CIRCULAR_FAST_SZ - sizeof(int));

        /* the buffer is now clean */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1,
                             OPND_CREATE_INTPTR(circular_fast));
    } else if (subtest == DRX_BUF_TEST_2_C) {
        /* testing slow circular buffer */
        /* test to make sure that on first invocation, the buffer is empty */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1,
                             OPND_CREATE_INTPTR(circular_slow));

        /* load the buf pointer, and then write an element to the buffer */
        drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0);
        drx_buf_insert_update_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr,
                                      DR_REG_NULL, sizeof(int));

        /* verify the buffer was written to */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_dirty, false, 2,
                             OPND_CREATE_INTPTR(circular_slow),
                             opnd_create_reg(scratch));

        /* slow circular buffer: trigger a fault */
        drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr);
        drx_buf_insert_update_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr,
                                      DR_REG_NULL, CIRCULAR_SLOW_SZ - sizeof(int));
        /* the "trigger" is a write, so we write whatever garbage is in reg_tmp */
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0);

        /* the buffer is now clean */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1,
                             OPND_CREATE_INTPTR(circular_slow));
    } else if (subtest == DRX_BUF_TEST_3_C) {
        /* testing trace buffer */
        /* test to make sure that on first invocation, the buffer is empty */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1,
                             OPND_CREATE_INTPTR(trace));

        /* load the buf pointer, and then write an element to the buffer */
        drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0);
        drx_buf_insert_update_buf_ptr(drcontext, trace, bb, inst, reg_ptr,
                                      DR_REG_NULL, sizeof(int));

        /* verify the buffer was written to */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_dirty, false, 2,
                             OPND_CREATE_INTPTR(trace),
                             opnd_create_reg(scratch));

        /* trace buffer: trigger a fault and verify */
        drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr);
        drx_buf_insert_update_buf_ptr(drcontext, trace, bb, inst, reg_ptr,
                                      DR_REG_NULL, TRACE_SZ - sizeof(int));
        /* the "trigger" is a write, so we write whatever garbage is in reg_tmp */
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch), OPSZ_4, 0);

        /* the buffer is now clean */
        dr_insert_clean_call(drcontext, bb, inst, verify_buffers_empty, false, 1,
                             OPND_CREATE_INTPTR(trace));
    } else if (subtest == DRX_BUF_TEST_4_C) {
        /* test immediate store: 8 bytes (if possible), 4 bytes, 2 bytes and 1 byte */
        /* "ABCDEFGH\x00" (x2 for x64) */
        drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x41, OPSZ_1),
                                 OPSZ_1, 0);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x42, OPSZ_1),
                                 OPSZ_1, 1);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x4443, OPSZ_2),
                                 OPSZ_2, 2);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x48474645, OPSZ_4),
                                 OPSZ_4, 4);
#ifdef X64
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x4847464544434241,
                                                                  OPSZ_8),
                                 OPSZ_8, 8);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x00, OPSZ_1),
                                 OPSZ_1, 17);
#else
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x00, OPSZ_1),
                                 OPSZ_1, 9);
#endif
        dr_insert_clean_call(drcontext, bb, inst, verify_store, false, 1,
                             OPND_CREATE_INTPTR(circular_fast));
    } else if (subtest == DRX_BUF_TEST_5_C) {
        /* test register store: 8 bytes (if possible), 4 bytes, 2 bytes and 1 byte */
        /* "ABCDEFGH\x00" (x2 for x64) */
        drx_buf_insert_load_buf_ptr(drcontext, circular_fast, bb, inst, reg_ptr);
        scratch = reg_resize_to_opsz(scratch, OPSZ_1);
        MINSERT(bb, inst, XINST_CREATE_load_int
                (drcontext,
                 opnd_create_reg(scratch),
                 opnd_create_immed_int(0x41, OPSZ_1)));
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch),
                                 OPSZ_1, 0);
        MINSERT(bb, inst, XINST_CREATE_load_int
                (drcontext,
                 opnd_create_reg(scratch),
                 opnd_create_immed_int(0x42, OPSZ_1)));
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch),
                                 OPSZ_1, 1);
        scratch = reg_resize_to_opsz(scratch, OPSZ_2);
        MINSERT(bb, inst, XINST_CREATE_load_int
                (drcontext,
                 opnd_create_reg(scratch),
                 opnd_create_immed_int(0x4443, OPSZ_2)));
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch),
                                 OPSZ_2, 2);
        scratch = reg_resize_to_opsz(scratch, OPSZ_4);
#ifdef X86
        MINSERT(bb, inst, XINST_CREATE_load_int
                (drcontext,
                 opnd_create_reg(scratch),
                 opnd_create_immed_int(0x48474645, OPSZ_4)));
#else
        instrlist_insert_mov_immed_ptrsz(drcontext, 0x48474645,
                                         opnd_create_reg(reg_resize_to_opsz
                                                         (scratch, OPSZ_PTR)),
                                         bb, inst, NULL, NULL);
#endif
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch),
                                 OPSZ_4, 4);
#ifdef X64
        scratch = reg_resize_to_opsz(scratch, OPSZ_8);
        /* only way to reliably move a 64 bit int into a register */
        instrlist_insert_mov_immed_ptrsz(drcontext, 0x4847464544434241,
                                         opnd_create_reg(scratch),
                                         bb, inst, NULL, NULL);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 DR_REG_NULL, opnd_create_reg(scratch),
                                 OPSZ_8, 8);
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x00, OPSZ_1),
                                 OPSZ_1, 17);
#else
        drx_buf_insert_buf_store(drcontext, circular_fast, bb, inst, reg_ptr,
                                 scratch, opnd_create_immed_int(0x00, OPSZ_1),
                                 OPSZ_1, 9);
#endif
        dr_insert_clean_call(drcontext, bb, inst, verify_store, false, 1,
                             OPND_CREATE_INTPTR(circular_fast));
    } else if (subtest == DRX_BUF_TEST_6_C) {
        /* Currently, the fast circular buffer does not recommend variable-size
         * writes, for good reason. We don't test the memcpy operation on the
         * fast circular buffer.
         */
        /* verify memcpy works on the slow clrcular buffer */
        drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr);
        instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_copy,
                                         opnd_create_reg(reg_resize_to_opsz
                                                         (scratch, OPSZ_PTR)),
                                         bb, inst, NULL, NULL);
        drx_buf_insert_buf_memcpy(drcontext, circular_slow, bb, inst,
                                  reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR),
                                  sizeof(test_copy));
        /* NULL out the buffer */
        drx_buf_insert_load_buf_ptr(drcontext, circular_slow, bb, inst, reg_ptr);
        instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_null,
                                         opnd_create_reg(reg_resize_to_opsz
                                                         (scratch, OPSZ_PTR)),
                                         bb, inst, NULL, NULL);
        drx_buf_insert_buf_memcpy(drcontext, circular_slow, bb, inst,
                                  reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR),
                                  sizeof(test_null));
        /* Unfortunately, we can't just use the check in verify_buffer_empty, because
         * drx_buf_insert_buf_memcpy() incrememnts the buffer pointer internally, unlike
         * drx_buf_insert_buf_store(). We simply check that the buffer was NULLed out.
         */
        dr_insert_clean_call(drcontext, bb, inst, (void *)verify_buffers_nulled, false, 1,
                             OPND_CREATE_INTPTR(circular_slow));
        /* verify memcpy works on the trace buffer */
        drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr);
        instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_copy,
                                         opnd_create_reg(reg_resize_to_opsz
                                                         (scratch, OPSZ_PTR)),
                                         bb, inst, NULL, NULL);
        drx_buf_insert_buf_memcpy(drcontext, trace, bb, inst,
                                  reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR),
                                  sizeof(test_copy));
        /* NULL out the buffer */
        drx_buf_insert_load_buf_ptr(drcontext, trace, bb, inst, reg_ptr);
        instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)test_null,
                                         opnd_create_reg(reg_resize_to_opsz
                                                         (scratch, OPSZ_PTR)),
                                         bb, inst, NULL, NULL);
        drx_buf_insert_buf_memcpy(drcontext, trace, bb, inst,
                                  reg_ptr, reg_resize_to_opsz(scratch, OPSZ_PTR),
                                  sizeof(test_null));
        /* verify buffer was NULLed */
        dr_insert_clean_call(drcontext, bb, inst, (void *)verify_buffers_nulled, false, 1,
                             OPND_CREATE_INTPTR(trace));
    }

    return DR_EMIT_DEFAULT;
}
Example #26
0
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;
}
Example #27
0
dr_emit_flags_t
bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
    instr_t *instr, *next_instr;

    app_pc bb_addr = dr_fragment_app_pc(tag);
    if (bb_addr == start_pc) {
        instrument = true;
    } else if (bb_addr == stop_pc) {
        instrument = false;
    }

    if (!instrument) {
        return DR_EMIT_DEFAULT;
    }

    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
        next_instr = instr_get_next(instr);

        /*
         * Conditional branch. We can determine the target and
         * fallthrough addresses here, but we need to instrument if we
         * want to record the edge only if it actually executes at
         * runtime. Instead of using dr_insert_cbr_instrumentation,
         * we'll insert separate instrumentation for the taken and not
         * taken cases and remove it separately after we see each
         * case.
         */
        if (instr_is_cbr(instr)) {
            app_pc src = instr_get_app_pc(instr);

            cbr_state_t state;
            bool insert_taken, insert_not_taken;

            /* First look up the state of this branch so we
             * know what instrumentation to insert, if any.
             */
            elem_t *elem = lookup(table, src);

            if (elem == NULL) {
                state = CBR_NONE;
                insert(table, src, CBR_NONE);
            } else {
                state = elem->state;
            }

            insert_taken = (state & CBR_TAKEN) == 0;
            insert_not_taken = (state & CBR_NOT_TAKEN) == 0;

            if (insert_taken || insert_not_taken) {
                app_pc fall = (app_pc)decode_next_pc(drcontext, (byte *)src);
                app_pc targ = instr_get_branch_target_pc(instr);

                /*
                 * Redirect the cbr to jump to the 'taken' callout.
                 * We'll insert a 'not-taken' callout at fallthrough
                 * address.
                 */
                instr_t *label = INSTR_CREATE_label(drcontext);
                instr_set_meta(instr);
                instr_set_translation(instr, NULL);
                /* If this is a short cti, make sure it can reach its new target */
                if (instr_is_cti_short(instr)) {
                    /* if jecxz/loop we want to set the target of the long-taken
                     * so set instr to the return value
                     */
                    instr = instr_convert_short_meta_jmp_to_long(drcontext, bb, instr);
                }
                instr_set_target(instr, opnd_create_instr(label));

                if (insert_not_taken) {
                    /*
                     * Callout for the not-taken case
                     */
                    dr_insert_clean_call(drcontext, bb, NULL, (void *)at_not_taken,
                                         false /* don't save fp state */,
                                         2 /* 2 args for at_not_taken */,
                                         OPND_CREATE_INTPTR((ptr_uint_t)src),
                                         OPND_CREATE_INTPTR((ptr_uint_t)fall));
                }

                /*
                 * Jump to the original fall-through address.
                 * (This should not be a meta-instruction).
                 */
                instrlist_preinsert(
                    bb, NULL,
                    INSTR_XL8(INSTR_CREATE_jmp(drcontext, opnd_create_pc(fall)), fall));

                /* label goes before the 'taken' callout */
                MINSERT(bb, NULL, label);

                if (insert_taken) {
                    /*
                     * Callout for the taken case
                     */
                    dr_insert_clean_call(drcontext, bb, NULL, (void *)at_taken,
                                         false /* don't save fp state */,
                                         2 /* 2 args for at_taken */,
                                         OPND_CREATE_INTPTR((ptr_uint_t)src),
                                         OPND_CREATE_INTPTR((ptr_uint_t)targ));
                }

                /*
                 * Jump to the original target block (this should
                 * not be a meta-instruction).
                 */
                instrlist_preinsert(
                    bb, NULL,
                    INSTR_XL8(INSTR_CREATE_jmp(drcontext, opnd_create_pc(targ)), targ));
            }
        }
    }
    /* since our added instrumentation is not constant, we ask to store
     * translations now
     */
    return DR_EMIT_STORE_TRANSLATIONS;
}