xref: /qemu/bsd-user/strace.c (revision 88dae46d)
1*88dae46dSSean Bruno /*
2*88dae46dSSean Bruno  *  System call tracing and debugging
3*88dae46dSSean Bruno  *
4*88dae46dSSean Bruno  *
5*88dae46dSSean Bruno  *  This program is free software; you can redistribute it and/or modify
6*88dae46dSSean Bruno  *  it under the terms of the GNU General Public License as published by
7*88dae46dSSean Bruno  *  the Free Software Foundation; either version 2 of the License, or
8*88dae46dSSean Bruno  *  (at your option) any later version.
9*88dae46dSSean Bruno  *
10*88dae46dSSean Bruno  *  This program is distributed in the hope that it will be useful,
11*88dae46dSSean Bruno  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12*88dae46dSSean Bruno  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*88dae46dSSean Bruno  *  GNU General Public License for more details.
14*88dae46dSSean Bruno  *
15*88dae46dSSean Bruno  *  You should have received a copy of the GNU General Public License
16*88dae46dSSean Bruno  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
17*88dae46dSSean Bruno  */
18*88dae46dSSean Bruno 
1984778508Sblueswir1 #include <stdio.h>
2084778508Sblueswir1 #include <errno.h>
2184778508Sblueswir1 #include <sys/select.h>
2284778508Sblueswir1 #include <sys/types.h>
2384778508Sblueswir1 #include <unistd.h>
2484778508Sblueswir1 #include <sys/syscall.h>
25*88dae46dSSean Bruno #include <sys/ioccom.h>
26*88dae46dSSean Bruno #include <ctype.h>
27*88dae46dSSean Bruno 
2884778508Sblueswir1 #include "qemu.h"
2984778508Sblueswir1 
30*88dae46dSSean Bruno int do_strace;
3184778508Sblueswir1 
3284778508Sblueswir1 /*
3384778508Sblueswir1  * Utility functions
3484778508Sblueswir1  */
3584778508Sblueswir1 
36*88dae46dSSean Bruno static void print_execve(const struct syscallname *name, abi_long arg1,
37*88dae46dSSean Bruno         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
38*88dae46dSSean Bruno         abi_long arg6)
3984778508Sblueswir1 {
4084778508Sblueswir1     abi_ulong arg_ptr_addr;
4184778508Sblueswir1     char *s;
4284778508Sblueswir1 
43*88dae46dSSean Bruno     s = lock_user_string(arg1);
44*88dae46dSSean Bruno     if (s == NULL) {
4584778508Sblueswir1         return;
46*88dae46dSSean Bruno     }
4784778508Sblueswir1     gemu_log("%s(\"%s\",{", name->name, s);
4884778508Sblueswir1     unlock_user(s, arg1, 0);
4984778508Sblueswir1 
5084778508Sblueswir1     for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
5118c9a9c3SChristoph Egger         abi_ulong *arg_ptr, arg_addr;
5284778508Sblueswir1 
5384778508Sblueswir1         arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
54*88dae46dSSean Bruno         if (!arg_ptr) {
5584778508Sblueswir1             return;
56*88dae46dSSean Bruno         }
5784778508Sblueswir1         arg_addr = tswapl(*arg_ptr);
5884778508Sblueswir1         unlock_user(arg_ptr, arg_ptr_addr, 0);
59*88dae46dSSean Bruno         if (!arg_addr) {
6084778508Sblueswir1             break;
61*88dae46dSSean Bruno         }
6284778508Sblueswir1         if ((s = lock_user_string(arg_addr))) {
6384778508Sblueswir1             gemu_log("\"%s\",", s);
6418c9a9c3SChristoph Egger             unlock_user(s, arg_addr, 0);
6584778508Sblueswir1         }
6684778508Sblueswir1     }
6784778508Sblueswir1     gemu_log("NULL})");
6884778508Sblueswir1 }
6984778508Sblueswir1 
7084778508Sblueswir1 /*
7184778508Sblueswir1  * Variants for the return value output function
7284778508Sblueswir1  */
7384778508Sblueswir1 
74*88dae46dSSean Bruno static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
7584778508Sblueswir1 {
7684778508Sblueswir1     if (ret == -1) {
7784778508Sblueswir1         gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
7884778508Sblueswir1     } else {
7984778508Sblueswir1         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
8084778508Sblueswir1     }
8184778508Sblueswir1 }
8284778508Sblueswir1 
8384778508Sblueswir1 #if 0 /* currently unused */
8484778508Sblueswir1 static void
8584778508Sblueswir1 print_syscall_ret_raw(struct syscallname *name, abi_long ret)
8684778508Sblueswir1 {
8784778508Sblueswir1         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
8884778508Sblueswir1 }
8984778508Sblueswir1 #endif
9084778508Sblueswir1 
9184778508Sblueswir1 /*
9284778508Sblueswir1  * An array of all of the syscalls we know about
9384778508Sblueswir1  */
9484778508Sblueswir1 
9584778508Sblueswir1 static const struct syscallname freebsd_scnames[] = {
9684778508Sblueswir1 #include "freebsd/strace.list"
9784778508Sblueswir1 };
9884778508Sblueswir1 static const struct syscallname netbsd_scnames[] = {
9984778508Sblueswir1 #include "netbsd/strace.list"
10084778508Sblueswir1 };
10184778508Sblueswir1 static const struct syscallname openbsd_scnames[] = {
10284778508Sblueswir1 #include "openbsd/strace.list"
10384778508Sblueswir1 };
10484778508Sblueswir1 
105*88dae46dSSean Bruno static void print_syscall(int num, const struct syscallname *scnames,
106*88dae46dSSean Bruno         unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
10784778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
10884778508Sblueswir1 {
10984778508Sblueswir1     unsigned int i;
11084778508Sblueswir1     const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
11184778508Sblueswir1         TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
11284778508Sblueswir1         TARGET_ABI_FMT_ld ")";
11384778508Sblueswir1 
11484778508Sblueswir1     gemu_log("%d ", getpid() );
11584778508Sblueswir1 
116*88dae46dSSean Bruno     for (i = 0; i < nscnames; i++) {
11784778508Sblueswir1         if (scnames[i].nr == num) {
11884778508Sblueswir1             if (scnames[i].call != NULL) {
11984778508Sblueswir1                 scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
12084778508Sblueswir1                         arg6);
12184778508Sblueswir1             } else {
12284778508Sblueswir1                 /* XXX: this format system is broken because it uses
12384778508Sblueswir1                    host types and host pointers for strings */
124*88dae46dSSean Bruno                 if (scnames[i].format != NULL) {
12584778508Sblueswir1                     format = scnames[i].format;
126*88dae46dSSean Bruno                 }
127*88dae46dSSean Bruno                 gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
128*88dae46dSSean Bruno                         arg6);
12984778508Sblueswir1             }
13084778508Sblueswir1             return;
13184778508Sblueswir1         }
132*88dae46dSSean Bruno     }
13384778508Sblueswir1     gemu_log("Unknown syscall %d\n", num);
13484778508Sblueswir1 }
13584778508Sblueswir1 
136*88dae46dSSean Bruno static void print_syscall_ret(int num, abi_long ret,
137*88dae46dSSean Bruno         const struct syscallname *scnames, unsigned int nscnames)
13884778508Sblueswir1 {
13984778508Sblueswir1     unsigned int i;
14084778508Sblueswir1 
141*88dae46dSSean Bruno     for (i = 0; i < nscnames; i++) {
14284778508Sblueswir1         if (scnames[i].nr == num) {
14384778508Sblueswir1             if (scnames[i].result != NULL) {
14484778508Sblueswir1                 scnames[i].result(&scnames[i], ret);
14584778508Sblueswir1             } else {
14684778508Sblueswir1                 if (ret < 0) {
14784778508Sblueswir1                     gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
14884778508Sblueswir1                              strerror(-ret));
14984778508Sblueswir1                 } else {
15084778508Sblueswir1                     gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
15184778508Sblueswir1                 }
15284778508Sblueswir1             }
15384778508Sblueswir1             break;
15484778508Sblueswir1         }
15584778508Sblueswir1     }
156*88dae46dSSean Bruno }
15784778508Sblueswir1 
15884778508Sblueswir1 /*
15984778508Sblueswir1  * The public interface to this module.
16084778508Sblueswir1  */
161*88dae46dSSean Bruno void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
16284778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
16384778508Sblueswir1 {
164*88dae46dSSean Bruno 
165*88dae46dSSean Bruno     print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
166*88dae46dSSean Bruno             arg3, arg4, arg5, arg6);
16784778508Sblueswir1 }
16884778508Sblueswir1 
169*88dae46dSSean Bruno void print_freebsd_syscall_ret(int num, abi_long ret)
17084778508Sblueswir1 {
171*88dae46dSSean Bruno 
17284778508Sblueswir1     print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
17384778508Sblueswir1 }
17484778508Sblueswir1 
175*88dae46dSSean Bruno void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
17684778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
17784778508Sblueswir1 {
178*88dae46dSSean Bruno 
17984778508Sblueswir1     print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
18084778508Sblueswir1                   arg1, arg2, arg3, arg4, arg5, arg6);
18184778508Sblueswir1 }
18284778508Sblueswir1 
183*88dae46dSSean Bruno void print_netbsd_syscall_ret(int num, abi_long ret)
18484778508Sblueswir1 {
185*88dae46dSSean Bruno 
18684778508Sblueswir1     print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
18784778508Sblueswir1 }
18884778508Sblueswir1 
189*88dae46dSSean Bruno void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
19084778508Sblueswir1         abi_long arg4, abi_long arg5, abi_long arg6)
19184778508Sblueswir1 {
192*88dae46dSSean Bruno 
193*88dae46dSSean Bruno     print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
194*88dae46dSSean Bruno             arg3, arg4, arg5, arg6);
19584778508Sblueswir1 }
19684778508Sblueswir1 
197*88dae46dSSean Bruno void print_openbsd_syscall_ret(int num, abi_long ret)
19884778508Sblueswir1 {
199*88dae46dSSean Bruno 
20084778508Sblueswir1     print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
20184778508Sblueswir1 }
202