From baffd83a41bb1e6dfcee1c196b2efcfa6444abdd Mon Sep 17 00:00:00 2001 From: Matthew Francis-Landau Date: Sat, 27 Aug 2016 20:10:41 -0400 Subject: [PATCH 1/3] taking useful changes from wait-till-ret branch --- make | 13 +++++--- src/asm_interface.S | 5 +++ src/manager.cc | 12 +++++--- src/tracer.cc | 74 +++++++++++++++++++++++++++++++++++++-------- src/tracer.h | 2 ++ tools/biset.py | 17 ++++++++--- 6 files changed, 96 insertions(+), 27 deletions(-) diff --git a/make b/make index 77c635b..a795dc2 100755 --- a/make +++ b/make @@ -10,6 +10,8 @@ from fabricate import * TARGET = 'jit-test' +VERSION = '1.0.0' + UNIT_TARGET = 'build/unit_tests' GIT_VERSION = Shell('git describe --always --long --dirty --abbrev=12', silent=True).strip() @@ -59,9 +61,9 @@ def release(): clean() build() Run('mkdir -p release') - Run('cp build/libredmagic.so.1.0.0 release/') + Run('cp build/libredmagic.so.{} release/'.format(VERSION)) Run('cp src/redmagic.h release/') - Run('strip --strip-unneeded -w -K redmagic_* release/libredmagic.so.1.0.0') + Run('strip --strip-unneeded -w -K redmagic_* release/libredmagic.so.{}'.format(VERSION)) def clean(): @@ -87,11 +89,11 @@ def link(): udis_libs = ' '.join(glob.glob('deps/udis86/libudis86/.libs/*.o')) # we are not using the compiler interface, just the assembler asmjit_libs = ' '.join(filter(lambda x: 'compiler' not in x, glob.glob('build/asmjit/CMakeFiles/asmjit.dir/src/asmjit/*/*.o'))) - Run('{LD} {LD_FLAGS} -shared -fPIC -Wl,-Bsymbolic -Wl,-soname,libredmagic.so.1.0.0 -o build/libredmagic.so.1.0.0 {objs} {udis_libs} {asmjit_libs} {LIBS}'.format( + Run('{LD} {LD_FLAGS} -shared -fPIC -Wl,-Bsymbolic -Wl,-soname,libredmagic.so.{VERSION} -o build/libredmagic.so.{VERSION} {objs} {udis_libs} {asmjit_libs} {LIBS}'.format( **dict(globals(), **locals()) )) after() - Run('{LD} -o {TARGET} build/main.o build/libredmagic.so.1.0.0 -Wl,-rpath=$ORIGIN/build/'.format( + Run('{LD} -o {TARGET} build/main.o build/libredmagic.so.{VERSION} -Wl,-rpath=$ORIGIN/build/'.format( **dict(globals(), **locals()) )) after() @@ -101,8 +103,9 @@ def compile(): f.write(''' #ifndef RED_BUILD_VERSION #define RED_BUILD_VERSION "{}" +#define RED_OBJ_VERSION "{}" #endif - '''.format(GIT_VERSION)) + '''.format(GIT_VERSION, VERSION)) for f in glob.glob('src/*.cc'): Run('{CXX} {} -c {} -o {}'.format( diff --git a/src/asm_interface.S b/src/asm_interface.S index e694ad3..e42bedb 100644 --- a/src/asm_interface.S +++ b/src/asm_interface.S @@ -23,6 +23,10 @@ red_asm_resume_tracer_block_end: .global red_asm_resume_eval_block red_asm_resume_eval_block: + // check if there is somewhere we are going to stash these values + test %rdi, %rdi + jz 1f + movq %rsp, 56(%rdi) movq %r12, 0(%rdi) @@ -32,6 +36,7 @@ red_asm_resume_eval_block: movq %rbx, 32(%rdi) movq %rbp, 40(%rdi) +1: movq %rsi, %rsp m_pop_all_regs jmpq *-TRACE_RESUME_ADDRESS_OFFSET(%rsp) diff --git a/src/manager.cc b/src/manager.cc index a720bdc..af45b4f 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -686,13 +686,15 @@ void* Manager::fellthrough_branch(void *id, void *ret_addr) { l = head->tracer; // this will pop the head of the stack internally ret = l->EndTraceFallthrough(); + // the tracer ^^^ will delete itself + info->tracer = head->tracer = nullptr; - Tracer *expected = nullptr; - if(!free_tracer_list.compare_exchange_strong(expected, l)) { - // failled to save the tracer to the free list head - delete l; - } + // Tracer *expected = nullptr; + // if(!free_tracer_list.compare_exchange_strong(expected, l)) { + // // failled to save the tracer to the free list head + // delete l; + // } return ret; } else { diff --git a/src/tracer.cc b/src/tracer.cc index da7e3f9..962b092 100644 --- a/src/tracer.cc +++ b/src/tracer.cc @@ -822,12 +822,22 @@ void* Tracer::EndMergeBlock() { mem_loc_t res_addr = buffer->getRawBuffer() + buffer->getOffset(); write_interrupt_block(); mem_loc_t ret = merge_close_core(); - if(ret == 0) + if(ret == 0) { ret = res_addr; + } else { + Tracer *expected = nullptr; + if(!free_tracer_list.compare_exchange_strong(expected, this)) { + // gaaaa + protected_malloc = false; + delete this; + protected_malloc = true; + } + } return (void*)ret; } +// calling method has to free tracer if result is non zero mem_loc_t Tracer::merge_close_core() { #ifdef CONF_CHECK_MERGE_RIP mem_loc_t check_rip; @@ -891,13 +901,13 @@ mem_loc_t Tracer::merge_close_core() { // head->tracer = info->tracer = nullptr; // have to free this tracer - Tracer *expected = nullptr; - if(!free_tracer_list.compare_exchange_strong(expected, this)) { - // gaaaa - protected_malloc = false; - delete this; - protected_malloc = true; - } + // Tracer *expected = nullptr; + // if(!free_tracer_list.compare_exchange_strong(expected, this)) { + // // gaaaa + // protected_malloc = false; + // delete this; + // protected_malloc = true; + // } #ifdef CONF_VERBOSE red_printf("merge block closing back to parent: %#016lx\n", head->trace_id); @@ -973,6 +983,41 @@ void Tracer::continue_program(mem_loc_t resume_loc) { } +void Tracer::continue_program_end_self(mem_loc_t resume_loc) { +#ifdef CONF_VERBOSE + red_printf("==> %#016lx (end)\n", resume_loc); +#endif + struct user_regs_struct *l_regs_struct = regs_struct; + + + assert(regs_struct->rsp - TRACE_STACK_OFFSET == (register_t)l_regs_struct); + l_regs_struct->rsp += move_stack_by; + move_stack_by = 0; + *((register_t*)(l_regs_struct->rsp - TRACE_RESUME_ADDRESS_OFFSET)) = resume_loc; + + Tracer *expected = nullptr; + if(!free_tracer_list.compare_exchange_strong(expected, this)) { + // gaaaa + assert(expected != this); + protected_malloc = false; + delete this; + protected_malloc = true; + } + + // this should not be returning + red_asm_resume_eval_block(NULL, l_regs_struct); + + assert(0); + __builtin_unreachable(); + + // // assert((regs_struct->rax & ~0xff) != 0xfbfbfbfbfbfbfb00); + // regs_struct = (struct user_regs_struct*) + // // assert((regs_struct->rax & ~0xff) != 0xfbfbfbfbfbfbfb00); +} + + + + #define ASM_BLOCK(label) \ extern "C" void red_asm_ ## label ## _start(); \ extern "C" void red_asm_ ## label ## _end(); \ @@ -1613,8 +1658,8 @@ void Tracer::evaluate_instruction() { if(method_stack.back().return_stack_pointer == -1 || method_stack.back().return_stack_pointer == regs_struct->rsp + move_stack_by - sizeof(register_t)) { mem_loc_t merge_close = merge_close_core(); - if(merge_close) // this might have an issue with the tracer getting free and then using it when it trys to continue the program - continue_program(merge_close); + if(merge_close) + continue_program_end_self(merge_close); } assert(merge_block_stack.size() < method_stack.back().corresponding_merge_block || method_stack.back().corresponding_merge_block == 0); #endif @@ -1799,9 +1844,14 @@ void Tracer::evaluate_instruction() { assert(merge_block_stack.size() >= method_stack.back().corresponding_merge_block); if((method_stack.back().return_stack_pointer == -1 && regs_struct->rsp + move_stack_by - sizeof(register_t) >= run_starting_stack_pointer) || method_stack.back().return_stack_pointer == regs_struct->rsp + move_stack_by - sizeof(register_t)) { + bool method_merge = merge_block_stack.back().method_merge; mem_loc_t merge_close = merge_close_core(); - if(merge_close) // this might have an issue with the tracer getting free and then using it when it trys to continue the program - continue_program(merge_close); + if(merge_close) { + // we won't have the info for this merge block since it currently isn't contained on the stack + continue_program_end_self(merge_close); + } else { + assert(method_merge == true); + } } //assert(merge_block_stack.size() >= method_stack.back().corresponding_merge_block);// || method_stack.back().corresponding_merge_block == 0); #endif diff --git a/src/tracer.h b/src/tracer.h index 7d571ad..56f658a 100644 --- a/src/tracer.h +++ b/src/tracer.h @@ -93,6 +93,8 @@ namespace redmagic { // continue program might not return, so any cleanup needs to be peformed before it is called void continue_program(mem_loc_t); + // continue the program but prepare to delete self + void continue_program_end_self(mem_loc_t); void write_interrupt_block(); // jump back to the normal execution of this program, no clean up diff --git a/tools/biset.py b/tools/biset.py index 6dda757..6933a40 100644 --- a/tools/biset.py +++ b/tools/biset.py @@ -8,7 +8,7 @@ -def do_run(instruction_count, process, error_search): +def do_run(instruction_count, process, error_search, out_log): env = os.environ.copy() env['REDMAGIC_GLOBAL_ABORT'] = str(instruction_count) @@ -19,10 +19,14 @@ def do_run(instruction_count, process, error_search): try: for li in proc.stdout: + if out_log: + out_log.write(li) qu.append(li) if cnt % 50000 == 0: print(instruction_count, li) cnt += 1 + except Exception as e: + print(e) finally: proc.kill() @@ -38,8 +42,9 @@ def do_run(instruction_count, process, error_search): def main(): - max_i = int(sys.argv[-1]) - min_i = int(sys.argv[-2]) + max_i = int(sys.argv[-2]) + min_i = int(sys.argv[-3]) + out_log = str(sys.argv[-1]) assert max_i > min_i @@ -53,14 +58,16 @@ def main(): inst = (max_i + min_i) // 2 print('>>>>>>>>>>>>>>>>>>>running bisect stopping at instruction {} ({}, {}, {})'.format(inst, min_i, max_i, max_i - min_i)) time.sleep(5) - r = do_run(inst, process, error_search) + r = do_run(inst, process, error_search, None) if r: min_i = inst else: max_i = inst + with open(out_log, 'bw+') as olog: + do_run(2*max_i, process, error_search, olog) finally: print(min_i, max_i) - + From 6b1dd19392bbeea546db6a575d403e2f831d5b08 Mon Sep 17 00:00:00 2001 From: Matthew Francis-Landau Date: Sun, 28 Aug 2016 00:35:33 -0400 Subject: [PATCH 2/3] appears that it might be working --- src/asm_interface.S | 12 ++++++++---- src/asm_macros.S | 1 - src/asm_snippets.S | 2 ++ src/jit_internal.h | 4 +++- src/manager.cc | 27 ++++++++++++++------------- src/simple_compiler.cc | 4 ++-- src/tracer.cc | 21 +++++++++++++++------ 7 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/asm_interface.S b/src/asm_interface.S index e42bedb..e7a9400 100644 --- a/src/asm_interface.S +++ b/src/asm_interface.S @@ -71,16 +71,16 @@ red_asm_restart_trace: movq %r10, %rdi movq %r9, %rsi movq %rsp, %rdx - movq %r8, %rcx + //movq %r8, %rcx - // restore the origional values of r10,9,8 + // restore the origional values of r10,9,rcx movq 216(%rsp), %r10 movq 224(%rsp), %r9 - // vvv moving the r8 register + // vvv moving the rcx register movq 232(%rsp), %rax movq %r10, 56(%rsp) movq %r9, 64(%rsp) - movq %rax, 72(%rsp) + movq %rax, 88(%rsp) call red_resume_trace@plt m_pop_all_regs @@ -91,14 +91,18 @@ red_asm_restart_trace: // might end up returning to a another trace block .global red_asm_end_trace red_asm_end_trace: + movq %rsp, %rsi + pushq $0 pushq %rdi call red_end_trace@plt popq %rsi + popq %rdi jmp *%rax .global red_asm_start_nested_trace red_asm_start_nested_trace: + movq %rsp, %rcx call red_branch_to_sub_trace@plt jmp *%rax diff --git a/src/asm_macros.S b/src/asm_macros.S index 6ae5fc1..5281053 100644 --- a/src/asm_macros.S +++ b/src/asm_macros.S @@ -3,7 +3,6 @@ * preserve registers: rbx, rsp, rbp, r12, r13, r14, r15 * scratch registers: rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11 * - * N.L represents a new line in the macro expansion */ #include "constants.h" diff --git a/src/asm_snippets.S b/src/asm_snippets.S index 929ee32..1130257 100644 --- a/src/asm_snippets.S +++ b/src/asm_snippets.S @@ -138,6 +138,8 @@ red_asm_pop_all_regs_end: .global red_asm_jump_rsi red_asm_jump_rsi: + // this is only used to resume a tracer at a different address + // the address where we are expecting to resume will be loaded into rsi, so if the check fails then we will jump to that address jmp *%rsi // we don't need executable stack diff --git a/src/jit_internal.h b/src/jit_internal.h index 9a6e7ed..374910f 100644 --- a/src/jit_internal.h +++ b/src/jit_internal.h @@ -68,7 +68,7 @@ namespace redmagic { void* end_trace(void *id, void *ret_addr); void* jump_to_trace(void *id); - void* backwards_branch(void *id, void *ret_addr); + void* backwards_branch(void *id, void *ret_addr, void **stack_ptr); void* fellthrough_branch(void *id, void *ret_addr); // void ensure_not_traced(); @@ -187,6 +187,8 @@ namespace redmagic { int32_t frame_id = -1; + mem_loc_t frame_stack_ptr = -1; + #ifdef CONF_ESTIMATE_INSTRUCTIONS int num_backwards_loops = 0; diff --git a/src/manager.cc b/src/manager.cc index af45b4f..c7734c6 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -61,60 +61,60 @@ class UnprotectMalloc { }; -extern "C" void* red_user_force_begin_trace(void *id, void *ret_addr) { +extern "C" void* red_user_force_begin_trace(void *id, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->begin_trace(id, ret_addr); } -extern "C" void* red_user_force_end_trace(void *id, void *ret_addr) { +extern "C" void* red_user_force_end_trace(void *id, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->end_trace(id, ret_addr); } -extern "C" void* red_user_force_jump_to_trace(void *id, void *ret_addr) { +extern "C" void* red_user_force_jump_to_trace(void *id, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->jump_to_trace(id); } -extern "C" void* red_user_backwards_branch(void *id, void *ret_addr) { +extern "C" void* red_user_backwards_branch(void *id, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; - return manager->backwards_branch(id, ret_addr); + return manager->backwards_branch(id, ret_addr, stack_ptr); } -extern "C" void* red_user_fellthrough_branch(void *id, void *ret_addr) { +extern "C" void* red_user_fellthrough_branch(void *id, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->fellthrough_branch(id, ret_addr); } -extern "C" void* red_user_ensure_not_traced(void *_, void *ret_addr) { +extern "C" void* red_user_ensure_not_traced(void *_, void *ret_addr, void **stack_ptr) { // TODO: return manager->ensure_not_traced(); } -extern "C" void* red_user_temp_disable(void *_, void *ret_addr) { +extern "C" void* red_user_temp_disable(void *_, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->temp_disable(ret_addr); //return NULL; } -extern "C" void* red_user_is_traced(void *_, void *ret_addr) { +extern "C" void* red_user_is_traced(void *_, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->is_traced_call(); } -extern "C" void* red_user_temp_enable(void *_, void *ret_addr) { +extern "C" void* red_user_temp_enable(void *_, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->temp_enable(ret_addr); //assert(0); //return NULL; } -extern "C" void* red_user_begin_merge_block(void *_, void *ret_addr) { +extern "C" void* red_user_begin_merge_block(void *_, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->begin_merge_block(); } -extern "C" void* red_user_end_merge_block(void *_, void *ret_addr) { +extern "C" void* red_user_end_merge_block(void *_, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; return manager->end_merge_block(); } @@ -505,7 +505,7 @@ void* Manager::jump_to_trace(void *id) { return NULL; } -void* Manager::backwards_branch(void *id, void *ret_addr) { +void* Manager::backwards_branch(void *id, void *ret_addr, void **stack_ptr) { // ignore if(id == nullptr) return NULL; @@ -567,6 +567,7 @@ void* Manager::backwards_branch(void *id, void *ret_addr) { head->tracer->JumpToNestedLoop(id); } new_head = push_tracer_stack(); + new_head->frame_stack_ptr = (mem_loc_t)stack_ptr; head = &threadl_tracer_stack[threadl_tracer_stack.size() - 2]; if(head->tracer) { new_head->return_to_trace_when_done = true; diff --git a/src/simple_compiler.cc b/src/simple_compiler.cc index 79f1b58..3babeab 100644 --- a/src/simple_compiler.cc +++ b/src/simple_compiler.cc @@ -355,14 +355,14 @@ void SimpleCompiler::ResumeBlockJump(mem_loc_t resume_pc) { bind(label_top); mov(x86::ptr(x86::rsp, -TRACE_STACK_OFFSET + 216), x86::r10); mov(x86::ptr(x86::rsp, -TRACE_STACK_OFFSET + 224), x86::r9); - mov(x86::ptr(x86::rsp, -TRACE_STACK_OFFSET + 232), x86::r8); + mov(x86::ptr(x86::rsp, -TRACE_STACK_OFFSET + 232), x86::rcx); mov(x86::r10, imm_u(resume_pc)); // TODO: have this load the address of the instruction that jumped here instead of just this block // this will allow for it to easily write in a direct jump, as being designed now, we will have to redirect the jump through this indirection // so first conditional jump followed by direct jump // also, this will not work with concurrent threads lea(x86::r9, x86::ptr(label)); // patch address - mov(x86::r8, imm_u(0xfbfbfbfbfbfbfbfb)); // merge point + mov(x86::rcx, imm_u(0xfbfbfbfbfbfbfbfb)); // merge point jmp(imm_ptr(&red_asm_restart_trace)); diff --git a/src/tracer.cc b/src/tracer.cc index 962b092..649bab5 100644 --- a/src/tracer.cc +++ b/src/tracer.cc @@ -55,6 +55,8 @@ namespace redmagic { } +extern "C" void red_asm_jump_rsi(); + static int udis_input_hook (ud_t *ud) { Tracer *t = (Tracer*)ud_get_user_opaque_data(ud); @@ -193,14 +195,16 @@ extern "C" void red_set_temp_resume(void *resume_addr) { new_head->return_to_trace_when_done = true; } -extern "C" void* red_end_trace(mem_loc_t normal_end_address) { +extern "C" void* red_end_trace(mem_loc_t normal_end_address, mem_loc_t stack_ptr) { // return the address that we want to jump to auto head = manager->pop_tracer_stack(); auto new_head = manager->get_tracer_head(); assert(head.is_traced); + assert(head.frame_stack_ptr != -1); auto info = &manager->branches[head.trace_id]; info->count_fellthrough++; void *ret = (void*)normal_end_address; + ((mem_loc_t*)stack_ptr)[-1] = head.frame_stack_ptr - stack_ptr; if(new_head->is_traced) { if(new_head->tracer) { new_head->tracer->JumpFromNestedLoop((void*)normal_end_address); @@ -233,7 +237,7 @@ extern "C" void red_end_trace_ensure() { #endif } -extern "C" void* red_branch_to_sub_trace(void *resume_addr, void *sub_trace_id, void* target_rip) { +extern "C" void* red_branch_to_sub_trace(void *resume_addr, void *sub_trace_id, void* target_rip, mem_loc_t stack_ptr) { auto head = manager->get_tracer_head(); assert(head->is_traced); assert(!head->tracer); @@ -242,12 +246,11 @@ extern "C" void* red_branch_to_sub_trace(void *resume_addr, void *sub_trace_id, assert(sub_trace_id != head->trace_id || head->frame_id != branchable_frame_id); protected_malloc = false; - void *ret = manager->backwards_branch(sub_trace_id, target_rip); + void *ret = manager->backwards_branch(sub_trace_id, target_rip, (void**)stack_ptr); protected_malloc = true; auto new_head = manager->get_tracer_head(); new_head->return_to_trace_when_done = true; return ret; - } extern "C" void red_asm_start_tracing(void*, void*, void*, void*); @@ -361,6 +364,14 @@ void Tracer::Run(struct user_regs_struct *other_stack) { run_starting_stack_pointer = regs_struct->rsp; + if(get_pc() == (mem_loc_t)&red_asm_jump_rsi) { + // this is only when resuming a tracer after another one exited + assert(regs_struct->rdi < 250); // this is the offset for the starting stack pointer (not a "real" assert, just some attempt at sanity) + // we offset the starting stack pointer since that controls where we end up merging back to + run_starting_stack_pointer += regs_struct->rdi; + assert(merge_resume != 0); + } + while(true) { assert(before_stack == 0xdeadbeef); assert(after_stack == 0xdeadbeef); @@ -746,8 +757,6 @@ void* Tracer::TempDisableTrace() { return (void*)last_call_ret_addr; } -extern "C" void red_asm_jump_rsi(); - void Tracer::TempEnableTrace(void *resume_pc) { // check that the temp enable instruction is coming in at a expected spot, otherwise fork a new trace set_pc((mem_loc_t)resume_pc); From f912efdb032ab90dd15cc6940e90ef86dcae452e Mon Sep 17 00:00:00 2001 From: Matthew Francis-Landau Date: Wed, 31 Aug 2016 02:37:28 -0400 Subject: [PATCH 3/3] handful of minor fixes --- src/asm_snippets.S | 11 ++++++++--- src/config.h | 2 +- src/jit_internal.h | 2 +- src/manager.cc | 21 +++++++++++++-------- src/tracer.cc | 34 +++++++++++++++++++++++++++------- src/user_interface.c | 2 ++ 6 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/asm_snippets.S b/src/asm_snippets.S index 1130257..3f99ac8 100644 --- a/src/asm_snippets.S +++ b/src/asm_snippets.S @@ -136,11 +136,16 @@ red_asm_pop_all_regs_start: m_pop_all_regs red_asm_pop_all_regs_end: - .global red_asm_jump_rsi -red_asm_jump_rsi: + .global red_asm_jump_rsi_temp_enable +red_asm_jump_rsi_temp_enable: + jmp *%rsi + + .global red_asm_jump_rsi_resume_trace +red_asm_jump_rsi_resume_trace: // this is only used to resume a tracer at a different address // the address where we are expecting to resume will be loaded into rsi, so if the check fails then we will jump to that address jmp *%rsi -// we don't need executable stack + + // we don't need executable stack .section .note.GNU-stack,"",%progbits diff --git a/src/config.h b/src/config.h index 374e610..38ebe01 100644 --- a/src/config.h +++ b/src/config.h @@ -29,7 +29,7 @@ // makes it print all the instructions processed and extra info #ifdef CONF_DEBUG_BUILD -# define CONF_VERBOSE +//# define CONF_VERBOSE #endif // support aborting the system after some fixed number of instruction have been processed, see tools/bisect for debugging with this diff --git a/src/jit_internal.h b/src/jit_internal.h index 374910f..0eb2e4d 100644 --- a/src/jit_internal.h +++ b/src/jit_internal.h @@ -69,7 +69,7 @@ namespace redmagic { void* jump_to_trace(void *id); void* backwards_branch(void *id, void *ret_addr, void **stack_ptr); - void* fellthrough_branch(void *id, void *ret_addr); + void* fellthrough_branch(void *id, void *ret_addr, void **stack_ptr); // void ensure_not_traced(); diff --git a/src/manager.cc b/src/manager.cc index c7734c6..6cff2e2 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -83,11 +83,10 @@ extern "C" void* red_user_backwards_branch(void *id, void *ret_addr, void **stac extern "C" void* red_user_fellthrough_branch(void *id, void *ret_addr, void **stack_ptr) { UnprotectMalloc upm; - return manager->fellthrough_branch(id, ret_addr); + return manager->fellthrough_branch(id, ret_addr, stack_ptr); } extern "C" void* red_user_ensure_not_traced(void *_, void *ret_addr, void **stack_ptr) { - // TODO: return manager->ensure_not_traced(); } @@ -669,7 +668,7 @@ void* Manager::backwards_branch(void *id, void *ret_addr, void **stack_ptr) { } -void* Manager::fellthrough_branch(void *id, void *ret_addr) { +void* Manager::fellthrough_branch(void *id, void *ret_addr, void **stack_ptr) { // ignore if(id == nullptr) return NULL; @@ -705,6 +704,7 @@ void* Manager::fellthrough_branch(void *id, void *ret_addr) { // we have to pop this frame since we weren't being traced and there is nothing that will do it for us auto old_head = pop_tracer_stack(); auto new_head = get_tracer_head(); + ((mem_loc_t*)stack_ptr)[-1] = old_head.frame_stack_ptr - (mem_loc_t)stack_ptr; if(new_head->resume_addr) { assert(old_head.return_to_trace_when_done); if(new_head->tracer) { @@ -737,22 +737,25 @@ void* Manager::fellthrough_branch(void *id, void *ret_addr) { assert(!head->is_compiled || head->frame_id != branchable_frame_id); return NULL; - } void* Manager::temp_disable(void *ret_addr) { temp_disable_last_addr = ret_addr; auto head = get_tracer_head(); assert(!head->is_temp_disabled); - head->is_temp_disabled = true; + //head->d_ret = ret_addr; void *ret = NULL; - assert(!head->is_traced || head->tracer); + + //assert(!head->is_traced || head->tracer); + // ^^^ due to the tracer sometimes + if(head->tracer && !head->tracer->did_abort) { // this will push the stack ret = head->tracer->TempDisableTrace(); } else { assert(!head->resume_addr); + head->is_temp_disabled = true; push_tracer_stack(); } return ret; @@ -769,7 +772,7 @@ void* Manager::temp_enable(void *ret_addr) { //head->is_temp_disabled = false; void *ret = NULL; //head->d_ret = nullptr; - if(head->tracer && !head->tracer->did_abort) { + if(old_head.return_to_trace_when_done && head->tracer && !head->tracer->did_abort) { head->tracer->TempEnableTrace(ret_addr); } if(head->resume_addr != nullptr) { @@ -921,8 +924,10 @@ void* Manager::end_branchable_frame(void *ret_addr, void **stack_ptr) { } } #endif + auto head = get_tracer_head(); + assert(head->frame_stack_ptr > (mem_loc_t)stack_ptr); branchable_frame_id--; - assert(get_tracer_head()->frame_id <= branchable_frame_id); + assert(head->frame_id <= branchable_frame_id); return NULL; } diff --git a/src/tracer.cc b/src/tracer.cc index 649bab5..d297f4d 100644 --- a/src/tracer.cc +++ b/src/tracer.cc @@ -55,7 +55,8 @@ namespace redmagic { } -extern "C" void red_asm_jump_rsi(); +extern "C" void red_asm_jump_rsi_temp_enable(); +extern "C" void red_asm_jump_rsi_resume_trace(); static int udis_input_hook (ud_t *ud) { @@ -364,7 +365,7 @@ void Tracer::Run(struct user_regs_struct *other_stack) { run_starting_stack_pointer = regs_struct->rsp; - if(get_pc() == (mem_loc_t)&red_asm_jump_rsi) { + if(get_pc() == (mem_loc_t)&red_asm_jump_rsi_resume_trace) { // this is only when resuming a tracer after another one exited assert(regs_struct->rdi < 250); // this is the offset for the starting stack pointer (not a "real" assert, just some attempt at sanity) // we offset the starting stack pointer since that controls where we end up merging back to @@ -739,7 +740,16 @@ void* Tracer::EndTraceEnsure() { void* Tracer::TempDisableTrace() { - assert(current_not_traced_call_addr == (mem_loc_t)&redmagic_temp_disable); + if(current_not_traced_call_addr != (mem_loc_t)&redmagic_temp_disable) { + // then this must be inside of some not traced call + // but we still have to behave the same + auto head = manager->get_tracer_head(); + head->is_temp_disabled = true; + assert(head->resume_addr == nullptr); + manager->push_tracer_stack(); + return NULL; + } + //assert(current_not_traced_call_addr == (mem_loc_t)&redmagic_temp_disable); assert(icount - last_call_instruction < 2); buffer->setOffset(last_call_generated_op); SimpleCompiler compiler(buffer); @@ -762,15 +772,22 @@ void Tracer::TempEnableTrace(void *resume_pc) { set_pc((mem_loc_t)resume_pc); SimpleCompiler compiler(buffer); // the "normal" return address will be set to ris when this returns from the temp disabled region - auto wb = compiler.TestRegister((mem_loc_t)&red_asm_jump_rsi, RSI, (register_t)resume_pc, &merge_block_stack.back()); + auto wb = compiler.TestRegister((mem_loc_t)&red_asm_jump_rsi_temp_enable, RSI, (register_t)resume_pc, &merge_block_stack.back()); auto written = compiler.finalize(); wb.replace_stump(0xfafafafafafafafa, written.getRawBuffer()); write_interrupt_block(); } void Tracer::JumpFromNestedLoop(void *resume_pc) { - // same code where we check the rsi register for where we expect to resume the trace from - TempEnableTrace(resume_pc); + // this code is very similar to the above, todo:? make into function + // TempEnableTrace(resume_pc); + set_pc((mem_loc_t)resume_pc); + SimpleCompiler compiler(buffer); + // the "normal" return address will be set to ris when this returns from the temp disabled region + auto wb = compiler.TestRegister((mem_loc_t)&red_asm_jump_rsi_resume_trace, RSI, (register_t)resume_pc, &merge_block_stack.back()); + auto written = compiler.finalize(); + wb.replace_stump(0xfafafafafafafafa, written.getRawBuffer()); + write_interrupt_block(); } extern "C" void red_asm_start_nested_trace(); @@ -795,7 +812,10 @@ void Tracer::JumpToNestedLoop(void *nested_trace_id) { } void* Tracer::ReplaceIsTracedCall() { - assert(current_not_traced_call_addr == (mem_loc_t)&redmagic_is_traced); + // if this wasn't the most recent call then don't delete + // also returning null will make this statement behave in a false way + if(current_not_traced_call_addr != (mem_loc_t)&redmagic_is_traced) + return NULL; assert(icount - last_call_instruction < 2); buffer->setOffset(last_call_generated_op); SimpleCompiler compiler(buffer); diff --git a/src/user_interface.c b/src/user_interface.c index 87a580e..3570570 100644 --- a/src/user_interface.c +++ b/src/user_interface.c @@ -20,7 +20,9 @@ __asm__("jmp_rax: \n" "redmagic_" #method ": \n" \ "movq 0(%rsp), %rsi \n" \ "movq %rsp, %rdx \n" \ + "pushq $0 \n" \ "call red_user_" #method "@plt \n" \ + "popq %rdi \n" \ "cmp $5, %rax \n" \ "jg jmp_rax \n" \ "ret \n" \