Hi,
I am trying to skip a function call based on some condition. Ideally, I would use drwrap_skip_call to skip it, but since this is having issues currently, I am trying my own workaround.
To skip the call, when my instrumentation hits the first BB in the target function, I want to explicitly check for some condition (in my TLS region) then based on it return or continue with the original BB.
In short, this is what I tried:
1. Use R11 as the TLS address (no reserving needed, caller saved and unused)
2. CMP TLS->condition against a value
3. Jcc over the next step
4. Return
5. Original BB, ending with Jcc
This fails because of DR's constraints on BB jumps, so instead I would like to split it to 3 BBs. The first containing steps 1, 2, and 3. The second containing 4. And the third containing the original values.
So, instead, I tried the following:
if (bb is beginning of func)
{
static bool first_step = false;
static bool second_step = false;
instr_t* first = instrlist_first(bb);
if (!first_step)
{
// Get TLS. Use R11 for the TLS, this is the beginning of the function so definitely not used.
// Flags don't matter either
reg_id_t tls_reg = DR_REG_R11;
drmgr_insert_read_tls_field(drctx, tls_index, bb, first, tls_reg);
// Test
opnd_t check_opnd = opnd_create_base_disp(tls_reg, DR_REG_NULL, 0,
offsetof(TLSInfo, skip_fn), OPSZ_1);
instr_t* tmp = INSTR_CREATE_cmp(drctx, check_opnd, opnd_create_immed_uint(1, OPSZ_1));
instr_set_translation(tmp, instr_get_app_pc(first) - 1);
instrlist_meta_preinsert(bb, first, tmp);
// conditional jump to original bb if not skip
tmp = INSTR_CREATE_jcc(drctx, OP_jne, opnd_create_pc(instr_get_app_pc(first)));
instr_set_translation(tmp, instr_get_app_pc(first) - 1);
instrlist_preinsert(bb, first, tmp);
// Remove the rest of the BB
for (instr_t* inst = first; inst != nullptr; )
{
instr_t* next_inst = instr_get_next(inst);
instrlist_remove(bb, inst);
inst = next_inst;
}
// end first step
first_step = true;
return DR_EMIT_DEFAULT;
}
else if (!second_step)
{
// Ret
instr_t* ret = INSTR_CREATE_ret(drctx);
instr_set_translation(ret, instr_get_app_pc(first)-1);
instrlist_preinsert(bb, first, ret);
// Remove the rest of the BB
for (instr_t* inst = first; inst != nullptr; )
{
instr_t* next_inst = instr_get_next(inst);
instrlist_remove(bb, inst);
inst = next_inst;
}
// end second step
second_step = true;
}
}
This obviously fails. It would make all three BBs share the same tag and thus would cause looping issues with step #3 (BB1 loops for a while first, then BB2 runs instead in a trace, BB3 never hits). So, my question is how to create new BBs without sharing the tag with the original? How to avoid this behavior?