qemu/bsd-user/strace.c
<<
>>
Prefs
   1/*
   2 *  System call tracing and debugging
   3 *
   4 *
   5 *  This program is free software; you can redistribute it and/or modify
   6 *  it under the terms of the GNU General Public License as published by
   7 *  the Free Software Foundation; either version 2 of the License, or
   8 *  (at your option) any later version.
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *  GNU General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU General Public License
  16 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include "qemu/osdep.h"
  20#include <sys/select.h>
  21#include <sys/syscall.h>
  22#include <sys/ioccom.h>
  23
  24#include "qemu.h"
  25
  26int do_strace;
  27
  28/*
  29 * Utility functions
  30 */
  31
  32static void print_sysctl(const struct syscallname *name, abi_long arg1,
  33        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
  34        abi_long arg6)
  35{
  36    uint32_t i;
  37    int32_t *namep;
  38
  39    gemu_log("%s({ ", name->name);
  40    namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
  41    if (namep) {
  42        int32_t *p = namep;
  43
  44        for (i = 0; i < (uint32_t)arg2; i++) {
  45            gemu_log("%d ", tswap32(*p++));
  46        }
  47        unlock_user(namep, arg1, 0);
  48    }
  49    gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
  50        TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
  51        (uint32_t)arg2, arg3, arg4, arg5, arg6);
  52}
  53
  54static void print_execve(const struct syscallname *name, abi_long arg1,
  55        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
  56        abi_long arg6)
  57{
  58    abi_ulong arg_ptr_addr;
  59    char *s;
  60
  61    s = lock_user_string(arg1);
  62    if (s == NULL) {
  63        return;
  64    }
  65    gemu_log("%s(\"%s\",{", name->name, s);
  66    unlock_user(s, arg1, 0);
  67
  68    for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
  69        abi_ulong *arg_ptr, arg_addr;
  70
  71        arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
  72        if (!arg_ptr) {
  73            return;
  74        }
  75        arg_addr = tswapl(*arg_ptr);
  76        unlock_user(arg_ptr, arg_ptr_addr, 0);
  77        if (!arg_addr) {
  78            break;
  79        }
  80        if ((s = lock_user_string(arg_addr))) {
  81            gemu_log("\"%s\",", s);
  82            unlock_user(s, arg_addr, 0);
  83        }
  84    }
  85    gemu_log("NULL})");
  86}
  87
  88static void print_ioctl(const struct syscallname *name,
  89        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
  90        abi_long arg5, abi_long arg6)
  91{
  92    /* Decode the ioctl request */
  93    gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
  94            TARGET_ABI_FMT_lx ", ...)",
  95            name->name,
  96            (int)arg1,
  97            (unsigned long)arg2,
  98            arg2 & IOC_OUT ? "R" : "",
  99            arg2 & IOC_IN ? "W" : "",
 100            (unsigned)IOCGROUP(arg2),
 101            isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
 102            (int)arg2 & 0xFF,
 103            (int)IOCPARM_LEN(arg2),
 104            arg3);
 105}
 106
 107/*
 108 * Variants for the return value output function
 109 */
 110
 111static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 112{
 113    if (ret == -1) {
 114        gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
 115    } else {
 116        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
 117    }
 118}
 119
 120#if 0 /* currently unused */
 121static void
 122print_syscall_ret_raw(struct syscallname *name, abi_long ret)
 123{
 124        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
 125}
 126#endif
 127
 128/*
 129 * An array of all of the syscalls we know about
 130 */
 131
 132static const struct syscallname freebsd_scnames[] = {
 133#include "freebsd/strace.list"
 134};
 135static const struct syscallname netbsd_scnames[] = {
 136#include "netbsd/strace.list"
 137};
 138static const struct syscallname openbsd_scnames[] = {
 139#include "openbsd/strace.list"
 140};
 141
 142static void print_syscall(int num, const struct syscallname *scnames,
 143        unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
 144        abi_long arg4, abi_long arg5, abi_long arg6)
 145{
 146    unsigned int i;
 147    const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
 148        TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
 149        TARGET_ABI_FMT_ld ")";
 150
 151    gemu_log("%d ", getpid() );
 152
 153    for (i = 0; i < nscnames; i++) {
 154        if (scnames[i].nr == num) {
 155            if (scnames[i].call != NULL) {
 156                scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
 157                        arg6);
 158            } else {
 159                /* XXX: this format system is broken because it uses
 160                   host types and host pointers for strings */
 161                if (scnames[i].format != NULL) {
 162                    format = scnames[i].format;
 163                }
 164                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
 165                        arg6);
 166            }
 167            return;
 168        }
 169    }
 170    gemu_log("Unknown syscall %d\n", num);
 171}
 172
 173static void print_syscall_ret(int num, abi_long ret,
 174        const struct syscallname *scnames, unsigned int nscnames)
 175{
 176    unsigned int i;
 177
 178    for (i = 0; i < nscnames; i++) {
 179        if (scnames[i].nr == num) {
 180            if (scnames[i].result != NULL) {
 181                scnames[i].result(&scnames[i], ret);
 182            } else {
 183                if (ret < 0) {
 184                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
 185                             strerror(-ret));
 186                } else {
 187                    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
 188                }
 189            }
 190            break;
 191        }
 192    }
 193}
 194
 195/*
 196 * The public interface to this module.
 197 */
 198void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
 199        abi_long arg4, abi_long arg5, abi_long arg6)
 200{
 201
 202    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
 203            arg3, arg4, arg5, arg6);
 204}
 205
 206void print_freebsd_syscall_ret(int num, abi_long ret)
 207{
 208
 209    print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
 210}
 211
 212void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
 213        abi_long arg4, abi_long arg5, abi_long arg6)
 214{
 215
 216    print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
 217                  arg1, arg2, arg3, arg4, arg5, arg6);
 218}
 219
 220void print_netbsd_syscall_ret(int num, abi_long ret)
 221{
 222
 223    print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
 224}
 225
 226void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
 227        abi_long arg4, abi_long arg5, abi_long arg6)
 228{
 229
 230    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
 231            arg3, arg4, arg5, arg6);
 232}
 233
 234void print_openbsd_syscall_ret(int num, abi_long ret)
 235{
 236
 237    print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
 238}
 239