xref: /openbmc/qemu/bsd-user/strace.c (revision 48e438a3)
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"
2584778508Sblueswir1 
26ea1ab4cfSStacey Son #include "os-strace.h"  /* OS dependent strace print functions */
27ea1ab4cfSStacey Son 
2888dae46dSSean Bruno int do_strace;
2984778508Sblueswir1 
3084778508Sblueswir1 /*
3184778508Sblueswir1  * Utility functions
3284778508Sblueswir1  */
33*fd5bec9aSWarner Losh static const char *
get_comma(int last)34*fd5bec9aSWarner Losh get_comma(int last)
35*fd5bec9aSWarner Losh {
36*fd5bec9aSWarner Losh     return (last) ? "" : ",";
37*fd5bec9aSWarner Losh }
38*fd5bec9aSWarner Losh 
39*fd5bec9aSWarner Losh /*
40*fd5bec9aSWarner Losh  * Prints out raw parameter using given format.  Caller needs
41*fd5bec9aSWarner Losh  * to do byte swapping if needed.
42*fd5bec9aSWarner Losh  */
43*fd5bec9aSWarner Losh static void
print_raw_param(const char * fmt,abi_long param,int last)44*fd5bec9aSWarner Losh print_raw_param(const char *fmt, abi_long param, int last)
45*fd5bec9aSWarner Losh {
46*fd5bec9aSWarner Losh     char format[64];
47*fd5bec9aSWarner Losh 
48*fd5bec9aSWarner Losh     (void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last));
49*fd5bec9aSWarner Losh     gemu_log(format, param);
50*fd5bec9aSWarner Losh }
5184778508Sblueswir1 
print_sysctl(const struct syscallname * name,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)5280b34604SSean Bruno static void print_sysctl(const struct syscallname *name, abi_long arg1,
5380b34604SSean Bruno         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
5480b34604SSean Bruno         abi_long arg6)
5580b34604SSean Bruno {
5680b34604SSean Bruno     uint32_t i;
5780b34604SSean Bruno     int32_t *namep;
5880b34604SSean Bruno 
5980b34604SSean Bruno     gemu_log("%s({ ", name->name);
6080b34604SSean Bruno     namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
6180b34604SSean Bruno     if (namep) {
6280b34604SSean Bruno         int32_t *p = namep;
6380b34604SSean Bruno 
6480b34604SSean Bruno         for (i = 0; i < (uint32_t)arg2; i++) {
6580b34604SSean Bruno             gemu_log("%d ", tswap32(*p++));
6680b34604SSean Bruno         }
6780b34604SSean Bruno         unlock_user(namep, arg1, 0);
6880b34604SSean Bruno     }
6980b34604SSean Bruno     gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
7080b34604SSean Bruno         TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
7180b34604SSean Bruno         (uint32_t)arg2, arg3, arg4, arg5, arg6);
7280b34604SSean Bruno }
7380b34604SSean 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)7488dae46dSSean Bruno static void print_execve(const struct syscallname *name, abi_long arg1,
7588dae46dSSean Bruno         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
7688dae46dSSean Bruno         abi_long arg6)
7784778508Sblueswir1 {
7884778508Sblueswir1     abi_ulong arg_ptr_addr;
7984778508Sblueswir1     char *s;
8084778508Sblueswir1 
8188dae46dSSean Bruno     s = lock_user_string(arg1);
8288dae46dSSean Bruno     if (s == NULL) {
8384778508Sblueswir1         return;
8488dae46dSSean Bruno     }
8584778508Sblueswir1     gemu_log("%s(\"%s\",{", name->name, s);
8684778508Sblueswir1     unlock_user(s, arg1, 0);
8784778508Sblueswir1 
8884778508Sblueswir1     for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
8918c9a9c3SChristoph Egger         abi_ulong *arg_ptr, arg_addr;
9084778508Sblueswir1 
9184778508Sblueswir1         arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
9288dae46dSSean Bruno         if (!arg_ptr) {
9384778508Sblueswir1             return;
9488dae46dSSean Bruno         }
9584778508Sblueswir1         arg_addr = tswapl(*arg_ptr);
9684778508Sblueswir1         unlock_user(arg_ptr, arg_ptr_addr, 0);
9788dae46dSSean Bruno         if (!arg_addr) {
9884778508Sblueswir1             break;
9988dae46dSSean Bruno         }
10084778508Sblueswir1         if ((s = lock_user_string(arg_addr))) {
10184778508Sblueswir1             gemu_log("\"%s\",", s);
10218c9a9c3SChristoph Egger             unlock_user(s, arg_addr, 0);
10384778508Sblueswir1         }
10484778508Sblueswir1     }
10584778508Sblueswir1     gemu_log("NULL})");
10684778508Sblueswir1 }
10784778508Sblueswir1 
print_ioctl(const struct syscallname * name,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)108b85159a3SSean Bruno static void print_ioctl(const struct syscallname *name,
109b85159a3SSean Bruno         abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
110b85159a3SSean Bruno         abi_long arg5, abi_long arg6)
111b85159a3SSean Bruno {
112b85159a3SSean Bruno     /* Decode the ioctl request */
113b85159a3SSean Bruno     gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
114b85159a3SSean Bruno             TARGET_ABI_FMT_lx ", ...)",
115b85159a3SSean Bruno             name->name,
116b85159a3SSean Bruno             (int)arg1,
117b85159a3SSean Bruno             (unsigned long)arg2,
118b85159a3SSean Bruno             arg2 & IOC_OUT ? "R" : "",
119b85159a3SSean Bruno             arg2 & IOC_IN ? "W" : "",
120b85159a3SSean Bruno             (unsigned)IOCGROUP(arg2),
121b85159a3SSean Bruno             isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
122b85159a3SSean Bruno             (int)arg2 & 0xFF,
123b85159a3SSean Bruno             (int)IOCPARM_LEN(arg2),
124b85159a3SSean Bruno             arg3);
125b85159a3SSean Bruno }
126b85159a3SSean 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)127ea1ab4cfSStacey Son static void print_sysarch(const struct syscallname *name, abi_long arg1,
128ea1ab4cfSStacey Son         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
129ea1ab4cfSStacey Son         abi_long arg6)
130ea1ab4cfSStacey Son {
131ea1ab4cfSStacey Son     /* This is os dependent. */
132ea1ab4cfSStacey Son     do_os_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
133ea1ab4cfSStacey Son }
134ea1ab4cfSStacey Son 
13584778508Sblueswir1 /*
13684778508Sblueswir1  * Variants for the return value output function
13784778508Sblueswir1  */
13884778508Sblueswir1 
print_syscall_ret_addr(const struct syscallname * name,abi_long ret)13988dae46dSSean Bruno static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
14084778508Sblueswir1 {
14184778508Sblueswir1     if (ret == -1) {
14284778508Sblueswir1         gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
14384778508Sblueswir1     } else {
14484778508Sblueswir1         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
14584778508Sblueswir1     }
14684778508Sblueswir1 }
14784778508Sblueswir1 
14884778508Sblueswir1 /*
14984778508Sblueswir1  * An array of all of the syscalls we know about
15084778508Sblueswir1  */
15184778508Sblueswir1 
15284778508Sblueswir1 static const struct syscallname freebsd_scnames[] = {
15384778508Sblueswir1 #include "freebsd/strace.list"
15484778508Sblueswir1 };
15584778508Sblueswir1 static const struct syscallname netbsd_scnames[] = {
15684778508Sblueswir1 #include "netbsd/strace.list"
15784778508Sblueswir1 };
15884778508Sblueswir1 static const struct syscallname openbsd_scnames[] = {
15984778508Sblueswir1 #include "openbsd/strace.list"
16084778508Sblueswir1 };
16184778508Sblueswir1 
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)16288dae46dSSean Bruno static void print_syscall(int num, const struct syscallname *scnames,
16388dae46dSSean Bruno         unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
16484778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
16584778508Sblueswir1 {
16684778508Sblueswir1     unsigned int i;
16784778508Sblueswir1     const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
16884778508Sblueswir1         TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
16984778508Sblueswir1         TARGET_ABI_FMT_ld ")";
17084778508Sblueswir1 
17184778508Sblueswir1     gemu_log("%d ", getpid() );
17284778508Sblueswir1 
17388dae46dSSean Bruno     for (i = 0; i < nscnames; i++) {
17484778508Sblueswir1         if (scnames[i].nr == num) {
17584778508Sblueswir1             if (scnames[i].call != NULL) {
17684778508Sblueswir1                 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
17784778508Sblueswir1                         arg6);
17884778508Sblueswir1             } else {
17984778508Sblueswir1                 /* XXX: this format system is broken because it uses
18084778508Sblueswir1                    host types and host pointers for strings */
18188dae46dSSean Bruno                 if (scnames[i].format != NULL) {
18284778508Sblueswir1                     format = scnames[i].format;
18388dae46dSSean Bruno                 }
18488dae46dSSean Bruno                 gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
18588dae46dSSean Bruno                         arg6);
18684778508Sblueswir1             }
18784778508Sblueswir1             return;
18884778508Sblueswir1         }
18988dae46dSSean Bruno     }
19084778508Sblueswir1     gemu_log("Unknown syscall %d\n", num);
19184778508Sblueswir1 }
19284778508Sblueswir1 
print_syscall_ret(int num,abi_long ret,const struct syscallname * scnames,unsigned int nscnames)19388dae46dSSean Bruno static void print_syscall_ret(int num, abi_long ret,
19488dae46dSSean Bruno         const struct syscallname *scnames, unsigned int nscnames)
19584778508Sblueswir1 {
19684778508Sblueswir1     unsigned int i;
19784778508Sblueswir1 
19888dae46dSSean Bruno     for (i = 0; i < nscnames; i++) {
19984778508Sblueswir1         if (scnames[i].nr == num) {
20084778508Sblueswir1             if (scnames[i].result != NULL) {
20184778508Sblueswir1                 scnames[i].result(&scnames[i], ret);
20284778508Sblueswir1             } else {
20384778508Sblueswir1                 if (ret < 0) {
20484778508Sblueswir1                     gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
20584778508Sblueswir1                              strerror(-ret));
20684778508Sblueswir1                 } else {
20784778508Sblueswir1                     gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
20884778508Sblueswir1                 }
20984778508Sblueswir1             }
21084778508Sblueswir1             break;
21184778508Sblueswir1         }
21284778508Sblueswir1     }
21388dae46dSSean Bruno }
21484778508Sblueswir1 
21584778508Sblueswir1 /*
21684778508Sblueswir1  * The public interface to this module.
21784778508Sblueswir1  */
print_freebsd_syscall(int num,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)21888dae46dSSean Bruno void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
21984778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
22084778508Sblueswir1 {
22188dae46dSSean Bruno 
22288dae46dSSean Bruno     print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
22388dae46dSSean Bruno             arg3, arg4, arg5, arg6);
22484778508Sblueswir1 }
22584778508Sblueswir1 
print_freebsd_syscall_ret(int num,abi_long ret)22688dae46dSSean Bruno void print_freebsd_syscall_ret(int num, abi_long ret)
22784778508Sblueswir1 {
22888dae46dSSean Bruno 
22984778508Sblueswir1     print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
23084778508Sblueswir1 }
23184778508Sblueswir1 
print_netbsd_syscall(int num,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)23288dae46dSSean Bruno void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
23384778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
23484778508Sblueswir1 {
23588dae46dSSean Bruno 
23684778508Sblueswir1     print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
23784778508Sblueswir1                   arg1, arg2, arg3, arg4, arg5, arg6);
23884778508Sblueswir1 }
23984778508Sblueswir1 
print_netbsd_syscall_ret(int num,abi_long ret)24088dae46dSSean Bruno void print_netbsd_syscall_ret(int num, abi_long ret)
24184778508Sblueswir1 {
24288dae46dSSean Bruno 
24384778508Sblueswir1     print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
24484778508Sblueswir1 }
24584778508Sblueswir1 
print_openbsd_syscall(int num,abi_long arg1,abi_long arg2,abi_long arg3,abi_long arg4,abi_long arg5,abi_long arg6)24688dae46dSSean Bruno void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
24784778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
24884778508Sblueswir1 {
24988dae46dSSean Bruno 
25088dae46dSSean Bruno     print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
25188dae46dSSean Bruno             arg3, arg4, arg5, arg6);
25284778508Sblueswir1 }
25384778508Sblueswir1 
print_openbsd_syscall_ret(int num,abi_long ret)25488dae46dSSean Bruno void print_openbsd_syscall_ret(int num, abi_long ret)
25584778508Sblueswir1 {
25688dae46dSSean Bruno 
25784778508Sblueswir1     print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
25884778508Sblueswir1 }
259*fd5bec9aSWarner Losh 
260*fd5bec9aSWarner Losh static void
print_signal(abi_ulong arg,int last)261*fd5bec9aSWarner Losh print_signal(abi_ulong arg, int last)
262*fd5bec9aSWarner Losh {
263*fd5bec9aSWarner Losh     const char *signal_name = NULL;
264*fd5bec9aSWarner Losh     switch (arg) {
265*fd5bec9aSWarner Losh     case TARGET_SIGHUP:
266*fd5bec9aSWarner Losh         signal_name = "SIGHUP";
267*fd5bec9aSWarner Losh         break;
268*fd5bec9aSWarner Losh     case TARGET_SIGINT:
269*fd5bec9aSWarner Losh         signal_name = "SIGINT";
270*fd5bec9aSWarner Losh         break;
271*fd5bec9aSWarner Losh     case TARGET_SIGQUIT:
272*fd5bec9aSWarner Losh         signal_name = "SIGQUIT";
273*fd5bec9aSWarner Losh         break;
274*fd5bec9aSWarner Losh     case TARGET_SIGILL:
275*fd5bec9aSWarner Losh         signal_name = "SIGILL";
276*fd5bec9aSWarner Losh         break;
277*fd5bec9aSWarner Losh     case TARGET_SIGABRT:
278*fd5bec9aSWarner Losh         signal_name = "SIGABRT";
279*fd5bec9aSWarner Losh         break;
280*fd5bec9aSWarner Losh     case TARGET_SIGFPE:
281*fd5bec9aSWarner Losh         signal_name = "SIGFPE";
282*fd5bec9aSWarner Losh         break;
283*fd5bec9aSWarner Losh     case TARGET_SIGKILL:
284*fd5bec9aSWarner Losh         signal_name = "SIGKILL";
285*fd5bec9aSWarner Losh         break;
286*fd5bec9aSWarner Losh     case TARGET_SIGSEGV:
287*fd5bec9aSWarner Losh         signal_name = "SIGSEGV";
288*fd5bec9aSWarner Losh         break;
289*fd5bec9aSWarner Losh     case TARGET_SIGPIPE:
290*fd5bec9aSWarner Losh         signal_name = "SIGPIPE";
291*fd5bec9aSWarner Losh         break;
292*fd5bec9aSWarner Losh     case TARGET_SIGALRM:
293*fd5bec9aSWarner Losh         signal_name = "SIGALRM";
294*fd5bec9aSWarner Losh         break;
295*fd5bec9aSWarner Losh     case TARGET_SIGTERM:
296*fd5bec9aSWarner Losh         signal_name = "SIGTERM";
297*fd5bec9aSWarner Losh         break;
298*fd5bec9aSWarner Losh     case TARGET_SIGUSR1:
299*fd5bec9aSWarner Losh         signal_name = "SIGUSR1";
300*fd5bec9aSWarner Losh         break;
301*fd5bec9aSWarner Losh     case TARGET_SIGUSR2:
302*fd5bec9aSWarner Losh         signal_name = "SIGUSR2";
303*fd5bec9aSWarner Losh         break;
304*fd5bec9aSWarner Losh     case TARGET_SIGCHLD:
305*fd5bec9aSWarner Losh         signal_name = "SIGCHLD";
306*fd5bec9aSWarner Losh         break;
307*fd5bec9aSWarner Losh     case TARGET_SIGCONT:
308*fd5bec9aSWarner Losh         signal_name = "SIGCONT";
309*fd5bec9aSWarner Losh         break;
310*fd5bec9aSWarner Losh     case TARGET_SIGSTOP:
311*fd5bec9aSWarner Losh         signal_name = "SIGSTOP";
312*fd5bec9aSWarner Losh         break;
313*fd5bec9aSWarner Losh     case TARGET_SIGTTIN:
314*fd5bec9aSWarner Losh         signal_name = "SIGTTIN";
315*fd5bec9aSWarner Losh         break;
316*fd5bec9aSWarner Losh     case TARGET_SIGTTOU:
317*fd5bec9aSWarner Losh         signal_name = "SIGTTOU";
318*fd5bec9aSWarner Losh         break;
319*fd5bec9aSWarner Losh     }
320*fd5bec9aSWarner Losh     if (signal_name == NULL) {
321*fd5bec9aSWarner Losh         print_raw_param("%ld", arg, last);
322*fd5bec9aSWarner Losh         return;
323*fd5bec9aSWarner Losh     }
324*fd5bec9aSWarner Losh     gemu_log("%s%s", signal_name, get_comma(last));
325*fd5bec9aSWarner Losh }
326*fd5bec9aSWarner Losh 
print_taken_signal(int target_signum,const target_siginfo_t * tinfo)327*fd5bec9aSWarner Losh void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
328*fd5bec9aSWarner Losh {
329*fd5bec9aSWarner Losh     /*
330*fd5bec9aSWarner Losh      * Print the strace output for a signal being taken:
331*fd5bec9aSWarner Losh      * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
332*fd5bec9aSWarner Losh      */
333*fd5bec9aSWarner Losh     gemu_log("%d ", getpid());
334*fd5bec9aSWarner Losh     gemu_log("--- ");
335*fd5bec9aSWarner Losh     print_signal(target_signum, 1);
336*fd5bec9aSWarner Losh     gemu_log(" ---\n");
337*fd5bec9aSWarner Losh }
338