Skip to content

Commit

Permalink
inlining small jumps
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewfl committed Jul 21, 2016
1 parent f3d7620 commit fc5985f
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 18 deletions.
10 changes: 7 additions & 3 deletions src/manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ void* Manager::begin_trace(void *id, void *ret_addr) {

auto old_head = get_tracer_head();

void *trace_pc = ret_addr;

void *ret;
Tracer *l;
{
Expand All @@ -184,6 +186,7 @@ void* Manager::begin_trace(void *id, void *ret_addr) {
} else {
assert(old_head->resume_addr == nullptr);
old_head->tracer->JumpToNestedLoop(id);
trace_pc = (void*)old_head->tracer->get_origional_pc();
assert(old_head->resume_addr != nullptr);
}
}
Expand All @@ -194,7 +197,7 @@ void* Manager::begin_trace(void *id, void *ret_addr) {

auto buff = make_shared<CodeBuffer>(4 * 1024 * 1024);
new_head->tracer = l = new Tracer(buff);
l->tracing_from = (mem_loc_t)ret_addr;
l->tracing_from = (mem_loc_t)trace_pc;
l->owning_thread = get_thread_id();
// int r = mprotect(this, 4*1024, PROT_READ | PROT_WRITE);
// assert(!r);
Expand All @@ -205,7 +208,7 @@ void* Manager::begin_trace(void *id, void *ret_addr) {
// assert(!r);

new_head->trace_id = id;
ret = l->Start(ret_addr);
ret = l->Start(trace_pc);
new_head->is_traced = true;
info->starting_point = l->get_start_location();
}
Expand All @@ -225,7 +228,7 @@ void* Manager::end_trace(void *id) {
head->tracer = nullptr;

// ret is going to be the address of the normal execution
ret = l->EndTraceFallThrough();
ret = l->EndTraceFallthrough();
// if(head->resume_addr != nullptr) {
// // if the next element contains a
// ret = head->resume_addr;
Expand Down Expand Up @@ -419,6 +422,7 @@ tracer_stack_state Manager::pop_tracer_stack() {

tracer_stack_state *Manager::get_tracer_head() {
if(stack_head == nullptr) {
threadl_tracer_stack.reserve(50);
tracer_stack_state e;
threadl_tracer_stack.push_back(e);
stack_head = &threadl_tracer_stack[0];
Expand Down
82 changes: 70 additions & 12 deletions src/tracer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ void* Tracer::Start(void *start_addr) {

compiler.jmp(imm_u(interrupt_block_location));
compiler.mov(x86::r15, imm_u(0xdeadbeef));
compiler.mov(x86::r15, imm_ptr(start_addr));
//compiler.jmp(imm_ptr(start_addr));

auto written = compiler.finalize();
Expand Down Expand Up @@ -280,6 +281,7 @@ void Tracer::Run(struct user_regs_struct *other_stack) {
assert(after_stack == 0xdeadbeef);
generated_location = buffer->getRawBuffer() + buffer->getOffset();
last_location = udis_loc;
local_jump_min_addr = last_local_jump = 0;
assert(current_location == last_location);
//assert(generation_lock.owns_lock());

Expand All @@ -301,8 +303,31 @@ void Tracer::Run(struct user_regs_struct *other_stack) {
//fflush(stderr);

jmp_info = decode_instruction();
if(jmp_info.is_jump)
if(jmp_info.is_jump) {
if(jmp_info.is_local_jump) {
// there is a chance that we can directly inline this if this is a short loop
if(jmp_info.local_jump_offset < 0) {
if(last_location - current_location > -jmp_info.local_jump_offset) {
// this is a backwards branch that is going an acceptable distance
continue;
}
} else {
// this is a forward branch
if(jmp_info.local_jump_offset > 512)
// this is too far forward, we are unlikely to actually be able to inline this, so just run it
goto run_instructions;
if(last_local_jump == 0) {
// this is the earliest instruction we are currently aware of so store its address
last_local_jump = ud_insn_off(&disassm);
}
if(udis_loc + jmp_info.local_jump_offset > local_jump_min_addr)
local_jump_min_addr = udis_loc + jmp_info.local_jump_offset;
continue;
}

}
goto run_instructions;
}

for(int i = 0;; i++) {
const ud_operand_t *opr = ud_insn_opr(&disassm, i);
Expand All @@ -321,8 +346,22 @@ void Tracer::Run(struct user_regs_struct *other_stack) {
goto run_instructions;
#endif
last_location = udis_loc;
if(local_jump_min_addr && udis_loc > local_jump_min_addr) {
// yay, we are able to direclty inline this jump
local_jump_min_addr = last_local_jump = 0;
}
}
run_instructions:
if(local_jump_min_addr > last_location) {
// we failed to get far enough in the decoding to allow these jumps to be inlined
// so we revert back to the last "good" state
last_location = last_local_jump;
set_pc(last_local_jump);
ud_disassemble(&disassm);
last_local_jump = local_jump_min_addr = 0;
// these jumps can't reference registers so if that is what caused the break then set to false
rip_used = false;
}
if(current_location != last_location) {
{
CodeBuffer ins_set(current_location, last_location - current_location);
Expand Down Expand Up @@ -357,7 +396,7 @@ void Tracer::Run(struct user_regs_struct *other_stack) {

extern "C" void red_asm_end_trace();

void* Tracer::EndTraceFallThrough() {
void* Tracer::EndTraceFallthrough() {
assert(icount - last_call_instruction < 2);
red_printf("tracer end fallthrough\n");
buffer->setOffset(last_call_generated_op);
Expand Down Expand Up @@ -619,6 +658,13 @@ struct jump_instruction_info Tracer::decode_instruction() {
struct jump_instruction_info ret;

switch(ud_insn_mnemonic(&disassm)) {

case UD_Inop: {
// this is used to remove nop since they are no longer helpful with alignment since we are rewriting everything
ret.is_jump = true;
return ret;
}

case UD_Ijo:
case UD_Ijno:
case UD_Ijb:
Expand All @@ -641,13 +687,13 @@ struct jump_instruction_info Tracer::decode_instruction() {
ret.is_jump = true;
switch(opr->size) {
case 8:
ret.local_jump_location = opr->lval.sbyte;
ret.local_jump_offset = opr->lval.sbyte;
break;
case 16:
ret.local_jump_location = opr->lval.sword;
ret.local_jump_offset = opr->lval.sword;
break;
case 32:
ret.local_jump_location = opr->lval.sdword;
ret.local_jump_offset = opr->lval.sdword;
break;
default:
assert(0);
Expand All @@ -663,13 +709,13 @@ struct jump_instruction_info Tracer::decode_instruction() {
ret.is_jump = true;
switch(opr->size) {
case 8:
ret.local_jump_location = opr->lval.sbyte;
ret.local_jump_offset = opr->lval.sbyte;
break;
case 16:
ret.local_jump_location = opr->lval.sword;
ret.local_jump_offset = opr->lval.sword;
break;
case 32:
ret.local_jump_location = opr->lval.sdword;
ret.local_jump_offset = opr->lval.sdword;
break;
default:
assert(0);
Expand All @@ -682,13 +728,13 @@ struct jump_instruction_info Tracer::decode_instruction() {
ret.is_local_jump = true;
switch(opr->size) {
case 8:
ret.local_jump_location = opr->lval.sbyte;
ret.local_jump_offset = opr->lval.sbyte;
break;
case 16:
ret.local_jump_location = opr->lval.sword;
ret.local_jump_offset = opr->lval.sword;
break;
case 32:
ret.local_jump_location = opr->lval.sdword;
ret.local_jump_offset = opr->lval.sdword;
break;
default:
assert(0);
Expand All @@ -715,6 +761,13 @@ struct jump_instruction_info Tracer::decode_instruction() {
return ret;
}

case UD_Iint3: {
// if we find an int3 then this means that there is some debugging statement and we don't want to trace that
red_printf("found int3 debugging statement, aborting");
abort();
return ret;
}

case UD_Iinvalid: {
//cerr << "no idea: " << ud_insn_hex(&disassm) << endl;
red_printf("no idea: %s\n", ud_insn_hex(&disassm));
Expand Down Expand Up @@ -805,6 +858,12 @@ void Tracer::evaluate_instruction() {
enum ud_mnemonic_code mnem = ud_insn_mnemonic(&disassm);

switch(mnem) {

case UD_Inop: {
// does nothing
return;
}

case UD_Ijo:
case UD_Ijno:
case UD_Ijb:
Expand Down Expand Up @@ -1271,7 +1330,6 @@ void Tracer::replace_rip_instruction() {
case UD_Iinc:



case UD_Icmpxchg: // todo: don't want this here....

_auto_rewrite_register:
Expand Down
11 changes: 9 additions & 2 deletions src/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace redmagic {
struct jump_instruction_info {
bool is_jump = false;
bool is_local_jump = false;
int64_t local_jump_location = 0;
int64_t local_jump_offset = 0;
};

class Tracer {
Expand All @@ -26,14 +26,18 @@ namespace redmagic {
void Run(struct user_regs_struct*);

// we are done with the loop, so resume normal execution
void* EndTraceFallThrough();
void* EndTraceFallthrough();
// if this was a nested trace then we want to branch back to the main trace
//void *EndTraceFallthroughNestedLoop(void *target_addr);
// we are jumping back to the top of the loop, so do that
void* EndTraceLoop();

// if there is another backwards branch inside of this backwards branch
// the there is a nested loop that we should trace
void JumpToNestedLoop(void *nested_trace_id);

void JumpFromNestedLoop(void *resume_pc) { set_pc((uint64_t)resume_pc); }

// generate a temp disable command, sets the thread local where to resume to address
void* TempDisableTrace();
void TempEnableTrace(void *resume_pc) { set_pc((uint64_t)resume_pc); }
Expand Down Expand Up @@ -145,6 +149,9 @@ namespace redmagic {
bool rip_used = false;
int64_t icount = 0;

mem_loc_t last_local_jump = 0;
mem_loc_t local_jump_min_addr = 0;

mem_loc_t interrupt_block_location;

// in the case that we don't actually want to inline this method, then we need to be able to backout
Expand Down
2 changes: 1 addition & 1 deletion src/user_interface.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

// useful for compiling against while not causing an "problems"
// useful for compiling against while not causing any "problems"
//#define DISABLE_REDMAGIC

// this is define in a .c file instead of .s so that we can
Expand Down

0 comments on commit fc5985f

Please sign in to comment.