Commit 0cb581d6 authored by Peter Maydell's avatar Peter Maydell Committed by Riku Voipio
Browse files

linux-user: report signals being taken in strace output



Native strace reports when the process being traced takes a signal:
   --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---

Report something similar when QEMU is doing its internal strace of
the guest process and is about to deliver it a signal.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarRiku Voipio <riku.voipio@linaro.org>
parent ce9c139d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -362,6 +362,16 @@ void print_syscall(int num,
                   abi_long arg1, abi_long arg2, abi_long arg3,
                   abi_long arg4, abi_long arg5, abi_long arg6);
void print_syscall_ret(int num, abi_long arg1);
/**
 * print_taken_signal:
 * @target_signum: target signal being taken
 * @tinfo: target_siginfo_t which will be passed to the guest for the signal
 *
 * Print strace output indicating that this signal is being taken by the guest,
 * in a format similar to:
 * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
 */
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
extern int do_strace;

/* signal.c */
+4 −0
Original line number Diff line number Diff line
@@ -5849,6 +5849,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
        handler = sa->_sa_handler;
    }

    if (do_strace) {
        print_taken_signal(sig, &k->info);
    }

    if (handler == TARGET_SIG_DFL) {
        /* default handler : ignore some signal. The other are job control or fatal */
        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
+106 −0
Original line number Diff line number Diff line
@@ -154,6 +154,100 @@ print_signal(abi_ulong arg, int last)
    gemu_log("%s%s", signal_name, get_comma(last));
}

static void print_si_code(int arg)
{
    const char *codename = NULL;

    switch (arg) {
    case SI_USER:
        codename = "SI_USER";
        break;
    case SI_KERNEL:
        codename = "SI_KERNEL";
        break;
    case SI_QUEUE:
        codename = "SI_QUEUE";
        break;
    case SI_TIMER:
        codename = "SI_TIMER";
        break;
    case SI_MESGQ:
        codename = "SI_MESGQ";
        break;
    case SI_ASYNCIO:
        codename = "SI_ASYNCIO";
        break;
    case SI_SIGIO:
        codename = "SI_SIGIO";
        break;
    case SI_TKILL:
        codename = "SI_TKILL";
        break;
    default:
        gemu_log("%d", arg);
        return;
    }
    gemu_log("%s", codename);
}

static void print_siginfo(const target_siginfo_t *tinfo)
{
    /* Print a target_siginfo_t in the format desired for printing
     * signals being taken. We assume the target_siginfo_t is in the
     * internal form where the top 16 bits of si_code indicate which
     * part of the union is valid, rather than in the guest-visible
     * form where the bottom 16 bits are sign-extended into the top 16.
     */
    int si_type = extract32(tinfo->si_code, 16, 16);
    int si_code = sextract32(tinfo->si_code, 0, 16);

    gemu_log("{si_signo=");
    print_signal(tinfo->si_signo, 1);
    gemu_log(", si_code=");
    print_si_code(si_code);

    switch (si_type) {
    case QEMU_SI_KILL:
        gemu_log(", si_pid = %u, si_uid = %u",
                 (unsigned int)tinfo->_sifields._kill._pid,
                 (unsigned int)tinfo->_sifields._kill._uid);
        break;
    case QEMU_SI_TIMER:
        gemu_log(", si_timer1 = %u, si_timer2 = %u",
                 tinfo->_sifields._timer._timer1,
                 tinfo->_sifields._timer._timer2);
        break;
    case QEMU_SI_POLL:
        gemu_log(", si_band = %d, si_fd = %d",
                 tinfo->_sifields._sigpoll._band,
                 tinfo->_sifields._sigpoll._fd);
        break;
    case QEMU_SI_FAULT:
        gemu_log(", si_addr = ");
        print_pointer(tinfo->_sifields._sigfault._addr, 1);
        break;
    case QEMU_SI_CHLD:
        gemu_log(", si_pid = %u, si_uid = %u, si_status = %d"
                 ", si_utime=" TARGET_ABI_FMT_ld
                 ", si_stime=" TARGET_ABI_FMT_ld,
                 (unsigned int)(tinfo->_sifields._sigchld._pid),
                 (unsigned int)(tinfo->_sifields._sigchld._uid),
                 tinfo->_sifields._sigchld._status,
                 tinfo->_sifields._sigchld._utime,
                 tinfo->_sifields._sigchld._stime);
        break;
    case QEMU_SI_RT:
        gemu_log(", si_pid = %u, si_uid = %u, si_sigval = " TARGET_ABI_FMT_ld,
                 (unsigned int)tinfo->_sifields._rt._pid,
                 (unsigned int)tinfo->_sifields._rt._uid,
                 tinfo->_sifields._rt._sigval.sival_ptr);
        break;
    default:
        g_assert_not_reached();
    }
    gemu_log("}");
}

static void
print_sockaddr(abi_ulong addr, abi_long addrlen)
{
@@ -2190,3 +2284,15 @@ print_syscall_ret(int num, abi_long ret)
            break;
        }
}

void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
{
    /* Print the strace output for a signal being taken:
     * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
     */
    gemu_log("--- ");
    print_signal(target_signum, 1);
    gemu_log(" ");
    print_siginfo(tinfo);
    gemu_log(" ---\n");
}