xref: /qemu/bsd-user/strace.c (revision 82723866)
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 
192231197cSPeter 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"
2582723866SPhilippe Mathieu-Daudé #include "user/tswap-target.h"
2684778508Sblueswir1 
27ea1ab4cfSStacey Son #include "os-strace.h"  /* OS dependent strace print functions */
28ea1ab4cfSStacey Son 
2988dae46dSSean Bruno int do_strace;
3084778508Sblueswir1 
3184778508Sblueswir1 /*
3284778508Sblueswir1  * Utility functions
3384778508Sblueswir1  */
34fd5bec9aSWarner Losh static const char *
get_comma(int last)35fd5bec9aSWarner Losh get_comma(int last)
36fd5bec9aSWarner Losh {
37fd5bec9aSWarner Losh     return (last) ? "" : ",";
38fd5bec9aSWarner Losh }
39fd5bec9aSWarner Losh 
40fd5bec9aSWarner Losh /*
41fd5bec9aSWarner Losh  * Prints out raw parameter using given format.  Caller needs
42fd5bec9aSWarner Losh  * to do byte swapping if needed.
43fd5bec9aSWarner Losh  */
44fd5bec9aSWarner Losh static void
print_raw_param(const char * fmt,abi_long param,int last)45fd5bec9aSWarner Losh print_raw_param(const char *fmt, abi_long param, int last)
46fd5bec9aSWarner Losh {
47fd5bec9aSWarner Losh     char format[64];
48fd5bec9aSWarner Losh 
49fd5bec9aSWarner Losh     (void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last));
50fd5bec9aSWarner Losh     gemu_log(format, param);
51fd5bec9aSWarner Losh }
5284778508Sblueswir1 
print_sysctl(const struct syscallname * name,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)5380b34604SSean Bruno static void print_sysctl(const struct syscallname *name, abi_long arg1,
5480b34604SSean Bruno         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
5580b34604SSean Bruno         abi_long arg6)
5680b34604SSean Bruno {
5780b34604SSean Bruno     uint32_t i;
5880b34604SSean Bruno     int32_t *namep;
5980b34604SSean Bruno 
6080b34604SSean Bruno     gemu_log("%s({ ", name->name);
6180b34604SSean Bruno     namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
6280b34604SSean Bruno     if (namep) {
6380b34604SSean Bruno         int32_t *p = namep;
6480b34604SSean Bruno 
6580b34604SSean Bruno         for (i = 0; i < (uint32_t)arg2; i++) {
6680b34604SSean Bruno             gemu_log("%d ", tswap32(*p++));
6780b34604SSean Bruno         }
6880b34604SSean Bruno         unlock_user(namep, arg1, 0);
6980b34604SSean Bruno     }
7080b34604SSean Bruno     gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
7180b34604SSean Bruno         TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
7280b34604SSean Bruno         (uint32_t)arg2, arg3, arg4, arg5, arg6);
7380b34604SSean Bruno }
7480b34604SSean Bruno 
print_execve(const struct syscallname * name,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)7588dae46dSSean Bruno static void print_execve(const struct syscallname *name, abi_long arg1,
7688dae46dSSean Bruno         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
7788dae46dSSean Bruno         abi_long arg6)
7884778508Sblueswir1 {
7984778508Sblueswir1     abi_ulong arg_ptr_addr;
8084778508Sblueswir1     char *s;
8184778508Sblueswir1 
8288dae46dSSean Bruno     s = lock_user_string(arg1);
8388dae46dSSean Bruno     if (s == NULL) {
8484778508Sblueswir1         return;
8588dae46dSSean Bruno     }
8684778508Sblueswir1     gemu_log("%s(\"%s\",{", name->name, s);
8784778508Sblueswir1     unlock_user(s, arg1, 0);
8884778508Sblueswir1 
8984778508Sblueswir1     for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
9018c9a9c3SChristoph Egger         abi_ulong *arg_ptr, arg_addr;
9184778508Sblueswir1 
9284778508Sblueswir1         arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
9388dae46dSSean Bruno         if (!arg_ptr) {
9484778508Sblueswir1             return;
9588dae46dSSean Bruno         }
9684778508Sblueswir1         arg_addr = tswapl(*arg_ptr);
9784778508Sblueswir1         unlock_user(arg_ptr, arg_ptr_addr, 0);
9888dae46dSSean Bruno         if (!arg_addr) {
9984778508Sblueswir1             break;
10088dae46dSSean Bruno         }
10184778508Sblueswir1         if ((s = lock_user_string(arg_addr))) {
10284778508Sblueswir1             gemu_log("\"%s\",", s);
10318c9a9c3SChristoph Egger             unlock_user(s, arg_addr, 0);
10484778508Sblueswir1         }
10584778508Sblueswir1     }
10684778508Sblueswir1     gemu_log("NULL})");
10784778508Sblueswir1 }
10884778508Sblueswir1 
print_ioctl(const struct syscallname * name,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)109b85159a3SSean Bruno static void print_ioctl(const struct syscallname *name,
110b85159a3SSean Bruno         abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
111b85159a3SSean Bruno         abi_long arg5, abi_long arg6)
112b85159a3SSean Bruno {
113b85159a3SSean Bruno     /* Decode the ioctl request */
114b85159a3SSean Bruno     gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
115b85159a3SSean Bruno             TARGET_ABI_FMT_lx ", ...)",
116b85159a3SSean Bruno             name->name,
117b85159a3SSean Bruno             (int)arg1,
118b85159a3SSean Bruno             (unsigned long)arg2,
119b85159a3SSean Bruno             arg2 & IOC_OUT ? "R" : "",
120b85159a3SSean Bruno             arg2 & IOC_IN ? "W" : "",
121b85159a3SSean Bruno             (unsigned)IOCGROUP(arg2),
122b85159a3SSean Bruno             isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
123b85159a3SSean Bruno             (int)arg2 & 0xFF,
124b85159a3SSean Bruno             (int)IOCPARM_LEN(arg2),
125b85159a3SSean Bruno             arg3);
126b85159a3SSean Bruno }
127b85159a3SSean Bruno 
print_sysarch(const struct syscallname * name,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)128ea1ab4cfSStacey Son static void print_sysarch(const struct syscallname *name, abi_long arg1,
129ea1ab4cfSStacey Son         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
130ea1ab4cfSStacey Son         abi_long arg6)
131ea1ab4cfSStacey Son {
132ea1ab4cfSStacey Son     /* This is os dependent. */
133ea1ab4cfSStacey Son     do_os_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
134ea1ab4cfSStacey Son }
135ea1ab4cfSStacey Son 
13684778508Sblueswir1 /*
13784778508Sblueswir1  * Variants for the return value output function
13884778508Sblueswir1  */
13984778508Sblueswir1 
print_syscall_ret_addr(const struct syscallname * name,abi_long ret)14088dae46dSSean Bruno static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
14184778508Sblueswir1 {
14284778508Sblueswir1     if (ret == -1) {
14384778508Sblueswir1         gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
14484778508Sblueswir1     } else {
14584778508Sblueswir1         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
14684778508Sblueswir1     }
14784778508Sblueswir1 }
14884778508Sblueswir1 
14984778508Sblueswir1 /*
15084778508Sblueswir1  * An array of all of the syscalls we know about
15184778508Sblueswir1  */
15284778508Sblueswir1 
15384778508Sblueswir1 static const struct syscallname freebsd_scnames[] = {
15484778508Sblueswir1 #include "freebsd/strace.list"
15584778508Sblueswir1 };
15684778508Sblueswir1 static const struct syscallname netbsd_scnames[] = {
15784778508Sblueswir1 #include "netbsd/strace.list"
15884778508Sblueswir1 };
15984778508Sblueswir1 static const struct syscallname openbsd_scnames[] = {
16084778508Sblueswir1 #include "openbsd/strace.list"
16184778508Sblueswir1 };
16284778508Sblueswir1 
print_syscall(int num,const struct syscallname * scnames,unsigned int nscnames,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)16388dae46dSSean Bruno static void print_syscall(int num, const struct syscallname *scnames,
16488dae46dSSean Bruno         unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
16584778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
16684778508Sblueswir1 {
16784778508Sblueswir1     unsigned int i;
16884778508Sblueswir1     const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
16984778508Sblueswir1         TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
17084778508Sblueswir1         TARGET_ABI_FMT_ld ")";
17184778508Sblueswir1 
17284778508Sblueswir1     gemu_log("%d ", getpid() );
17384778508Sblueswir1 
17488dae46dSSean Bruno     for (i = 0; i < nscnames; i++) {
17584778508Sblueswir1         if (scnames[i].nr == num) {
17684778508Sblueswir1             if (scnames[i].call != NULL) {
17784778508Sblueswir1                 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
17884778508Sblueswir1                         arg6);
17984778508Sblueswir1             } else {
18084778508Sblueswir1                 /* XXX: this format system is broken because it uses
18184778508Sblueswir1                    host types and host pointers for strings */
18288dae46dSSean Bruno                 if (scnames[i].format != NULL) {
18384778508Sblueswir1                     format = scnames[i].format;
18488dae46dSSean Bruno                 }
18588dae46dSSean Bruno                 gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
18688dae46dSSean Bruno                         arg6);
18784778508Sblueswir1             }
18884778508Sblueswir1             return;
18984778508Sblueswir1         }
19088dae46dSSean Bruno     }
19184778508Sblueswir1     gemu_log("Unknown syscall %d\n", num);
19284778508Sblueswir1 }
19384778508Sblueswir1 
print_syscall_ret(int num,abi_long ret,const struct syscallname * scnames,unsigned int nscnames)19488dae46dSSean Bruno static void print_syscall_ret(int num, abi_long ret,
19588dae46dSSean Bruno         const struct syscallname *scnames, unsigned int nscnames)
19684778508Sblueswir1 {
19784778508Sblueswir1     unsigned int i;
19884778508Sblueswir1 
19988dae46dSSean Bruno     for (i = 0; i < nscnames; i++) {
20084778508Sblueswir1         if (scnames[i].nr == num) {
20184778508Sblueswir1             if (scnames[i].result != NULL) {
20284778508Sblueswir1                 scnames[i].result(&scnames[i], ret);
20384778508Sblueswir1             } else {
20484778508Sblueswir1                 if (ret < 0) {
20584778508Sblueswir1                     gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
20684778508Sblueswir1                              strerror(-ret));
20784778508Sblueswir1                 } else {
20884778508Sblueswir1                     gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
20984778508Sblueswir1                 }
21084778508Sblueswir1             }
21184778508Sblueswir1             break;
21284778508Sblueswir1         }
21384778508Sblueswir1     }
21488dae46dSSean Bruno }
21584778508Sblueswir1 
21684778508Sblueswir1 /*
21784778508Sblueswir1  * The public interface to this module.
21884778508Sblueswir1  */
print_freebsd_syscall(int num,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)21988dae46dSSean Bruno void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
22084778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
22184778508Sblueswir1 {
22288dae46dSSean Bruno 
22388dae46dSSean Bruno     print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
22488dae46dSSean Bruno             arg3, arg4, arg5, arg6);
22584778508Sblueswir1 }
22684778508Sblueswir1 
print_freebsd_syscall_ret(int num,abi_long ret)22788dae46dSSean Bruno void print_freebsd_syscall_ret(int num, abi_long ret)
22884778508Sblueswir1 {
22988dae46dSSean Bruno 
23084778508Sblueswir1     print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
23184778508Sblueswir1 }
23284778508Sblueswir1 
print_netbsd_syscall(int num,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)23388dae46dSSean Bruno void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
23484778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
23584778508Sblueswir1 {
23688dae46dSSean Bruno 
23784778508Sblueswir1     print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
23884778508Sblueswir1                   arg1, arg2, arg3, arg4, arg5, arg6);
23984778508Sblueswir1 }
24084778508Sblueswir1 
print_netbsd_syscall_ret(int num,abi_long ret)24188dae46dSSean Bruno void print_netbsd_syscall_ret(int num, abi_long ret)
24284778508Sblueswir1 {
24388dae46dSSean Bruno 
24484778508Sblueswir1     print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
24584778508Sblueswir1 }
24684778508Sblueswir1 
print_openbsd_syscall(int num,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)24788dae46dSSean Bruno void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
24884778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
24984778508Sblueswir1 {
25088dae46dSSean Bruno 
25188dae46dSSean Bruno     print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
25288dae46dSSean Bruno             arg3, arg4, arg5, arg6);
25384778508Sblueswir1 }
25484778508Sblueswir1 
print_openbsd_syscall_ret(int num,abi_long ret)25588dae46dSSean Bruno void print_openbsd_syscall_ret(int num, abi_long ret)
25684778508Sblueswir1 {
25788dae46dSSean Bruno 
25884778508Sblueswir1     print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
25984778508Sblueswir1 }
260fd5bec9aSWarner Losh 
261fd5bec9aSWarner Losh static void
print_signal(abi_ulong arg,int last)262fd5bec9aSWarner Losh print_signal(abi_ulong arg, int last)
263fd5bec9aSWarner Losh {
264fd5bec9aSWarner Losh     const char *signal_name = NULL;
265fd5bec9aSWarner Losh     switch (arg) {
266fd5bec9aSWarner Losh     case TARGET_SIGHUP:
267fd5bec9aSWarner Losh         signal_name = "SIGHUP";
268fd5bec9aSWarner Losh         break;
269fd5bec9aSWarner Losh     case TARGET_SIGINT:
270fd5bec9aSWarner Losh         signal_name = "SIGINT";
271fd5bec9aSWarner Losh         break;
272fd5bec9aSWarner Losh     case TARGET_SIGQUIT:
273fd5bec9aSWarner Losh         signal_name = "SIGQUIT";
274fd5bec9aSWarner Losh         break;
275fd5bec9aSWarner Losh     case TARGET_SIGILL:
276fd5bec9aSWarner Losh         signal_name = "SIGILL";
277fd5bec9aSWarner Losh         break;
278fd5bec9aSWarner Losh     case TARGET_SIGABRT:
279fd5bec9aSWarner Losh         signal_name = "SIGABRT";
280fd5bec9aSWarner Losh         break;
281fd5bec9aSWarner Losh     case TARGET_SIGFPE:
282fd5bec9aSWarner Losh         signal_name = "SIGFPE";
283fd5bec9aSWarner Losh         break;
284fd5bec9aSWarner Losh     case TARGET_SIGKILL:
285fd5bec9aSWarner Losh         signal_name = "SIGKILL";
286fd5bec9aSWarner Losh         break;
287fd5bec9aSWarner Losh     case TARGET_SIGSEGV:
288fd5bec9aSWarner Losh         signal_name = "SIGSEGV";
289fd5bec9aSWarner Losh         break;
290fd5bec9aSWarner Losh     case TARGET_SIGPIPE:
291fd5bec9aSWarner Losh         signal_name = "SIGPIPE";
292fd5bec9aSWarner Losh         break;
293fd5bec9aSWarner Losh     case TARGET_SIGALRM:
294fd5bec9aSWarner Losh         signal_name = "SIGALRM";
295fd5bec9aSWarner Losh         break;
296fd5bec9aSWarner Losh     case TARGET_SIGTERM:
297fd5bec9aSWarner Losh         signal_name = "SIGTERM";
298fd5bec9aSWarner Losh         break;
299fd5bec9aSWarner Losh     case TARGET_SIGUSR1:
300fd5bec9aSWarner Losh         signal_name = "SIGUSR1";
301fd5bec9aSWarner Losh         break;
302fd5bec9aSWarner Losh     case TARGET_SIGUSR2:
303fd5bec9aSWarner Losh         signal_name = "SIGUSR2";
304fd5bec9aSWarner Losh         break;
305fd5bec9aSWarner Losh     case TARGET_SIGCHLD:
306fd5bec9aSWarner Losh         signal_name = "SIGCHLD";
307fd5bec9aSWarner Losh         break;
308fd5bec9aSWarner Losh     case TARGET_SIGCONT:
309fd5bec9aSWarner Losh         signal_name = "SIGCONT";
310fd5bec9aSWarner Losh         break;
311fd5bec9aSWarner Losh     case TARGET_SIGSTOP:
312fd5bec9aSWarner Losh         signal_name = "SIGSTOP";
313fd5bec9aSWarner Losh         break;
314fd5bec9aSWarner Losh     case TARGET_SIGTTIN:
315fd5bec9aSWarner Losh         signal_name = "SIGTTIN";
316fd5bec9aSWarner Losh         break;
317fd5bec9aSWarner Losh     case TARGET_SIGTTOU:
318fd5bec9aSWarner Losh         signal_name = "SIGTTOU";
319fd5bec9aSWarner Losh         break;
320fd5bec9aSWarner Losh     }
321fd5bec9aSWarner Losh     if (signal_name == NULL) {
322fd5bec9aSWarner Losh         print_raw_param("%ld", arg, last);
323fd5bec9aSWarner Losh         return;
324fd5bec9aSWarner Losh     }
325fd5bec9aSWarner Losh     gemu_log("%s%s", signal_name, get_comma(last));
326fd5bec9aSWarner Losh }
327fd5bec9aSWarner Losh 
print_taken_signal(int target_signum,const target_siginfo_t * tinfo)328fd5bec9aSWarner Losh void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
329fd5bec9aSWarner Losh {
330fd5bec9aSWarner Losh     /*
331fd5bec9aSWarner Losh      * Print the strace output for a signal being taken:
332fd5bec9aSWarner Losh      * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
333fd5bec9aSWarner Losh      */
334fd5bec9aSWarner Losh     gemu_log("%d ", getpid());
335fd5bec9aSWarner Losh     gemu_log("--- ");
336fd5bec9aSWarner Losh     print_signal(target_signum, 1);
337fd5bec9aSWarner Losh     gemu_log(" ---\n");
338fd5bec9aSWarner Losh }
339