Example #1
0
static void
kernel_xfer_event(void *drcontext, const dr_kernel_xfer_info_t *info)
{
    /* Test kernel xfer on dr_redirect_execution */
    dr_fprintf(STDERR, "%s: type %d\n", __FUNCTION__, info->type);
    ASSERT(info->source_mcontext != NULL);
    dr_mcontext_t mc = {sizeof(mc)};
    mc.flags = DR_MC_CONTROL;
    bool ok = dr_get_mcontext(drcontext, &mc);
    ASSERT(ok);
    ASSERT(mc.pc == info->target_pc);
    ASSERT(mc.xsp == info->target_xsp);
    mc.flags = DR_MC_ALL;
    ok = dr_get_mcontext(drcontext, &mc);
    ASSERT(ok);
}
Example #2
0
static void
at_not_taken(app_pc src, app_pc fall)
{
    dr_mcontext_t mcontext = {
        sizeof(mcontext),
        DR_MC_ALL,
    };
    void *drcontext = dr_get_current_drcontext();

    /*
     * Record the fact that we've seen the fallthrough case.
     */
    elem_t *elem = lookup(table, src);
    ASSERT(elem != NULL);
    elem->state |= CBR_NOT_TAKEN;

    dr_fprintf(STDERR, "cbr not taken\n");

    /*
     * Remove the bb from the cache so it will be re-built the next
     * time it is executed.  Since the flush will remove the fragment
     * we're already in, redirect execution to the target.
     */
    dr_flush_region(src, 1);
    dr_get_mcontext(drcontext, &mcontext);
    mcontext.pc = fall;
    dr_redirect_execution(&mcontext);
}
Example #3
0
void memory_write(void *pc, void *prev_pc)
{
  void		*drcontext = dr_get_current_drcontext();
  instr_t	*instr = instr_create(drcontext);
  dr_mcontext_t mctx;
  opnd_t	dst;
  ctx_t		ctx;
  
  pc = dr_app_pc_for_decoding(pc);

  mctx.flags = DR_MC_CONTROL|DR_MC_INTEGER;
  mctx.size = sizeof(mctx);
  dr_get_mcontext(drcontext, &mctx);

  instr_init(drcontext, instr);
  if (!decode(drcontext, pc, instr))
    {
      dr_printf("Decode of instruction at %p failed\n", pc);
      return;
    }

  ctx.addr = prev_pc;
  ctx.dr_addr = prev_pc;

  for (int i = 0; i < instr_num_dsts(instr); i++)
    {
      dst = instr_get_dst(instr, i);
      check_opnd(dst, pc, 0, drcontext, &mctx, &ctx);
    }

  instr_destroy(drcontext, instr);
}
Example #4
0
static
void callback(void *tag, app_pc next_pc)
{
    callback_count++;

    /* Flush all fragments containing this tag twice every hundred calls alternating
     * between a sync_all and delay flush (if available) and an unlink and delay flush
     * (if available). */
    if (callback_count % 100 == 0) {
        if (callback_count % 200 == 0) {
            /* For windows test dr_flush_region() half the time */
            dr_mcontext_t mcontext = {sizeof(mcontext),DR_MC_ALL,};

            dr_delay_flush_region((app_pc)tag - 20, 30, callback_count, flush_event);
            dr_get_mcontext(dr_get_current_drcontext(), &mcontext);
            mcontext.pc = next_pc;
            dr_flush_region(tag, 1);
            dr_redirect_execution(&mcontext);
            *(volatile uint *)NULL = 0; /* ASSERT_NOT_REACHED() */
        } else if (use_unlink) {
            /* Test dr_unlink_flush_region() half the time (if available).
             * FIXME - extend once we add unlink callback. */
            delay_flush_at_next_build = true;
            dr_unlink_flush_region(tag, 1);
        }
    }
}
Example #5
0
static void at_taken(app_pc src, app_pc targ)
{
    int app_errno;
    dr_mcontext_t mcontext;
    void *drcontext = dr_get_current_drcontext();

    /* 
     * Record the fact that we've seen the taken case.
     */
    elem_t *elem = lookup(table, src);
    ASSERT(elem != NULL);
    elem->state |= CBR_TAKEN;

    dr_fprintf(STDERR, "cbr taken\n");

    /* 
     * Remove the bb from the cache so it will be re-built the next
     * time it is executed.  Since the flush will remove the fragment
     * we're already in, redirect execution to the target.
     */
    dr_flush_region(src, 1);
    dr_get_mcontext(drcontext, &mcontext, &app_errno);
    mcontext.xip = targ;
    dr_redirect_execution(&mcontext, app_errno);
}
Example #6
0
static void
at_syscall()
{
    if (monitoring) {
        dr_mcontext_t mcontext = {sizeof(mcontext),DR_MC_ALL,};
        void *drcontext = dr_get_current_drcontext();
        dr_get_mcontext(drcontext, &mcontext);
        dr_fprintf(STDERR, PFX"\n", mcontext.xax);
    }
}
Example #7
0
static void
event_post_syscall(void *drcontext, int sysnum)
{
#ifdef SHOW_RESULTS
    dr_syscall_result_info_t info = { sizeof(info), };
    dr_syscall_get_result_ex(drcontext, &info);
    if (!info.succeeded) {
        /* XXX: we could use the "drsyscall" Extension from the Dr. Memory
         * Framework (DRMF) to obtain the name of the system call (as well as
         * the number of arguments and the type of each).  Please see the strace
         * sample and drstrace tool within DRMF for further information.
         */
        dr_fprintf(STDERR, "<---- syscall %d failed (returned "PFX" == "SZFMT") ---->\n",
                   sysnum, info.value, (ptr_int_t)info.value);
    }
#endif
    if (sysnum == write_sysnum) {
        per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx);
        /* we repeat a write originally to stdout that we redirected to
         * stderr: on the repeat we use stdout
         */
        if (data->repeat) {
            /* repeat syscall with stdout */
            int i;
#ifdef SHOW_RESULTS
            dr_fprintf(STDERR, "<---- repeating write ---->\n");
#endif
            dr_syscall_set_sysnum(drcontext, write_sysnum);
            dr_syscall_set_param(drcontext, 0, (reg_t) STDOUT);
            for (i = 1; i < SYS_MAX_ARGS; i++)
                dr_syscall_set_param(drcontext, i, data->param[i]);
#ifdef WINDOWS
            if (dr_is_wow64()) {
                /* Set the xcx emulation parameter for wow64: since
                 * we're executing the same system call again we can
                 * use that same parameter.  For new system calls we'd
                 * need to determine the parameter from the ntdll
                 * wrapper.
                 */
                dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/};
                dr_get_mcontext(drcontext, &mc);
                mc.xcx = data->xcx;
                dr_set_mcontext(drcontext, &mc);
            }
#endif
            dr_syscall_invoke_another(drcontext);
        }
    }
}
Example #8
0
static void
at_call(app_pc instr_addr, app_pc target_addr)
{
    file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(dr_get_current_drcontext());
    dr_mcontext_t mc = {sizeof(mc),DR_MC_CONTROL/*only need xsp*/};
    dr_get_mcontext(dr_get_current_drcontext(), &mc);
#ifdef SHOW_SYMBOLS
    print_address(f, instr_addr, "CALL @ ");
    print_address(f, target_addr, "\t to ");
    dr_fprintf(f, "\tTOS is "PFX"\n", mc.xsp);
#else
    dr_fprintf(f, "CALL @ "PFX" to "PFX", TOS is "PFX"\n",
               instr_addr, target_addr, mc.xsp);
#endif
}
Example #9
0
static void clean_call_print_regvalues(){

	uint regvalue;
	dr_mcontext_t mc = { sizeof(mc), DR_MC_ALL };
	void * drcontext = dr_get_current_drcontext();

	dr_get_mcontext(drcontext, &mc);
	dr_printf("---------\n");
	regvalue = reg_get_value(DR_REG_XAX, &mc);
	dr_printf("xax - %x\n", regvalue);
	regvalue = reg_get_value(DR_REG_XBX, &mc);
	dr_printf("xbx - %x\n", regvalue);
	regvalue = reg_get_value(DR_REG_XCX, &mc);
	dr_printf("xcx - %x\n", regvalue);
	regvalue = reg_get_value(DR_REG_XDX, &mc);
	dr_printf("xdx - %x\n", regvalue);

}
Example #10
0
static void clean_call(uint pc){

	//DEBUG_PRINT("funcwrap - entered the pre-call clean call\n");
	
	dr_mcontext_t mc = { sizeof(mc), DR_MC_ALL };
	dr_get_mcontext(dr_get_current_drcontext(), &mc);
	mc.pc = pc;
	if (dumped == 0){
		dumped = 1;
		dr_flush_region(0, ~((ptr_uint_t)0));
		dr_redirect_execution(&mc);
	}
	
	//DEBUG_PRINT("funcwrap - entered the pre-call done\n");

	
	

}
Example #11
0
static void
event_post_syscall(void *drcontext, int sysnum)
{
#ifdef SHOW_RESULTS
    dr_fprintf(STDERR, "  [%d] => "PFX" ("SZFMT")\n",
               sysnum, 
               dr_syscall_get_result(drcontext),
               (ptr_int_t)dr_syscall_get_result(drcontext));
#endif
    if (sysnum == write_sysnum) {
        per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx);
        /* we repeat a write originally to stdout that we redirected to
         * stderr: on the repeat we use stdout
         */
        if (data->repeat) {
            /* repeat syscall with stdout */
            int i;
#ifdef SHOW_RESULTS
            dr_fprintf(STDERR, "  [%d] => repeating\n", sysnum);
#endif
            dr_syscall_set_sysnum(drcontext, write_sysnum);
            dr_syscall_set_param(drcontext, 0, (reg_t) STDOUT);
            for (i = 1; i < SYS_MAX_ARGS; i++) 
                dr_syscall_set_param(drcontext, i, data->param[i]);
#ifdef WINDOWS
            if (dr_is_wow64()) {
                /* Set the xcx emulation parameter for wow64: since
                 * we're executing the same system call again we can
                 * use that same parameter.  For new system calls we'd
                 * need to determine the parameter from the ntdll
                 * wrapper.
                 */
                dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/};
                dr_get_mcontext(drcontext, &mc);
                mc.xcx = data->xcx;
                dr_set_mcontext(drcontext, &mc);
            }
#endif
            dr_syscall_invoke_another(drcontext);
        }
    }
}
Example #12
0
static void
check_mcontext(void *drcontext)
{
    dr_mcontext_t *mc;
    dr_mcontext_t mc_DR;

    if (drsys_get_mcontext(drcontext, &mc) != DRMF_SUCCESS)
        ASSERT(false, "drsys_get_mcontext failed");
    mc_DR.size = sizeof(mc_DR);
    mc_DR.flags = DR_MC_INTEGER|DR_MC_CONTROL;
    dr_get_mcontext(drcontext, &mc_DR);
    ASSERT(mc->IF_ARM_ELSE(r7,xdi) == mc_DR.IF_ARM_ELSE(r7,xdi), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r6,xsi) == mc_DR.IF_ARM_ELSE(r6,xsi), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r5,xbp) == mc_DR.IF_ARM_ELSE(r5,xbp), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r4,xsp) == mc_DR.IF_ARM_ELSE(r4,xsp), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r3,xbx) == mc_DR.IF_ARM_ELSE(r3,xbx), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r2,xdx) == mc_DR.IF_ARM_ELSE(r2,xdx), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r1,xcx) == mc_DR.IF_ARM_ELSE(r1,xcx), "mc check");
    ASSERT(mc->IF_ARM_ELSE(r0,xax) == mc_DR.IF_ARM_ELSE(r0,xax), "mc check");
    ASSERT(mc->xflags == mc_DR.xflags, "mc check");
}
Example #13
0
/* Clean call for the 'taken' case */
static void at_taken(app_pc src, app_pc targ)
{
    dr_mcontext_t mcontext = {sizeof(mcontext),DR_MC_ALL,};
    void *drcontext = dr_get_current_drcontext();

    /* 
     * Record the fact that we've seen the taken case.
     */
    elem_t *elem = lookup(table, src);
    ASSERT(elem != NULL);
    elem->state |= CBR_TAKEN;

    /* Remove the bb from the cache so it will be re-built the next
     * time it executes.
     */
    /* Since the flush will remove the fragment we're already in,
     * redirect execution to the target address.
     */
    dr_flush_region(src, 1);
    dr_get_mcontext(drcontext, &mcontext);
    mcontext.pc = targ;
    dr_redirect_execution(&mcontext);
}
Example #14
0
static void 
getRegReg(reg_id_t r1, reg_id_t r2, int opcode, app_pc addr){
	
	const char * r1Name = get_register_name(r1);
	const char * r2Name = get_register_name(r2);
	int s1        = atoi(r1Name + 3 * sizeof(char));
	int s2        = atoi(r2Name + 3 * sizeof(char));
	dr_mcontext_t mcontext;
   	memset(&mcontext, 0, sizeof(dr_mcontext_t));
   	mcontext.flags = DR_MC_MULTIMEDIA;
   	mcontext.size = sizeof(dr_mcontext_t);
   	bool result = dr_get_mcontext(dr_get_current_drcontext(), &mcontext);
	int r, s;
	int bits = 0;
	double loss = 0;
	double lossD = 0;
	if(is_single_precision_instr(opcode)){
		float op1, op2;
//		for(r=0; r<16; ++r)
//			for(s=0; s<4; ++s)
//		     		printf("reg %i.%i: %f\n", r, s, 
//					*((float*) &mcontext.ymm[r].u32[s]));
		op1 = *((float*) &mcontext.ymm[s1].u32[0]);
		op2 = *((float*) &mcontext.ymm[s2].u32[0]);
       //		dr_fprintf(logF, "%d: %f  %f\n",opcode, op1, op2);
		int exp1, exp2;
		float mant1, mant2;
		mant1 = frexpf(op1, &exp1);
		mant2 = frexpf(op2, &exp2);
		bits = abs(exp1-exp2);

		double dop1 = op1;
		double dop2 = op2;

		if(opcode == OP_addss){
			double dadd = dop1 + dop2;
			float fadd = op1 + op2;
			lossD = dadd - fadd;
//		printf("double %.13lf float %.13f\n", dadd, fadd);
		}
		else{
			double dsub = dop1 - dop2;
			float fsub = op1 - op2;	
			lossD = dsub - fsub;
		}

//		printf("diff of double and float is %.13lf\n", lossD);
	}
	else{
		double op1, op2;
//		for(r=0; r<16; ++r)
//    			for(s=0; s<2; ++s)
//	     			printf("reg %i.%i: %f\n", r, s, 
//					*((double*) &mcontext.ymm[r].u64[s]));
		op1 = *((double*) &mcontext.ymm[s1].u64[0]);
		op2 = *((double*) &mcontext.ymm[s2].u64[0]);
      // 		dr_fprintf(logF, "%d: %.13lf  %.13lf\n",opcode, op1, op2);
		int exp1, exp2;
		double mant1, mant2;
		mant1 = frexp(op1, &exp1);
		mant2 = frexp(op2, &exp2);
		bits = abs(exp1-exp2);
		printf("op1 %.13lf mantissa %.13lf exp %d\n", op1, mant1, exp1);
		printf("op2 %.13lf mantissa %.13lf exp %d\n", op2, mant2, exp2);
	}
	print_address(addr, bits, loss, lossD);
}
Example #15
0
static void
callback(reg_id_t reg, int displacement, reg_id_t destReg, int opcode, app_pc addr){
	int r, s;
   	const char * destRegName = get_register_name(destReg);
   	int regId = atoi(destRegName + 3 * sizeof(char));
   	dr_mcontext_t mcontext;
   	memset(&mcontext, 0, sizeof(dr_mcontext_t));
   	mcontext.flags = DR_MC_ALL;
   	mcontext.size = sizeof(dr_mcontext_t);
   	bool result = dr_get_mcontext(dr_get_current_drcontext(), &mcontext);

	reg_t mem_reg;
	if(reg == DR_REG_RAX)
		mem_reg = mcontext.rax;
	else if(reg == DR_REG_RBP)
		mem_reg = mcontext.rbp;
	else if(reg == DR_REG_RBX)
		mem_reg = mcontext.rbx;
	else if(reg == DR_REG_RCX)
		mem_reg = mcontext.rcx;
	else if(reg == DR_REG_RDI)
		mem_reg = mcontext.rdi;
	else if(reg == DR_REG_RDX)
		mem_reg = mcontext.rdx;
	else if(reg == DR_REG_RSI)
		mem_reg = mcontext.rsi;
	else if(reg == DR_REG_RSP)
		mem_reg = mcontext.rsp;
	else
		mem_reg = NULL;
//deal with a null case, rip enum doesn't exist

	int bits = 0;
	double loss = 0;
	double lossD = 0;
	if(is_single_precision_instr(opcode)){
   		float op1, op2;
//   		printf("Mem reg contents: %f\n", *(float*)(mem_reg + displacement));
   		op2 = *(float*)(mem_reg + displacement);
//		for(r=0; r<16; ++r)
//			for(s=0; s<4; ++s)
//		     		printf("reg %i.%i: %f\n", r, s, 
//					*((float*) &mcontext.ymm[r].u32[s]));
		op1 = *((float*) &mcontext.ymm[regId].u32[0]);
  // 		dr_fprintf(logF, "%d: %f  %f\n",opcode, op1, op2);
		int exp1, exp2;
		float mant1, mant2;
		mant1 = frexpf(op1, &exp1);
		mant2 = frexpf(op2, &exp2);
		bits = abs(exp1-exp2);
		double dop1 = op1;
		double dop2 = op2;
		if(opcode == OP_addss){
			double dadd = dop1 + dop2;
			float fadd = op1 + op2;
			lossD = dadd - fadd;
		//printf("double %.13lf float %.13f\n", dadd, fadd);
		}
		else{
			double dsub = dop1 - dop2;
			float fsub = op1 - op2;	
			lossD = dsub - fsub;
		}
//		printf("diff of double and float is %.13lf\n", lossD);
	}
	else{
		double op1, op2;
   		printf("Mem reg contents: %.13lf\n", *(double*)(mem_reg + displacement));
   		op2 = *(double*)(mem_reg + displacement);
//		for(r=0; r<16; ++r)
 //   			for(s=0; s<2; ++s)
//	     			printf("reg %i.%i: %lf\n", r, s, 
//					*((double*) &mcontext.ymm[r].u64[s]));
		op1 = *((double*) &mcontext.ymm[regId].u64[0]);
  // 		dr_fprintf(logF, "%d: %.13lf  %.13lf\n",opcode, op1, op2);
		int exp1, exp2;
		double mant1, mant2;
		mant1 = frexp(op1, &exp1);
		mant2 = frexp(op2, &exp2);
		bits = abs(exp1-exp2);
		printf("op1 %.13lf mantissa %.13lf exp %d\n", op1, mant1, exp1);
		printf("op2 %.13lf mantissa %.13lf exp %d\n", op2, mant2, exp2);
	}
	print_address(addr, bits, loss, lossD);
}
Example #16
0
static bool
event_pre_syscall(void *drcontext, int sysnum)
{
    ATOMIC_INC(num_syscalls);
#ifdef LINUX
    if (sysnum == SYS_execve) {
        /* our stats will be re-set post-execve so display now */
        show_results();
# ifdef SHOW_RESULTS
        dr_fprintf(STDERR, "<---- execve ---->\n");
# endif
    }
#endif
#ifdef SHOW_RESULTS
    dr_fprintf(STDERR, "[%d] "PFX" "PFX" "PFX"\n",
               sysnum, 
               dr_syscall_get_param(drcontext, 0),
               dr_syscall_get_param(drcontext, 1),
               dr_syscall_get_param(drcontext, 2));
#endif
    if (sysnum == write_sysnum) {
        /* store params for access post-syscall */
        int i;
        per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx);
#ifdef WINDOWS
        /* stderr and stdout are identical in our cygwin rxvt shell so for
         * our example we suppress output starting with 'H' instead
         */
        byte *output = (byte *) dr_syscall_get_param(drcontext, 5);
        byte first;
        size_t read;
        bool ok = dr_safe_read(output, 1, &first, &read);
        if (!ok || read != 1)
            return true; /* data unreadable: execute normally */
        if (dr_is_wow64()) {
            /* store the xcx emulation parameter for wow64 */
            dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/};
            dr_get_mcontext(drcontext, &mc);
            data->xcx = mc.xcx;
        }
