xref: /qemu/bsd-user/strace.c (revision 2231197c87337a9778e0b2000b1ecb7d33c774b3)
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