static void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) { unsigned long sp, pc; unsigned long *ksp; if (regs) { sp = GET_USP(regs); pc = GET_IP(regs); } else if (task == NULL || task == current) { const register unsigned long current_sp __asm__ ("sp"); sp = current_sp; pc = (unsigned long)walk_stackframe; } else { /* task blocked in __switch_to */ sp = task->thread.sp; pc = task->thread.ra; } if (unlikely(sp & 0x7)) return; ksp = (unsigned long *)sp; while (!kstack_end(ksp)) { if (__kernel_text_address(pc) && unlikely(fn(pc, arg))) break; pc = (*ksp++) - 0x4; } }
int main(int argc, char ** argv) { void *cip1, *cip2; // GET_IP(cip1); GET_IP(back_address); jmp_back(); // GET_IP(cip2); // printf("ip: %p, %p, difference: %ld\n", cip2, cip1, cip2 - cip1); printf("We are back!\n"); return 0; }
static void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) { unsigned long fp, sp, pc; if (regs) { fp = GET_FP(regs); sp = GET_USP(regs); pc = GET_IP(regs); } else if (task == NULL || task == current) { const register unsigned long current_sp __asm__ ("sp"); fp = (unsigned long)__builtin_frame_address(0); sp = current_sp; pc = (unsigned long)walk_stackframe; } else { /* task blocked in __switch_to */ fp = task->thread.s[0]; sp = task->thread.sp; pc = task->thread.ra; } for (;;) { unsigned long low, high; struct stackframe *frame; if (unlikely(!__kernel_text_address(pc) || fn(pc, arg))) break; /* Validate frame pointer */ low = sp + sizeof(struct stackframe); high = ALIGN(sp, THREAD_SIZE); if (unlikely(fp < low || fp > high || fp & 0x7)) break; /* Unwind stack frame */ frame = (struct stackframe *)fp - 1; sp = fp; fp = frame->fp; pc = frame->ra - 0x4; } }
static void libbf_save_state(DynAllocDesc* desc, void* ptr) { cast_ptr_to_context(ptr, context); long pagesize = libbf_getpagesize(); long regIP = (long)GET_IP(context); int relative_ip = regIP - (long)desc->current_executable_code; void* data_ptr = (void*)GET_DATA_PTR_REG(context); void* base_data_ptr = desc->executableCodeData.base_data_ptr; int relative_data_ptr = (long)data_ptr - (long)base_data_ptr; /* Restore regular protection for user data pages */ int ret = libbf_mprotect(desc->current_mem, (COUNT_LOW_ACT_HIGH_PAGES(desc)) * pagesize, PROT_READ | PROT_WRITE); if (ret != 0) fatal("mprotect failed\n"); assert (regIP >= (long)desc->current_executable_code && regIP < (long)desc->current_executable_code + desc->size_of_executable_code); #if defined(__i386__) { int eax = GET_AX(context); int ebx = GET_BX(context); int ecx = GET_CX(context); int edx = GET_DX(context); int flags = GET_FL(context); int i; unsigned char* c = (unsigned char*) desc->current_executable_code; FILE* f; if (desc->options->suspend_file && (f = fopen(desc->options->suspend_file, "wb")) != NULL) { fwrite(desc->current_executable_code, desc->size_of_executable_code, 1, f); fwrite(&relative_ip, sizeof(int), 1, f); fwrite(&eax, sizeof(int), 1, f); fwrite(&ebx, sizeof(int), 1, f); fwrite(&ecx, sizeof(int), 1, f); fwrite(&edx, sizeof(int), 1, f); fwrite(&flags, sizeof(int), 1, f); fwrite(&relative_data_ptr, sizeof(int), 1, f); fwrite(&desc->count_active_pages, sizeof(int), 1, f); fwrite(base_data_ptr, desc->count_active_pages * pagesize, 1, f); fclose(f); } else { warning("Can't write in suspend file\n"); } /* seek : 83 c4 0c add $12,%esp */ for(i=desc->size_of_executable_code-3-1;i>=0;i--) { if (c[i] == 0x83 && c[i+1] == 0xc4 && c[i+2] == 4*3) { GET_IP(context) = (int)(c + i); return; } } SHOULDNT_HAPPEN(); } #else { long rax = GET_AX(context); long rdi = GET_DI(context); long rsi = GET_SI(context); long rcx = GET_CX(context); long rdx = GET_DX(context); long flags = GET_FL(context); int i; unsigned char* c = (unsigned char*) desc->current_executable_code; FILE* f; if (desc->options->suspend_file && (f = fopen(desc->options->suspend_file, "wb")) != NULL) { fwrite(desc->current_executable_code, desc->size_of_executable_code, 1, f); fwrite(&relative_ip, sizeof(int), 1, f); fwrite(&rax, sizeof(rax), 1, f); fwrite(&rdi, sizeof(rdi), 1, f); fwrite(&rsi, sizeof(rsi), 1, f); fwrite(&rcx, sizeof(rcx), 1, f); fwrite(&rdx, sizeof(rdx), 1, f); fwrite(&flags, sizeof(flags), 1, f); fwrite(&relative_data_ptr, sizeof(int), 1, f); fwrite(&desc->count_active_pages, sizeof(int), 1, f); fwrite(base_data_ptr, desc->count_active_pages * pagesize, 1, f); fclose(f); } else { warning("Can't write in suspend file\n"); } /* seek : 48 83 c4 18 add $24,%rsp */ for(i=desc->size_of_executable_code-4-1;i>=0;i--) { if (c[i] == 0x48 && c[i+1] == 0x83 && c[i+2] == 0xc4 && c[i+3] == 8*3) { GET_IP(context) = (long)(c + i); return; } } SHOULDNT_HAPPEN(); } #endif }
static void libbf_compiler_dynalloc_handler(int signum, siginfo_t* info, void* ptr) { if (signum == SIGBUS || (signum == SIGSEGV /* && info->si_code == SEGV_ACCERR */)) { long pagesize = libbf_getpagesize(); cast_ptr_to_context(ptr, context); long fault_page; long regIP; void* old_mem; int old_size; long delta_mem; int ret; #if defined(__powerpc__) DynAllocDesc* desc = (DynAllocDesc*)GET_R14(context); #elif defined(sun) && defined(__sparc__) DynAllocDesc* desc = (DynAllocDesc*)GET_O4(context); #else void** esp = (void**)GET_SP(context); DynAllocDesc* desc = (DynAllocDesc*)esp[0]; assert(esp[1] == (void*)SIGNATURE_1); assert(esp[2] == (void*)SIGNATURE_2); #endif if (DEBUG_DYNALLOC) fprintf(stderr, "illegal access to 0x%lX\n", (long)info->si_addr); assert(desc->signature1 == SIGNATURE_1); assert(desc->signature2 == SIGNATURE_2); #if (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(WIN32)) && (defined(__i386__) || defined(__x86_64__)) if (desc->isInterrupted) { libbf_save_state(desc, ptr); return; } #endif fault_page = (long)info->si_addr & ~(pagesize-1); if (fault_page >= (long)desc->current_mem && fault_page < (long)desc->current_mem + desc->count_low_pages * pagesize) { if (DEBUG_DYNALLOC) fprintf(stderr, "before current memory\n"); desc->increase_from_low = ((long)desc->current_mem + desc->count_low_pages * pagesize - (long)fault_page) / pagesize; } else if (fault_page >= (long)desc->current_mem + COUNT_LOW_ACT_PAGES(desc) * pagesize && fault_page < (long)desc->current_mem + COUNT_LOW_ACT_HIGH_PAGES(desc) * pagesize) { if (DEBUG_DYNALLOC) fprintf(stderr, "after current memory\n"); desc->increase_from_high = 1 + (fault_page - ((long)desc->current_mem + COUNT_LOW_ACT_PAGES(desc) * pagesize)) / pagesize; } else { fatal("dynamic memory allocator strangly failed !"); } if (desc->max_total_pages >= 0 && desc->count_active_pages + desc->increase_from_low + desc->increase_from_high > desc->max_total_pages) { fatal("Cannot dynamically alloc more than %d pages\n", desc->max_total_pages); } regIP = (long)GET_IP(context); if (DEBUG_DYNALLOC) fprintf(stderr, "0x%lX [0x%lX,0x%lX[\n", regIP, (long)desc->current_executable_code, (long)desc->current_executable_code + desc->size_of_executable_code); if (!(regIP >= (long)desc->current_executable_code && regIP < (long)desc->current_executable_code + desc->size_of_executable_code)) { fatal("!(regIP >= desc->current_executable_code && regIP < desc->current_executable_code + desc->size_of_executable_code)\n"); } #if defined(__powerpc__) libbf_compiler_desasm(desc->sizeof_elt, (char*)regIP); #endif old_mem = desc->current_mem; old_size = (COUNT_LOW_ACT_HIGH_PAGES(desc)) * pagesize; delta_mem = libbf_compiler_dynalloc_realloc(desc); GET_DATA_PTR_REG(context) += delta_mem; desc->executableCodeData.base_data_ptr = (void*)((long)desc->executableCodeData.base_data_ptr + delta_mem); if (DEBUG_DYNALLOC) fprintf(stderr, "dynamic memory allocator can go on\n"); /* Unprotecting all - old - user memory, including upper reserved page, for any latter reuse */ ret = libbf_mprotect(old_mem, old_size, PROT_READ | PROT_WRITE); if (ret != 0) fatal("mprotect failed\n"); /* Discarding now old memory */ libbf_free_aligned(old_mem); } else { fatal("unexpected sigsegv at 0x%lX\n", (long)info->si_addr); } }
void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip, PEXCEPTION_RECORD pRecord, DWORD returnEax, CONTEXT *context ) { EXCEPTION_RECORD record, newrec; PEXCEPTION_FRAME frame, dispatch; #ifdef __i386__ context->Eax = returnEax; #endif /* build an exception record, if we do not have one */ if (!pRecord) { record.ExceptionCode = STATUS_UNWIND; record.ExceptionFlags = 0; record.ExceptionRecord = NULL; record.ExceptionAddress = GET_IP(context); record.NumberParameters = 0; pRecord = &record; } pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND); TRACE( "code=%lx flags=%lx\n", pRecord->ExceptionCode, pRecord->ExceptionFlags ); /* get chain of exception frames */ frame = NtCurrentTeb()->except; while ((frame != (PEXCEPTION_FRAME)0xffffffff) && (frame != pEndFrame)) { /* Check frame address */ if (pEndFrame && (frame > pEndFrame)) { newrec.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; newrec.ExceptionFlags = EH_NONCONTINUABLE; newrec.ExceptionRecord = pRecord; newrec.NumberParameters = 0; RtlRaiseException( &newrec ); /* never returns */ } if (((void*)frame < NtCurrentTeb()->stack_low) || ((void*)(frame+1) > NtCurrentTeb()->stack_top) || (int)frame & 3) { newrec.ExceptionCode = STATUS_BAD_STACK; newrec.ExceptionFlags = EH_NONCONTINUABLE; newrec.ExceptionRecord = pRecord; newrec.NumberParameters = 0; RtlRaiseException( &newrec ); /* never returns */ } /* Call handler */ switch(EXC_CallHandler( pRecord, frame, context, &dispatch, frame->Handler, EXC_UnwindHandler )) { case ExceptionContinueSearch: break; case ExceptionCollidedUnwind: frame = dispatch; break; default: newrec.ExceptionCode = STATUS_INVALID_DISPOSITION; newrec.ExceptionFlags = EH_NONCONTINUABLE; newrec.ExceptionRecord = pRecord; newrec.NumberParameters = 0; RtlRaiseException( &newrec ); /* never returns */ break; } frame = __wine_pop_frame( frame ); } }