#endif
        for (i = 0; i < SYS_MAX_ARGS; i++)
            data->param[i] = dr_syscall_get_param(drcontext, i);
        /* suppress stderr */
        if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDERR
#ifdef WINDOWS
            && first == 'H'
#endif
            ) {
            /* pretend it succeeded */
#ifdef LINUX
            /* return the #bytes == 3rd param */
            dr_syscall_set_result(drcontext, dr_syscall_get_param(drcontext, 2));
#else
            /* we should also set the IO_STATUS_BLOCK.Information field */
            dr_syscall_set_result(drcontext, 0);
#endif
#ifdef SHOW_RESULTS
            dr_fprintf(STDERR, "  [%d] => skipped\n", sysnum);
#endif
            return false; /* skip syscall */
        } else if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDOUT) {
            if (!data->repeat) {
                /* redirect stdout to stderr (unless it's our repeat) */
#ifdef SHOW_RESULTS
                dr_fprintf(STDERR, "  [%d] STDOUT => STDERR\n", sysnum);
#endif
                dr_syscall_set_param(drcontext, 0, (reg_t) STDERR);
            }
            /* we're going to repeat this syscall once */
            data->repeat = !data->repeat;
        }
    }
    return true; /* execute normally */
}
Example #17
0
static bool
event_pre_syscall(void *drcontext, int sysnum)
{
    bool modify_write = (sysnum == write_sysnum);
    dr_atomic_add32_return_sum(&num_syscalls, 1);
#ifdef UNIX
    if (sysnum == SYS_execve) {
        /* our stats will be re-set post-execve so display now */
        show_results();
# ifdef SHOW_RESULTS
        dr_fprintf(STDERR, "<---- execve ---->\n");
# endif
    }
#endif
#ifndef SHOW_RESULTS
    /* for sanity tests that don't show results we don't change the app's output */
    modify_write = false;
#endif
    if (modify_write) {
        /* store params for access post-syscall */
        int i;
        per_thread_t *data = (per_thread_t *) drmgr_get_cls_field(drcontext, tcls_idx);
#ifdef WINDOWS
        /* stderr and stdout are identical in our cygwin rxvt shell so for
         * our example we suppress output starting with 'H' instead
         */
        byte *output = (byte *) dr_syscall_get_param(drcontext, 5);
        byte first;
        size_t read;
        bool ok = dr_safe_read(output, 1, &first, &read);
        if (!ok || read != 1)
            return true; /* data unreadable: execute normally */
        if (dr_is_wow64()) {
            /* store the xcx emulation parameter for wow64 */
            dr_mcontext_t mc = {sizeof(mc),DR_MC_INTEGER/*only need xcx*/};
            dr_get_mcontext(drcontext, &mc);
            data->xcx = mc.xcx;
        }
#endif
        for (i = 0; i < SYS_MAX_ARGS; i++)
            data->param[i] = dr_syscall_get_param(drcontext, i);
        /* suppress stderr */
        if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDERR
#ifdef WINDOWS
                && first == 'H'
#endif
           ) {
            /* pretend it succeeded */
#ifdef UNIX
            /* return the #bytes == 3rd param */
            dr_syscall_result_info_t info = { sizeof(info), };
            info.succeeded = true;
            info.value = dr_syscall_get_param(drcontext, 2);
            dr_syscall_set_result_ex(drcontext, &info);
#else
            /* XXX: we should also set the IO_STATUS_BLOCK.Information field */
            dr_syscall_set_result(drcontext, 0);
#endif
#ifdef SHOW_RESULTS
            dr_fprintf(STDERR, "<---- skipping write to stderr ---->\n");
#endif
            return false; /* skip syscall */
        } else if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDOUT) {
            if (!data->repeat) {
                /* redirect stdout to stderr (unless it's our repeat) */
#ifdef SHOW_RESULTS
                dr_fprintf(STDERR, "<---- changing stdout to stderr ---->\n");
#endif
                dr_syscall_set_param(drcontext, 0, (reg_t) STDERR);
            }
            /* we're going to repeat this syscall once */
            data->repeat = !data->repeat;
        }
    }
    return true; /* execute normally */
}