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#include <ctype.h>
  24
  25#include "qemu.h"
  26
  27#include "os-strace.h"  /* OS dependent strace print functions */
  28
  29int do_strace;
  30
  31/*
  32 * Utility functions
  33 */
  34static const char *
  35get_comma(int last)
  36{
  37    return (last) ? "" : ",";
  38}
  39
  40/*
  41 * Prints out raw parameter using given format.  Caller needs
  42 * to do byte swapping if needed.
  43 */
  44static void
  45print_raw_param(const char *fmt, abi_long param, int last)
  46{
  47    char format[64];
  48
  49    (void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last));
  50    gemu_log(format, param);
  51}
  52
  53static void print_sysctl(const struct syscallname *name, abi_long arg1,
  54        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
  55        abi_long arg6)
  56{
  57    uint32_t i;
  58    int32_t *namep;
  59
  60    gemu_log("%s({ ", name->name);
  61    namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1);
  62    if (namep) {
  63        int32_t *p = namep;
  64
  65        for (i = 0; i < (uint32_t)arg2; i++) {
  66            gemu_log("%d ", tswap32(*p++));
  67        }
  68        unlock_user(namep, arg1, 0);
  69    }
  70    gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x"
  71        TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")",
  72        (uint32_t)arg2, arg3, arg4, arg5, arg6);
  73}
  74
  75static void print_execve(const struct syscallname *name, abi_long arg1,
  76        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
  77        abi_long arg6)
  78{
  79    abi_ulong arg_ptr_addr;
  80    char *s;
  81
  82    s = lock_user_string(arg1);
  83    if (s == NULL) {
  84        return;
  85    }
  86    gemu_log("%s(\"%s\",{", name->name, s);
  87    unlock_user(s, arg1, 0);
  88
  89    for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
  90        abi_ulong *arg_ptr, arg_addr;
  91
  92        arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
  93        if (!arg_ptr) {
  94            return;
  95        }
  96        arg_addr = tswapl(*arg_ptr);
  97        unlock_user(arg_ptr, arg_ptr_addr, 0);
  98        if (!arg_addr) {
  99            break;
 100        }
 101        if ((s = lock_user_string(arg_addr))) {
 102            gemu_log("\"%s\",", s);
 103            unlock_user(s, arg_addr, 0);
 104        }
 105    }
 106    gemu_log("NULL})");
 107}
 108
 109static void print_ioctl(const struct syscallname *name,
 110        abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4,
 111        abi_long arg5, abi_long arg6)
 112{
 113    /* Decode the ioctl request */
 114    gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x"
 115            TARGET_ABI_FMT_lx ", ...)",
 116            name->name,
 117            (int)arg1,
 118            (unsigned long)arg2,
 119            arg2 & IOC_OUT ? "R" : "",
 120            arg2 & IOC_IN ? "W" : "",
 121            (unsigned)IOCGROUP(arg2),
 122            isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?',
 123            (int)arg2 & 0xFF,
 124            (int)IOCPARM_LEN(arg2),
 125            arg3);
 126}
 127
 128static void print_sysarch(const struct syscallname *name, abi_long arg1,
 129        abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
 130        abi_long arg6)
 131{
 132    /* This is os dependent. */
 133    do_os_print_sysarch(name, arg1, arg2, arg3, arg4, arg5, arg6);
 134}
 135
 136/*
 137 * Variants for the return value output function
 138 */
 139
 140static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 141{
 142    if (ret == -1) {
 143        gemu_log(" = -1 errno=%d (%s)\n", errno, strerror(errno));
 144    } else {
 145        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
 146    }
 147}
 148
 149/*
 150 * An array of all of the syscalls we know about
 151 */
 152
 153static const struct syscallname freebsd_scnames[] = {
 154#include "freebsd/strace.list"
 155};
 156static const struct syscallname netbsd_scnames[] = {
 157#include "netbsd/strace.list"
 158};
 159static const struct syscallname openbsd_scnames[] = {
 160#include "openbsd/strace.list"
 161};
 162
 163static void print_syscall(int num, const struct syscallname *scnames,
 164        unsigned int nscnames, abi_long arg1, abi_long arg2, abi_long arg3,
 165        abi_long arg4, abi_long arg5, abi_long arg6)
 166{
 167    unsigned int i;
 168    const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
 169        TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ","
 170        TARGET_ABI_FMT_ld ")";
 171
 172    gemu_log("%d ", getpid() );
 173
 174    for (i = 0; i < nscnames; i++) {
 175        if (scnames[i].nr == num) {
 176            if (scnames[i].call != NULL) {
 177                scnames[i].call(&scnames[i], arg1, arg2, arg3, arg4, arg5,
 178                        arg6);
 179            } else {
 180                /* XXX: this format system is broken because it uses
 181                   host types and host pointers for strings */
 182                if (scnames[i].format != NULL) {
 183                    format = scnames[i].format;
 184                }
 185                gemu_log(format, scnames[i].name, arg1, arg2, arg3, arg4, arg5,
 186                        arg6);
 187            }
 188            return;
 189        }
 190    }
 191    gemu_log("Unknown syscall %d\n", num);
 192}
 193
 194static void print_syscall_ret(int num, abi_long ret,
 195        const struct syscallname *scnames, unsigned int nscnames)
 196{
 197    unsigned int i;
 198
 199    for (i = 0; i < nscnames; i++) {
 200        if (scnames[i].nr == num) {
 201            if (scnames[i].result != NULL) {
 202                scnames[i].result(&scnames[i], ret);
 203            } else {
 204                if (ret < 0) {
 205                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret,
 206                             strerror(-ret));
 207                } else {
 208                    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
 209                }
 210            }
 211            break;
 212        }
 213    }
 214}
 215
 216/*
 217 * The public interface to this module.
 218 */
 219void print_freebsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
 220        abi_long arg4, abi_long arg5, abi_long arg6)
 221{
 222
 223    print_syscall(num, freebsd_scnames, ARRAY_SIZE(freebsd_scnames), arg1, arg2,
 224            arg3, arg4, arg5, arg6);
 225}
 226
 227void print_freebsd_syscall_ret(int num, abi_long ret)
 228{
 229
 230    print_syscall_ret(num, ret, freebsd_scnames, ARRAY_SIZE(freebsd_scnames));
 231}
 232
 233void print_netbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
 234        abi_long arg4, abi_long arg5, abi_long arg6)
 235{
 236
 237    print_syscall(num, netbsd_scnames, ARRAY_SIZE(netbsd_scnames),
 238                  arg1, arg2, arg3, arg4, arg5, arg6);
 239}
 240
 241void print_netbsd_syscall_ret(int num, abi_long ret)
 242{
 243
 244    print_syscall_ret(num, ret, netbsd_scnames, ARRAY_SIZE(netbsd_scnames));
 245}
 246
 247void print_openbsd_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3,
 248        abi_long arg4, abi_long arg5, abi_long arg6)
 249{
 250
 251    print_syscall(num, openbsd_scnames, ARRAY_SIZE(openbsd_scnames), arg1, arg2,
 252            arg3, arg4, arg5, arg6);
 253}
 254
 255void print_openbsd_syscall_ret(int num, abi_long ret)
 256{
 257
 258    print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
 259}
 260
 261static void
 262print_signal(abi_ulong arg, int last)
 263{
 264    const char *signal_name = NULL;
 265    switch (arg) {
 266    case TARGET_SIGHUP:
 267        signal_name = "SIGHUP";
 268        break;
 269    case TARGET_SIGINT:
 270        signal_name = "SIGINT";
 271        break;
 272    case TARGET_SIGQUIT:
 273        signal_name = "SIGQUIT";
 274        break;
 275    case TARGET_SIGILL:
 276        signal_name = "SIGILL";
 277        break;
 278    case TARGET_SIGABRT:
 279        signal_name = "SIGABRT";
 280        break;
 281    case TARGET_SIGFPE:
 282        signal_name = "SIGFPE";
 283        break;
 284    case TARGET_SIGKILL:
 285        signal_name = "SIGKILL";
 286        break;
 287    case TARGET_SIGSEGV:
 288        signal_name = "SIGSEGV";
 289        break;
 290    case TARGET_SIGPIPE:
 291        signal_name = "SIGPIPE";
 292        break;
 293    case TARGET_SIGALRM:
 294        signal_name = "SIGALRM";
 295        break;
 296    case TARGET_SIGTERM:
 297        signal_name = "SIGTERM";
 298        break;
 299    case TARGET_SIGUSR1:
 300        signal_name = "SIGUSR1";
 301        break;
 302    case TARGET_SIGUSR2:
 303        signal_name = "SIGUSR2";
 304        break;
 305    case TARGET_SIGCHLD:
 306        signal_name = "SIGCHLD";
 307        break;
 308    case TARGET_SIGCONT:
 309        signal_name = "SIGCONT";
 310        break;
 311    case TARGET_SIGSTOP:
 312        signal_name = "SIGSTOP";
 313        break;
 314    case TARGET_SIGTTIN:
 315        signal_name = "SIGTTIN";
 316        break;
 317    case TARGET_SIGTTOU:
 318        signal_name = "SIGTTOU";
 319        break;
 320    }
 321    if (signal_name == NULL) {
 322        print_raw_param("%ld", arg, last);
 323        return;
 324    }
 325    gemu_log("%s%s", signal_name, get_comma(last));
 326}
 327
 328void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
 329{
 330    /*
 331     * Print the strace output for a signal being taken:
 332     * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
 333     */
 334    gemu_log("%d ", getpid());
 335    gemu_log("--- ");
 336    print_signal(target_signum, 1);
 337    gemu_log(" ---\n");
 338}
 339