qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [ADD] tests for PPC target.


From: J. Mayer
Subject: Re: [Qemu-devel] [ADD] tests for PPC target.
Date: 18 Nov 2003 09:08:13 +0100

target-ppc__tests__ctrace.c.diff

This is a program which follows the execution of it's child and
print the state of the CPU for each executed instruction.
The output can be compared with qemu.log to find qemu bugs...

diff -urNbB -x CVS qemu-current/target-ppc/tests/ctrace.c 
qemu/target-ppc/tests/ctrace.c
--- qemu-current/target-ppc/tests/ctrace.c      Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/tests/ctrace.c      Wed Nov 12 10:37:09 2003
@@ -0,0 +1,177 @@
+/*
+ *  CPU trace debugger.
+ * 
+ *  Copyright (c) 2003 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * This utility traces the CPU state for each execution step of a program.
+ * Of course, this is awfully slow.
+ * This can be used to compare the result of the execution of a native program
+ * vs the same one emulated by qemu.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#if defined (__powerpc__)
+static void dump_cpu_state (int child)
+{
+    unsigned long GPR[32];
+    unsigned long nip, LR, CTR, CR;
+    unsigned long opcode = 0, tmp;
+    int i;
+    
+    /* Retrieve GPR's */
+    for (i = 0; i < 32; i++)
+        GPR[i] = ptrace(PTRACE_PEEKUSR, child, (void *)(i << 2), &GPR[i]);
+
+    /* Retrieve nip */
+    nip = ptrace(PTRACE_PEEKUSR, child, (void *)(32 << 2), &nip);
+    /* Retrieve LR  */
+    LR = ptrace(PTRACE_PEEKUSR, child, (void *)(36 << 2), &LR);
+    /* Retrieve CTR  */
+    CTR = ptrace(PTRACE_PEEKUSR, child, (void *)(35 << 2), &CTR);
+    /* Retrieve CR  */
+    CR = ptrace(PTRACE_PEEKUSR, child, (void *)(38 << 2), &CR);
+    /* Retrieve current opcode */
+    if (nip == -1)
+        return;
+
+    opcode = ptrace(PTRACE_PEEKTEXT, child, nip - 4, NULL);
+    /* Dump all */
+    printf("nip=0x%08lx LR=0x%08lx CTR=0x%08lx\n",
+           nip, LR, CTR);
+    for (i = 0; i < 32; i++) {
+        if ((i & 7) == 0)
+            printf("GPR%02d: ", i);
+        printf("%08lx ", GPR[i]);
+        if ((i & 7) == 7)
+            printf("\n");
+    }
+    printf("0x%08lx: translate opcode %08lx\n", nip, opcode);
+}
+#elif defined (__i386__)
+static void dump_cpu_state (int child)
+{
+    struct user_regs_struct regs;
+
+    memset(&regs, 0, sizeof(regs));
+    if (ptrace(PTRACE_GETREGS, child, NULL, &regs) < 0) {
+        printf("PTRACE_GETREGS: %m\n");
+        return;
+    }
+    printf("nip=0x%08lx\n", regs.eip);
+    printf("eax=0x%08lx ebx=0x%08lx ecx=0x%08lx edx=0x%08lx\n",
+           regs.eax, regs.ebx, regs.ecx, regs.edx);
+    printf("esi=0x%08lx edi=0x%08lx esp=0x%08lx ebp=0x%08lx\n",
+           regs.esi, regs.edi, regs.esp, regs.ebp);
+    fflush(stdout);
+}
+#else
+#error "Unsupported target CPU"
+#endif
+
+/* Main loop */
+__attribute__((noreturn))
+int main (int argc, char **argv)
+{
+    pid_t child, me;
+    int status;
+
+    me = getpid();
+    if (argc < 2) {
+        fprintf(stderr, "Usage : ctrace prog args...\n");
+        fprintf(stderr, "Need a program to be inspected !\n");
+        fflush(stderr);
+        exit(1);
+    }
+    if (access(argv[1], R_OK | X_OK) < 0) {
+        fprintf(stderr, "Can't execute %s\n", argv[1]);
+        fflush(stderr);
+        exit(1);
+    }
+    fflush(stdout);
+
+    child = fork();
+    switch (child) {
+    case 0:
+        /* Child */
+        /* Initiate trace */
+        if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
+            fprintf(stderr, "Ptrace failed : %m\n");
+            fflush(stderr);
+            exit(1);
+        }
+        /* Launch the program to be traced */
+        execv(argv[1], &argv[1]);
+        /* Can't come here ! */
+        fprintf(stderr, "Exec failed: %m\n");
+        fflush(stderr);
+        exit(1);
+    case -1:
+        /* Error case... */
+        fprintf(stderr, "Can't fork to execute %s\n", argv[1]);
+        fflush(stderr);
+        exit(1);
+    default:
+        break;
+    }
+    /* Wait for the child to be launched */
+    while (0) {
+        while (waitpid(child, &status, WUNTRACED) != child)
+            continue;
+        if (WIFSTOPPED(status))
+            break;
+    }
+    /* Now, trace it ! */
+    while (1) {
+        while (waitpid(child, &status, WUNTRACED) != child)
+            continue;
+        if (!WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)
+            break;
+        if (WSTOPSIG(status) != SIGTRAP) {
+            printf("%d: seen signal %d\n", me, WSTOPSIG(status));
+            fflush(stdout);
+        }
+        dump_cpu_state(child);
+        while (ptrace(PTRACE_SINGLESTEP, child, 1, SIGCONT) < 0)
+            continue;
+    }
+    printf("process %s ", argv[1]);
+    fflush(stdout);
+    if (WIFEXITED(status)) {
+        printf("ended with code: %d\n", WEXITSTATUS(status));
+        fflush(stdout);
+    } else if (WIFSIGNALED(status)) {
+        printf("killed by signal: %d\n", WTERMSIG(status));
+        fflush(stdout);
+    } else if (WIFSTOPPED(status)) {
+        /* Should never happen */
+        printf("stopped\n");
+        fflush(stdout);
+    }
+
+    exit(0);
+}






reply via email to

[Prev in Thread] Current Thread [Next in Thread]