qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 1/5] single step with no IRQs and timers


From: Jason Wessel
Subject: [Qemu-devel] [PATCH 1/5] single step with no IRQs and timers
Date: Sat, 20 May 2006 16:01:10 -0500
User-agent: Thunderbird 1.5.0.2 (Windows/20060308)


This patch adds the functionality to the gdb-stub to single step with the IRQs and timers disabled. It greatly improves gdb's ability to perform run control while running a linux kernel and stepping off of breakpoints or stepping into certain types of functions. I have also included individual controls for IRQs and timers to restore the original behavior, since it is useful as well.

signed-off-by: address@hidden

Jason.
Index: qemu/cpu-exec.c
===================================================================
--- qemu.orig/cpu-exec.c
+++ qemu/cpu-exec.c
@@ -452,7 +452,8 @@ int cpu_exec(CPUState *env1)
                 tmp_T0 = T0;
 #endif     
                 interrupt_request = env->interrupt_request;
-                if (__builtin_expect(interrupt_request, 0)) {
+                if (__builtin_expect(interrupt_request, 0) &&
+                    !(env->singlestep_enabled & SSTEP_NOIRQ)) {
 #if defined(TARGET_I386)
                     /* if hardware interrupt pending, we execute it */
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -4407,6 +4407,8 @@ void qemu_system_powerdown_request(void)
         cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }
 
+static CPUState *cur_cpu;
+
 void main_loop_wait(int timeout)
 {
     IOHandlerRecord *ioh, *ioh_next;
@@ -4500,19 +4502,19 @@ void main_loop_wait(int timeout)
 #endif
 
     if (vm_running) {
-        qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], 
-                        qemu_get_clock(vm_clock));
+        if (!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))
+            qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+                            qemu_get_clock(vm_clock));
         /* run dma transfers, if any */
         DMA_run();
     }
     
     /* real time timers */
-    qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], 
-                    qemu_get_clock(rt_clock));
+    if (!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))
+        qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
+                        qemu_get_clock(rt_clock));
 }
 
-static CPUState *cur_cpu;
-
 int main_loop(void)
 {
     int ret, timeout;
Index: qemu/gdbstub.c
===================================================================
--- qemu.orig/gdbstub.c
+++ qemu/gdbstub.c
@@ -46,6 +46,11 @@ enum RSState {
 /* XXX: This is not thread safe.  Do we care?  */
 static int gdbserver_fd = -1;
 
+/* By default use no IRQs and no timers while single stepping so as to
+ * make single stepping like an ICE HW step.
+ */
+static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
+
 typedef struct GDBState {
     CPUState *env; /* current CPU */
     enum RSState state; /* parsing state */
@@ -596,7 +601,7 @@ static int gdb_handle_packet(GDBState *s
            env->pc = addr;
 #endif
         }
-        cpu_single_step(env, 1);
+        cpu_single_step(env, sstep_flags);
 #ifdef CONFIG_USER_ONLY
         s->running_state = 1;
 #else
@@ -672,8 +677,35 @@ static int gdb_handle_packet(GDBState *s
             goto breakpoint_error;
         }
         break;
+    case 'q':
+        /* parse any 'q' packets here */
+        if (!strcmp(p,"sstepbits")) {
+            /* Query Breakpoint bit definitions */
+            sprintf(buf,"ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
+                    SSTEP_ENABLE,
+                    SSTEP_NOIRQ,
+                    SSTEP_NOTIMER);
+            put_packet(s, buf);
+            break;
+        } else if (strncmp(p,"sstep",5) == 0) {
+            /* Display or change the sstep_flags */
+            p += 5;
+            if (*p != '=') {
+                /* Display current setting */
+                sprintf(buf,"0x%x", sstep_flags);
+                put_packet(s, buf);
+                break;
+            }
+            p++;
+            type = strtoul(p, (char **)&p, 16);
+            sstep_flags = type;
+            put_packet(s, "OK");
+            break;
+        }
+        goto unknown_command;
+        break;
     default:
-        //        unknown_command:
+    unknown_command:
         /* put empty packet */
         buf[0] = '\0';
         put_packet(s, buf);
Index: qemu/cpu-all.h
===================================================================
--- qemu.orig/cpu-all.h
+++ qemu/cpu-all.h
@@ -768,6 +768,11 @@ void cpu_reset_interrupt(CPUState *env, 
 
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
 int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
+
+#define SSTEP_ENABLE  0x1  /* Enable simulated HW single stepping */
+#define SSTEP_NOIRQ   0x2  /* Do not use IRQ while single stepping */
+#define SSTEP_NOTIMER 0x4  /* Do not Timers while single stepping */
+
 void cpu_single_step(CPUState *env, int enabled);
 void cpu_reset(CPUState *s);
 
Index: qemu/qemu-doc.texi
===================================================================
--- qemu.orig/qemu-doc.texi
+++ qemu/qemu-doc.texi
@@ -1219,6 +1219,36 @@ Use @code{set architecture i8086} to dum
 @code{x/10i $cs*16+$eip} to dump the code at the PC position.
 @end enumerate
 
+Advanced debugging options:
+
+The default single stepping behavior is step with the IRQs and timer service 
routines off.  It is set this way because when gdb executes a single step it 
expects to advance beyond the current instruction.  With the IRQs and and timer 
service routines on, a single step might jump into the one of the interrupt or 
exception vectors instead of executing the current instruction. This means you 
may hit the same breakpoint a number of times before executing the instruction 
gdb wants to have executed.  Because there are rare circumstances where you 
want to single step into an interrupt vector the behavior can be controlled 
from GDB.  There are three commands you can query and set the single step 
behavior:
address@hidden @code
address@hidden maintenance packet qsstepbits
+
+This will display the MASK bits used to control the single stepping IE:
address@hidden
+(gdb) maintenance packet qsstepbits
+sending: "qsstepbits"
+received: "ENABLE=1,NOIRQ=2,NOTIMER=4"
address@hidden example
address@hidden maintenance packet qsstep
+
+This will display the current value of the mask used when single stepping IE:
address@hidden
+(gdb) maintenance packet qsstep
+sending: "qsstep"
+received: "0x7"
address@hidden example
address@hidden maintenance packet qsstep=HEX_VALUE
+
+This will change the single step mask, so if wanted to enable IRQs on the 
single step, but not timers, you would use:
address@hidden
+(gdb) maintenance packet qsstep=0x5
+sending: "qsstep=0x5"
+received: "OK"
address@hidden example
address@hidden enumerate
+
 @node pcsys_os_specific
 @section Target OS specific information
 

reply via email to

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