From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1InFB9-0006Sd-LE for qemu-devel@nongnu.org; Wed, 31 Oct 2007 11:08:23 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1InFB7-0006Pb-Vg for qemu-devel@nongnu.org; Wed, 31 Oct 2007 11:08:23 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1InFB7-0006PN-Qv for qemu-devel@nongnu.org; Wed, 31 Oct 2007 11:08:21 -0400 Received: from owa.c2.net ([207.235.78.2] helo=email.c2.net) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1InFB6-0001ze-Qv for qemu-devel@nongnu.org; Wed, 31 Oct 2007 11:08:21 -0400 Subject: Re: [Qemu-devel] [PATCH] strace rework From: Thayne Harbaugh In-Reply-To: <20071027132612.GK29176@networkno.de> References: <1193063060.5068.45.camel@phantasm.home.enterpriseandprosperity.com> <20071027132612.GK29176@networkno.de> Content-Type: multipart/mixed; boundary="=-8padk5UiRiA4ssnQhRhZ" Date: Wed, 31 Oct 2007 09:00:29 -0600 Message-Id: <1193842829.19343.24.camel@phantasm.home.enterpriseandprosperity.com> Mime-Version: 1.0 Reply-To: thayne@c2.net, qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Thiemo Seufer Cc: qemu-devel --=-8padk5UiRiA4ssnQhRhZ Content-Type: text/plain Content-Transfer-Encoding: 7bit On Sat, 2007-10-27 at 14:26 +0100, Thiemo Seufer wrote: > Thayne Harbaugh wrote: > > This is a rework of Stuart Anderson's strace patch. I've fixed > > target-to-host and host-to-target syscall lookups so that the proper > > host or target errno is returned. > > It didn't build for me due to the a missing target_to_host_errno > function. This isn't obvious to me. It also doesn't appear that you included this error in the output you sent. > Could you also have a look at the compiler warnings > from strace.c? I see e.g.: Thank you for sending me the warnings. I've reworked it so that function arguments are passed correctly, target addresses have access checked and locked and that proper print format codes are used. Attached is the new version. Please send me feedback. Thank you. --=-8padk5UiRiA4ssnQhRhZ Content-Disposition: attachment; filename=05_strace.patch Content-Type: text/x-patch; name=05_strace.patch; charset=utf-8 Content-Transfer-Encoding: 7bit Index: qemu/Makefile.target =================================================================== --- qemu.orig/Makefile.target 2007-10-31 00:00:47.000000000 -0600 +++ qemu/Makefile.target 2007-10-31 00:02:13.000000000 -0600 @@ -249,7 +249,7 @@ endif ifdef CONFIG_LINUX_USER -OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ +OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \ elfload.o linuxload.o LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT Index: qemu/linux-user/syscall.c =================================================================== --- qemu.orig/linux-user/syscall.c 2007-10-31 00:00:47.000000000 -0600 +++ qemu/linux-user/syscall.c 2007-10-31 00:02:13.000000000 -0600 @@ -249,11 +249,18 @@ extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); +#define ERRNO_TABLE_SIZE 1200 + +/* target_to_host_errno_table[] is initialized from + * host_to_target_errno_table[] in syscall_init(). */ +static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = { +}; + /* * This list is the union of errno values overridden in asm-/errno.h * minus the errnos that are not actually generic to all archs. */ -static uint16_t host_to_target_errno_table[1200] = { +static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { [EIDRM] = TARGET_EIDRM, [ECHRNG] = TARGET_ECHRNG, [EL2NSYNC] = TARGET_EL2NSYNC, @@ -359,7 +366,7 @@ #ifdef ENOTRECOVERABLE [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, #endif - }; +}; static inline int host_to_target_errno(int err) { @@ -368,6 +375,13 @@ return err; } +static inline int target_to_host_errno(int err) +{ + if (target_to_host_errno_table[err]) + return target_to_host_errno_table[err]; + return err; +} + static inline target_long get_errno(target_long ret) { if (ret == -1) @@ -381,6 +395,11 @@ return (target_ulong)ret >= (target_ulong)(-4096); } +char *target_strerror(int err) +{ + return strerror(target_to_host_errno(err)); +} + static target_ulong target_brk; static target_ulong target_original_brk; @@ -2458,6 +2477,7 @@ IOCTLEntry *ie; const argtype *arg_type; int size; + int i; #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); #define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); @@ -2483,6 +2503,12 @@ ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | (size << TARGET_IOC_SIZESHIFT); } + + /* Build target_to_host_errno_table[] table from + * host_to_target_errno_table[]. */ + for (i=0; i < ERRNO_TABLE_SIZE; i++) + target_to_host_errno_table[host_to_target_errno_table[i]] = i; + /* automatic consistency check if same arch */ #if defined(__i386__) && defined(TARGET_I386) if (ie->target_cmd != ie->host_cmd) { @@ -2582,6 +2608,9 @@ #ifdef DEBUG gemu_log("syscall %d", num); #endif + if(do_strace) + print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + switch(num) { case TARGET_NR_exit: #ifdef HAVE_GPROF @@ -5016,5 +5045,7 @@ #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif + if(do_strace) + print_syscall_ret(num, ret); return ret; } Index: qemu/linux-user/main.c =================================================================== --- qemu.orig/linux-user/main.c 2007-10-31 00:00:47.000000000 -0600 +++ qemu/linux-user/main.c 2007-10-31 00:02:13.000000000 -0600 @@ -1927,6 +1927,10 @@ putenv("LD_LIBRARY_PATH=/usr/lib/libfakeroot:/usr/lib64/libfakeroot:/usr/lib32/libfakeroot"); } + if(getenv("QEMU_STRACE") ){ + do_strace=1; + } + wrk = environ; while (*(wrk++)) environ_count++; Index: qemu/linux-user/qemu.h =================================================================== --- qemu.orig/linux-user/qemu.h 2007-10-31 00:00:47.000000000 -0600 +++ qemu/linux-user/qemu.h 2007-10-31 00:51:48.000000000 -0600 @@ -138,10 +138,18 @@ void cpu_loop(CPUState *env); void init_paths(const char *prefix); const char *path(const char *pathname); +char *target_strerror(int err); extern int loglevel; extern FILE *logfile; +/* strace.c */ +void print_syscall(int num, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6); +void print_syscall_ret(int num, target_long arg1); +extern int do_strace; + /* signal.c */ void process_pending_signals(void *cpu_env); void signal_init(void); Index: qemu/linux-user/strace.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/linux-user/strace.c 2007-10-31 02:24:30.000000000 -0600 @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qemu.h" + +int do_strace=0; + +struct syscallname { + int nr; + char *name; + char *format; + void (*call)(struct syscallname *, + target_long, target_long, target_long, + target_long, target_long, target_long); + void (*result)(struct syscallname *, target_long); +}; + +/* + * Utility functions + */ +static void +print_ipc_cmd(int cmd) +{ +#define output_cmd(val) \ +if( cmd == val ) { \ + gemu_log(#val); \ + return; \ +} + + cmd &= 0xff; + + /* General IPC commands */ + output_cmd( IPC_RMID ); + output_cmd( IPC_SET ); + output_cmd( IPC_STAT ); + output_cmd( IPC_INFO ); + /* msgctl() commands */ + #ifdef __USER_MISC + output_cmd( MSG_STAT ); + output_cmd( MSG_INFO ); + #endif + /* shmctl() commands */ + output_cmd( SHM_LOCK ); + output_cmd( SHM_UNLOCK ); + output_cmd( SHM_STAT ); + output_cmd( SHM_INFO ); + /* semctl() commands */ + output_cmd( GETPID ); + output_cmd( GETVAL ); + output_cmd( GETALL ); + output_cmd( GETNCNT ); + output_cmd( GETZCNT ); + output_cmd( SETVAL ); + output_cmd( SETALL ); + output_cmd( SEM_STAT ); + output_cmd( SEM_INFO ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + + /* Some value we don't recognize */ + gemu_log("%d",cmd); +} + +static void +print_fdset(int n, target_ulong target_fds_addr) +{ + int i; + + gemu_log("["); + if( target_fds_addr ) { + target_long *target_fds; + + if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1))) + return; + + target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1); + for (i=n; i>=0; i--) { + if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1) + gemu_log("%d,", i ); + } + unlock_user(target_fds, target_fds_addr, 0); + } + gemu_log("]"); +} + +static void +print_timeval(target_ulong tv_addr) +{ + if( tv_addr ) { + struct target_timeval *tv; + + if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv))) + return; + + tv = lock_user(tv_addr, sizeof(*tv), 1); + gemu_log("{%d,%d}", tv->tv_sec, tv->tv_usec); + unlock_user(tv, tv_addr, 0); + } else + gemu_log("NULL"); +} + +/* + * Sysycall specific output functions + */ + +/* select */ +static long newselect_arg1 = 0; +static long newselect_arg2 = 0; +static long newselect_arg3 = 0; +static long newselect_arg4 = 0; +static long newselect_arg5 = 0; + +static void +print_newselect(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + gemu_log("%s(" TARGET_FMT_ld ",", name->name, arg1); + print_fdset(arg1, arg2); + gemu_log(","); + print_fdset(arg1, arg3); + gemu_log(","); + print_fdset(arg1, arg4); + gemu_log(","); + print_timeval(arg5); + gemu_log(")"); + + /* save for use in the return output function below */ + newselect_arg1=arg1; + newselect_arg2=arg2; + newselect_arg3=arg3; + newselect_arg4=arg4; + newselect_arg5=arg5; +} + +static void +print_semctl(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld ",", name->name, arg1, arg2); + print_ipc_cmd(arg3); + gemu_log(",0x" TARGET_FMT_lx ")", arg4); +} + +static void +print_execve(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + target_ulong arg_ptr_addr; + char *s; + + if (!access_ok(VERIFY_READ, arg1, 1)) + return; + + s = lock_user_string(arg1); + gemu_log("%s(\"%s\",{", name->name, s); + unlock_user(s, arg1, 0); + + for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) { + target_ulong *arg_ptr, arg_addr, s_addr; + + if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong))) + return; + + arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1); + arg_addr = tswapl(*arg_ptr); + unlock_user(arg_ptr, arg_ptr_addr, 0); + if (!arg_addr) + break; + s = lock_user_string(arg_addr); + gemu_log("\"%s\",", s); + unlock_user(s, s_addr, 0); + } + + gemu_log("NULL})"); +} + +static void +print_ipc(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + switch(arg1) { + case IPCOP_semctl: + name->name = "semctl"; + print_semctl(name,arg2,arg3,arg4,arg5,arg6,0); + break; + default: + gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld ")", + name->name, arg1, arg2, arg3, arg4); + } +} + +/* + * Variants for the return value output function + */ + +static void +print_syscall_ret_addr(struct syscallname *name, target_long ret) +{ +if( ret == -1 ) { + gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); + } else { + gemu_log(" = " TARGET_FMT_lx "\n", ret); + } +} + +static void +print_syscall_ret_raw(struct syscallname *name, target_long ret) +{ + gemu_log(" = " TARGET_FMT_lx "\n", ret); +} + +static void +print_syscall_ret_newselect(struct syscallname *name, target_long ret) +{ + gemu_log(" = " TARGET_FMT_lx " (", ret); + print_fdset(newselect_arg1,newselect_arg2); + gemu_log(","); + print_fdset(newselect_arg1,newselect_arg3); + gemu_log(","); + print_fdset(newselect_arg1,newselect_arg4); + gemu_log(","); + print_timeval(newselect_arg5); + gemu_log(")\n"); +} + +/* + * An array of all of the syscalls we know about + */ + +static struct syscallname scnames[] = { +#include "strace.list" +}; + +static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname); + +/* + * The public interface to this module. + */ +void +print_syscall(int num, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + int i; + char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)"; + + gemu_log("%d ", getpid() ); + + for(i=0;i