int tracer_copy_out( struct tracer *t, const void *data, const void *uaddr, int length ) { int result; static int has_fast_write=1; UPTRINT_T iuaddr = (UPTRINT_T)uaddr; if(length==0) return 0; #if !defined(CCTOOLS_CPU_I386) if(!tracer_is_64bit(t)) iuaddr &= 0xffffffff; #endif if(has_fast_write) { result = full_pwrite64(t->memory_file,data,length,iuaddr); if( result!=length ) { has_fast_write = 0; debug(D_SYSCALL,"writing to /proc/X/mem failed, falling back to slow ptrace write"); } else { return result; } } result = tracer_copy_out_slow(t,data,(void*)iuaddr,length); return result; }
int tracer_copy_in( struct tracer *t, void *data, const void *uaddr, int length ) { int result; static int fast_read_success = 0; static int fast_read_failure = 0; static int fast_read_attempts = 100; UPTRINT_T iuaddr = (UPTRINT_T)uaddr; #if !defined(CCTOOLS_CPU_I386) if(!tracer_is_64bit(t)) iuaddr &= 0xffffffff; #endif if(fast_read_success>0 || fast_read_failure<fast_read_attempts) { result = full_pread64(t->memory_file,data,length,iuaddr); if(result>0) { fast_read_success++; return result; } else { fast_read_failure++; // fall through to slow method, print message on the last attempt. if(fast_read_success==0 && fast_read_failure>=fast_read_attempts) { debug(D_SYSCALL,"reading from /proc/X/mem failed, falling back to slow ptrace read"); } } } result = tracer_copy_in_slow(t,data,(void*)iuaddr,length); return result; }
ssize_t tracer_copy_in_string( struct tracer *t, char *str, const void *uaddr, size_t length, int flags ) { if(length==0) return 0; #if !defined(CCTOOLS_CPU_I386) if(!tracer_is_64bit(t)) { uaddr = VOID_MATH(uaddr, & 0xffffffff); } #endif ssize_t rc = copy_in_fast(t,str,uaddr,length,flags); if (rc == -1 && errno == ENOSYS && !(flags & TRACER_O_FAST)) rc = copy_in_string_slow(t,str,uaddr,length,flags); /* check for NUL */ if (rc > 0) { void *nul = memchr(str,'\0',length); if (nul) { rc = (ssize_t)((uintptr_t)nul-(uintptr_t)str); } else { *str = '\0'; errno = EINVAL; rc = -1; } } return rc; }
int tracer_copy_in( struct tracer *t, void *data, const void *uaddr, int length ) { int result; static int has_fast_read = 1; UPTRINT_T iuaddr = (UPTRINT_T)uaddr; #if !defined(CCTOOLS_CPU_I386) if(!tracer_is_64bit(t)) iuaddr &= 0xffffffff; #endif if(has_fast_read) { result = full_pread64(t->memory_file,data,length,iuaddr); if( result<=0 && errno==EINVAL ) { has_fast_read = 0; debug(D_SYSCALL,"reading from /proc/X/mem failed, falling back to slow ptrace read"); } else { return result; } } result = tracer_copy_in_slow(t,data,(void*)iuaddr,length); return result; }
const char * tracer_syscall_name( struct tracer *t, int syscall ) { if(tracer_is_64bit(t)) { return tracer_syscall64_name(syscall); } else { return tracer_syscall32_name(syscall); } }
int tracer_args_set( struct tracer *t, INT64_T syscall, const INT64_T *args, int nargs ) { if(!t->gotregs) { if(ptrace(PTRACE_GETREGS,t->pid,0,&t->regs) == -1) ERROR; t->gotregs = 1; } #if 0 /* Enable this for extreme debugging... */ { int i; buffer_t B; buffer_init(&B); buffer_putfstring(&B, "SET args[%zu] = {", (size_t)nargs); for (i = 0; i < nargs; i++) buffer_putfstring(&B, "%" PRId64 ", ", args[i]); buffer_putliteral(&B, "}"); debug(D_DEBUG, "%s", buffer_tostring(&B, NULL)); buffer_free(&B); } #endif #ifdef CCTOOLS_CPU_I386 t->regs.regs32.orig_eax = syscall; if(nargs>=1) t->regs.regs32.ebx = args[0]; if(nargs>=2) t->regs.regs32.ecx = args[1]; if(nargs>=3) t->regs.regs32.edx = args[2]; if(nargs>=4) t->regs.regs32.esi = args[3]; if(nargs>=5) t->regs.regs32.edi = args[4]; if(nargs>=6) t->regs.regs32.ebp = args[5]; #else if(tracer_is_64bit(t)) { t->regs.regs64.orig_rax = syscall; if(nargs>=1) t->regs.regs64.rdi = args[0]; if(nargs>=2) t->regs.regs64.rsi = args[1]; if(nargs>=3) t->regs.regs64.rdx = args[2]; if(nargs>=4) t->regs.regs64.r10 = args[3]; if(nargs>=5) t->regs.regs64.r8 = args[4]; if(nargs>=6) t->regs.regs64.r9 = args[5]; } else { t->regs.regs64.orig_rax = syscall; if(nargs>=1) t->regs.regs64.rbx = args[0]; if(nargs>=2) t->regs.regs64.rcx = args[1]; if(nargs>=3) t->regs.regs64.rdx = args[2]; if(nargs>=4) t->regs.regs64.rsi = args[3]; if(nargs>=5) t->regs.regs64.rdi = args[4]; if(nargs>=6) { if (t->has_args5_bug) t->regs.regs64.r9 = args[5]; else t->regs.regs64.rbp = args[5]; } } #endif t->setregs = 1; return 1; }
ssize_t tracer_copy_in( struct tracer *t, void *data, const void *uaddr, size_t length, int flags ) { if(length==0) return 0; #if !defined(CCTOOLS_CPU_I386) if(!tracer_is_64bit(t)) { uaddr = VOID_MATH(uaddr, & 0xffffffff); } #endif ssize_t rc = copy_in_fast(t,data,uaddr,length,flags); if (rc == -1 && errno == ENOSYS && !(flags & TRACER_O_FAST)) rc = tracer_copy_in_slow(t,data,uaddr,length,flags); assert(!(flags & TRACER_O_ATOMIC) || (rc == -1 || (size_t)rc == length)); return rc; }
int tracer_args_get( struct tracer *t, INT64_T *syscall, INT64_T args[TRACER_ARGS_MAX] ) { if(!t->gotregs) { if(ptrace(PTRACE_GETREGS,t->pid,0,&t->regs) == -1) ERROR; t->gotregs = 1; } #ifdef CCTOOLS_CPU_I386 *syscall = t->regs.regs32.orig_eax; args[0] = t->regs.regs32.ebx; args[1] = t->regs.regs32.ecx; args[2] = t->regs.regs32.edx; args[3] = t->regs.regs32.esi; args[4] = t->regs.regs32.edi; args[5] = t->regs.regs32.ebp; #else if(tracer_is_64bit(t)) { *syscall = t->regs.regs64.orig_rax; #if 0 /* Enable this for extreme debugging... */ debug(D_DEBUG, "rax = %d; -%d is -ENOSYS (rax == -ENOSYS indicates syscall-enter-stop)", (int)t->regs.regs64.rax, ENOSYS); #endif args[0] = t->regs.regs64.rdi; args[1] = t->regs.regs64.rsi; args[2] = t->regs.regs64.rdx; args[3] = t->regs.regs64.r10; args[4] = t->regs.regs64.r8; args[5] = t->regs.regs64.r9; } else { *syscall = t->regs.regs64.orig_rax; args[0] = t->regs.regs64.rbx; args[1] = t->regs.regs64.rcx; args[2] = t->regs.regs64.rdx; args[3] = t->regs.regs64.rsi; args[4] = t->regs.regs64.rdi; if (t->has_args5_bug) args[5] = t->regs.regs64.r9; else args[5] = t->regs.regs64.rbp; } #endif #if 0 /* Enable this for extreme debugging... */ debug(D_DEBUG, "GET args[] = {%"PRId64", %"PRId64", %"PRId64", %"PRId64", %"PRId64", %"PRId64"}", args[0], args[1], args[2], args[3], args[4], args[5]); #endif return 1; }
int tracer_args_set( struct tracer *t, INT64_T syscall, INT64_T args[TRACER_ARGS_MAX], int nargs ) { if(!t->gotregs) { if(ptrace(PTRACE_GETREGS,t->pid,0,&t->regs)!=0) FATAL; t->gotregs = 1; } #ifdef CCTOOLS_CPU_I386 t->regs.regs32.orig_eax = syscall; if(nargs>=1) t->regs.regs32.ebx = args[0]; if(nargs>=2) t->regs.regs32.ecx = args[1]; if(nargs>=3) t->regs.regs32.edx = args[2]; if(nargs>=4) t->regs.regs32.esi = args[3]; if(nargs>=5) t->regs.regs32.edi = args[4]; if(nargs>=6) t->regs.regs32.ebp = args[5]; #else if(tracer_is_64bit(t)) { t->regs.regs64.orig_rax = syscall; if(nargs>=1) t->regs.regs64.rdi = args[0]; if(nargs>=2) t->regs.regs64.rsi = args[1]; if(nargs>=3) t->regs.regs64.rdx = args[2]; if(nargs>=4) t->regs.regs64.r10 = args[3]; if(nargs>=5) t->regs.regs64.r8 = args[4]; if(nargs>=6) t->regs.regs64.r9 = args[5]; } else { t->regs.regs64.orig_rax = syscall; if(nargs>=1) t->regs.regs64.rbx = args[0]; if(nargs>=2) t->regs.regs64.rcx = args[1]; if(nargs>=3) t->regs.regs64.rdx = args[2]; if(nargs>=4) t->regs.regs64.rsi = args[3]; if(nargs>=5) t->regs.regs64.rdi = args[4]; if(nargs>=6) { if (t->has_args5_bug) t->regs.regs64.r9 = args[5]; else t->regs.regs64.rbp = args[5]; } } #endif if(ptrace(PTRACE_SETREGS,t->pid,0,&t->regs)!=0) FATAL; return 1; }
int tracer_args_get( struct tracer *t, INT64_T *syscall, INT64_T args[TRACER_ARGS_MAX] ) { if(!t->gotregs) { if(ptrace(PTRACE_GETREGS,t->pid,0,&t->regs)!=0) FATAL; t->gotregs = 1; } #ifdef CCTOOLS_CPU_I386 *syscall = t->regs.regs32.orig_eax; args[0] = t->regs.regs32.ebx; args[1] = t->regs.regs32.ecx; args[2] = t->regs.regs32.edx; args[3] = t->regs.regs32.esi; args[4] = t->regs.regs32.edi; args[5] = t->regs.regs32.ebp; #else if(tracer_is_64bit(t)) { *syscall = t->regs.regs64.orig_rax; args[0] = t->regs.regs64.rdi; args[1] = t->regs.regs64.rsi; args[2] = t->regs.regs64.rdx; args[3] = t->regs.regs64.r10; args[4] = t->regs.regs64.r8; args[5] = t->regs.regs64.r9; } else { *syscall = t->regs.regs64.orig_rax; args[0] = t->regs.regs64.rbx; args[1] = t->regs.regs64.rcx; args[2] = t->regs.regs64.rdx; args[3] = t->regs.regs64.rsi; args[4] = t->regs.regs64.rdi; if (t->has_args5_bug) args[5] = t->regs.regs64.r9; else args[5] = t->regs.regs64.rbp; } #endif return 1; }