188dae46dSSean Bruno /* 288dae46dSSean Bruno * System call tracing and debugging 388dae46dSSean Bruno * 488dae46dSSean Bruno * 588dae46dSSean Bruno * This program is free software; you can redistribute it and/or modify 688dae46dSSean Bruno * it under the terms of the GNU General Public License as published by 788dae46dSSean Bruno * the Free Software Foundation; either version 2 of the License, or 888dae46dSSean Bruno * (at your option) any later version. 988dae46dSSean Bruno * 1088dae46dSSean Bruno * This program is distributed in the hope that it will be useful, 1188dae46dSSean Bruno * but WITHOUT ANY WARRANTY; without even the implied warranty of 1288dae46dSSean Bruno * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1388dae46dSSean Bruno * GNU General Public License for more details. 1488dae46dSSean Bruno * 1588dae46dSSean Bruno * You should have received a copy of the GNU General Public License 1688dae46dSSean Bruno * along with this program; if not, see <http://www.gnu.org/licenses/>. 1788dae46dSSean Bruno */ 1888dae46dSSean Bruno 19*2231197cSPeter Maydell #include "qemu/osdep.h" 2084778508Sblueswir1 #include <sys/select.h> 2184778508Sblueswir1 #include <sys/syscall.h> 2288dae46dSSean Bruno #include <sys/ioccom.h> 2388dae46dSSean Bruno 2484778508Sblueswir1 #include "qemu.h" 2584778508Sblueswir1 2688dae46dSSean Bruno int do_strace; 2784778508Sblueswir1 2884778508Sblueswir1 /* 2984778508Sblueswir1 * Utility functions 3084778508Sblueswir1 */ 3184778508Sblueswir1 3280b34604SSean Bruno static void print_sysctl(const struct syscallname *name, abi_long arg1, 3380b34604SSean Bruno abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, 3480b34604SSean Bruno abi_long arg6) 3580b34604SSean Bruno { 3680b34604SSean Bruno uint32_t i; 3780b34604SSean Bruno int32_t *namep; 3880b34604SSean Bruno 3980b34604SSean Bruno gemu_log("%s({ ", name->name); 4080b34604SSean Bruno namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1); 4180b34604SSean Bruno if (namep) { 4280b34604SSean Bruno int32_t *p = namep; 4380b34604SSean Bruno 4480b34604SSean Bruno for (i = 0; i < (uint32_t)arg2; i++) { 4580b34604SSean Bruno gemu_log("%d ", tswap32(*p++)); 4680b34604SSean Bruno } 4780b34604SSean Bruno unlock_user(namep, arg1, 0); 4880b34604SSean Bruno } 4980b34604SSean Bruno gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x" 5080b34604SSean Bruno TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")", 5180b34604SSean Bruno (uint32_t)arg2, arg3, arg4, arg5, arg6); 5280b34604SSean Bruno } 5380b34604SSean Bruno 5488dae46dSSean Bruno static void print_execve(const struct syscallname *name, abi_long arg1, 5588dae46dSSean Bruno abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, 5688dae46dSSean Bruno abi_long arg6) 5784778508Sblueswir1 { 5884778508Sblueswir1 abi_ulong arg_ptr_addr; 5984778508Sblueswir1 char *s; 6084778508Sblueswir1 6188dae46dSSean Bruno s = lock_user_string(arg1); 6288dae46dSSean Bruno if (s == NULL) { 6384778508Sblueswir1 return; 6488dae46dSSean Bruno } 6584778508Sblueswir1 gemu_log("%s(\"%s\",{", name->name, s); 6684778508Sblueswir1 unlock_user(s, arg1, 0); 6784778508Sblueswir1 6884778508Sblueswir1 for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { 6918c9a9c3SChristoph Egger abi_ulong *arg_ptr, arg_addr; 7084778508Sblueswir1 7184778508Sblueswir1 arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); 7288dae46dSSean Bruno if (!arg_ptr) { 7384778508Sblueswir1 return; 7488dae46dSSean Bruno } 7584778508Sblueswir1 arg_addr = tswapl(*arg_ptr); 7684778508Sblueswir1 unlock_user(arg_ptr, arg_ptr_addr, 0); 7788dae46dSSean Bruno if (!arg_addr) { 7884778508Sblueswir1 break; 7988dae46dSSean Bruno } 8084778508Sblueswir1 if ((s = lock_user_string(arg_addr))) { 8184778508Sblueswir1 gemu_log("\"%s\",", s); 8218c9a9c3SChristoph Egger unlock_user(s, arg_addr, 0); 8384778508Sblueswir1 } 8484778508Sblueswir1 } 8584778508Sblueswir1 gemu_log("NULL})"); 8684778508Sblueswir1 } 8784778508Sblueswir1 88b85159a3SSean Bruno static void print_ioctl(const struct syscallname *name, 89b85159a3SSean Bruno abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, 90b85159a3SSean Bruno abi_long arg5, abi_long arg6) 91b85159a3SSean Bruno { 92b85159a3SSean Bruno /* Decode the ioctl request */ 93b85159a3SSean Bruno gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x" 94b85159a3SSean Bruno TARGET_ABI_FMT_lx ", ...)", 95b85159a3SSean Bruno name->name, 96b85159a3SSean Bruno (int)arg1, 97b85159a3SSean Bruno (unsigned long)arg2, 98b85159a3SSean Bruno arg2 & IOC_OUT ? "R" : "", 99b85159a3SSean Bruno arg2 & IOC_IN ? "W" : "", 100b85159a3SSean Bruno (unsigned)IOCGROUP(arg2), 101b85159a3SSean Bruno isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?', 102b85159a3SSean Bruno (int)arg2 & 0xFF, 103b85159a3SSean Bruno (int)IOCPARM_LEN(arg2), 104b85159a3SSean Bruno arg3); 105b85159a3SSean Bruno } 106b85159a3SSean Bruno 10784778508Sblueswir1 /* 10884778508Sblueswir1 * Variants for the return value output function 10984778508Sblueswir1 */ 11084778508Sblueswir1 11188dae46dSSean Bruno static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret) 11284778508Sblueswir1 { 11384778508Sblueswir1 if (ret == -1) { 11484778508Sblueswir1 gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno)); 11584778508Sblueswir1 } else { 11684778508Sblueswir1 gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); 11784778508Sblueswir1 } 11884778508Sblueswir1 } 11984778508Sblueswir1 12084778508Sblueswir1 #if 0 /* currently unused */ 12184778508Sblueswir1 static void 12284778508Sblueswir1 print_syscall_ret_raw(struct syscallname *name, abi_long ret) 12384778508Sblueswir1 { 12484778508Sblueswir1 gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); 12584778508Sblueswir1 } 12684778508Sblueswir1 #endif 12784778508Sblueswir1 12884778508Sblueswir1 /* 12984778508Sblueswir1 * An array of all of the syscalls we know about 13084778508Sblueswir1 */ 13184778508Sblueswir1 13284778508Sblueswir1 static const struct syscallname freebsd_scnames[] = { 13384778508Sblueswir1 #include "freebsd/strace.list" 13484778508Sblueswir1 }; 13584778508Sblueswir1 static const struct syscallname netbsd_scnames[] = { 13684778508Sblueswir1 #include "netbsd/strace.list" 13784778508Sblueswir1 }; 13884778508Sblueswir1 static const struct syscallname openbsd_scnames[] = { 13984778508Sblueswir1 #include "openbsd/strace.list" 14084778508Sblueswir1 }; 14184778508Sblueswir1 14288dae46dSSean Bruno static void print_syscall(int num, const struct syscallname *scnames, 14388dae46dSSean Bruno unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3, 14484778508Sblueswir1 abi_long arg4, abi_long arg5, abi_long arg6) 14584778508Sblueswir1 { 14684778508Sblueswir1 unsigned int i; 14784778508Sblueswir1 const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," 14884778508Sblueswir1 TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," 14984778508Sblueswir1 TARGET_ABI_FMT_ld ")"; 15084778508Sblueswir1 15184778508Sblueswir1 gemu_log("%d ", getpid() ); 15284778508Sblueswir1 15388dae46dSSean Bruno for (i = 0; i < nscnames; i++) { 15484778508Sblueswir1 if (scnames[i].nr == num) { 15584778508Sblueswir1 if (scnames[i].call != NULL) { 15684778508Sblueswir1 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5, 15784778508Sblueswir1 arg6); 15884778508Sblueswir1 } else { 15984778508Sblueswir1 /* XXX: this format system is broken because it uses 16084778508Sblueswir1 host types and host pointers for strings */ 16188dae46dSSean Bruno if (scnames[i].format != NULL) { 16284778508Sblueswir1 format = scnames[i].format; 16388dae46dSSean Bruno } 16488dae46dSSean Bruno gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5, 16588dae46dSSean Bruno arg6); 16684778508Sblueswir1 } 16784778508Sblueswir1 return; 16884778508Sblueswir1 } 16988dae46dSSean Bruno } 17084778508Sblueswir1 gemu_log("Unknown syscall %d\n", num); 17184778508Sblueswir1 } 17284778508Sblueswir1 17388dae46dSSean Bruno static void print_syscall_ret(int num, abi_long ret, 17488dae46dSSean Bruno const struct syscallname *scnames, unsigned int nscnames) 17584778508Sblueswir1 { 17684778508Sblueswir1 unsigned int i; 17784778508Sblueswir1 17888dae46dSSean Bruno for (i = 0; i < nscnames; i++) { 17984778508Sblueswir1 if (scnames[i].nr == num) { 18084778508Sblueswir1 if (scnames[i].result != NULL) { 18184778508Sblueswir1 scnames[i].result(&scnames[i], ret); 18284778508Sblueswir1 } else { 18384778508Sblueswir1 if (ret < 0) { 18484778508Sblueswir1 gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, 18584778508Sblueswir1 strerror(-ret)); 18684778508Sblueswir1 } else { 18784778508Sblueswir1 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); 18884778508Sblueswir1 } 18984778508Sblueswir1 } 19084778508Sblueswir1 break; 19184778508Sblueswir1 } 19284778508Sblueswir1 } 19388dae46dSSean Bruno } 19484778508Sblueswir1 19584778508Sblueswir1 /* 19684778508Sblueswir1 * The public interface to this module. 19784778508Sblueswir1 */ 19888dae46dSSean Bruno void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, 19984778508Sblueswir1 abi_long arg4, abi_long arg5, abi_long arg6) 20084778508Sblueswir1 { 20188dae46dSSean Bruno 20288dae46dSSean Bruno print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2, 20388dae46dSSean Bruno arg3, arg4, arg5, arg6); 20484778508Sblueswir1 } 20584778508Sblueswir1 20688dae46dSSean Bruno void print_freebsd_syscall_ret(int num, abi_long ret) 20784778508Sblueswir1 { 20888dae46dSSean Bruno 20984778508Sblueswir1 print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames)); 21084778508Sblueswir1 } 21184778508Sblueswir1 21288dae46dSSean Bruno void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, 21384778508Sblueswir1 abi_long arg4, abi_long arg5, abi_long arg6) 21484778508Sblueswir1 { 21588dae46dSSean Bruno 21684778508Sblueswir1 print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames), 21784778508Sblueswir1 arg1, arg2, arg3, arg4, arg5, arg6); 21884778508Sblueswir1 } 21984778508Sblueswir1 22088dae46dSSean Bruno void print_netbsd_syscall_ret(int num, abi_long ret) 22184778508Sblueswir1 { 22288dae46dSSean Bruno 22384778508Sblueswir1 print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames)); 22484778508Sblueswir1 } 22584778508Sblueswir1 22688dae46dSSean Bruno void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, 22784778508Sblueswir1 abi_long arg4, abi_long arg5, abi_long arg6) 22884778508Sblueswir1 { 22988dae46dSSean Bruno 23088dae46dSSean Bruno print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2, 23188dae46dSSean Bruno arg3, arg4, arg5, arg6); 23284778508Sblueswir1 } 23384778508Sblueswir1 23488dae46dSSean Bruno void print_openbsd_syscall_ret(int num, abi_long ret) 23584778508Sblueswir1 { 23688dae46dSSean Bruno 23784778508Sblueswir1 print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames)); 23884778508Sblueswir1 } 239