Skip to contentSkip to conversation

Usermode support for GDB Stub

PATCH New Paul Brook 1 participant 1 message Mar 21, 2005 Kbuild

lore
Share & tools
lore

Paul Brook

author
#0 lore raw

PATCH 1/1 Usermode support for GDB Stub

The attached patch adds gdb stub support to the qemu linux user mode emulator.

I added a bit of code to automatically generate an EXCP_DEBUG exception if we get to the end of a translation block in single step mode, and no exception has been raised. The arm target conditional execution capabilities mean inserting explicit debug exception everywhere would be a pain.

Signal handling is still a somewhat incomplete (continuing/stepping after a signal basically doesn't work), and it doesn't support multithreaded applications. All the important stuff seems to work though (breakpoints, stepping, reading/writing regs/memory).

I tested i386-user and arm-user emulation, and they both seem to work. The other targets I can't conveniently test, but they at least build ok.

Paul

Index: Makefile.target
===================================================================
RCS file: /cvsroot/qemu/qemu/Makefile.target,v
retrieving revision 1.62

Makefile.target +3 -0
diff -u -p -r1.62 Makefile.target
@@ -296,6 +296,9 @@ endif
 ifeq ($(ARCH),ia64)
 OBJS += ia64-syscall.o
 endif
+ifdef CONFIG_GDBSTUB
+OBJS+=gdbstub.o
+endif
 
 all: $(PROGS)
 

Index: cpu-exec.c
===================================================================
RCS file: /cvsroot/qemu/qemu/cpu-exec.c,v
retrieving revision 1.51

cpu-exec.c +4 -0
diff -u -p -r1.51 cpu-exec.c
@@ -568,6 +568,10 @@ int cpu_exec(CPUState *env1)
                 gen_func();
 #endif
                 env->current_tb = NULL;
+                if (env->singlestep_enabled && env->exception_index == -1) {
+                    env->exception_index = EXCP_DEBUG;
+                    cpu_loop_exit ();
+                }
                 /* reset soft MMU for next block (it can currently
                    only be set by a memory fault) */
 #if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)

Index: exec.c
===================================================================
RCS file: /cvsroot/qemu/qemu/exec.c,v
retrieving revision 1.57

exec.c +6 -6
diff -u -p -r1.57 exec.c
@@ -1076,7 +1076,7 @@ static void tb_reset_jump_recursive(Tran
     tb_reset_jump_recursive2(tb, 1);
 }
 
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
 static void breakpoint_invalidate(CPUState *env, target_ulong pc)
 {
     target_ulong phys_addr;
@@ -1090,7 +1090,7 @@ static void breakpoint_invalidate(CPUSta
    breakpoint is reached */
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
     int i;
     
     for(i = 0; i < env->nb_breakpoints; i++) {
@@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env,
 /* remove a breakpoint */
 int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
     int i;
     for(i = 0; i < env->nb_breakpoints; i++) {
         if (env->breakpoints[i] == pc)
@@ -1120,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env,
     }
     return -1;
  found:
-    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
-            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
     env->nb_breakpoints--;
+    if (i < env->nb_breakpoints)
+      env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
 
     breakpoint_invalidate(env, pc);
     return 0;
@@ -1135,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env,
    CPU loop after each instruction */
 void cpu_single_step(CPUState *env, int enabled)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
     if (env->singlestep_enabled != enabled) {
         env->singlestep_enabled = enabled;
         /* must flush all the translated code to avoid inconsistancies */

Index: gdbstub.c
===================================================================
RCS file: /cvsroot/qemu/qemu/gdbstub.c,v
retrieving revision 1.23

gdbstub.c +139 -13

281 lines not on this page · raw message

Index: gdbstub.h
===================================================================
RCS file: gdbstub.h

gdbstub.h new file +11 -0
diff -N gdbstub.h
@@ -0,0 +1,11 @@
+#ifndef GDBSTUB_H
+#define GDBSTUB_H
+
+#define DEFAULT_GDBSTUB_PORT 1234
+
+#ifdef CONFIG_USER_ONLY
+int gdb_handlesig (CPUState *, int);
+#endif
+int gdbserver_start(int);
+
+#endif

Index: vl.h
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.h,v
retrieving revision 1.69

vl.h +1 -6
diff -u -p -r1.69 vl.h
@@ -71,6 +71,7 @@ static inline char *realpath(const char 
 #else
 
 #include "cpu.h"
+#include "gdbstub.h"
 
 #endif /* !defined(QEMU_TOOL) */
 
@@ -829,10 +830,4 @@ const char *readline_get_history(unsigne
 void readline_start(const char *prompt, int is_password,
                     ReadLineFunc *readline_func, void *opaque);
 
-/* gdbstub.c */
-
-#define DEFAULT_GDBSTUB_PORT 1234
-
-int gdbserver_start(int port);
-
 #endif /* VL_H */

Index: linux-user/main.c
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/main.c,v
retrieving revision 1.62

main.c +66 -3

126 lines not on this page · raw message

Index: linux-user/qemu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/qemu.h,v
retrieving revision 1.22

qemu.h +1 -0
diff -u -p -r1.22 qemu.h
@@ -9,6 +9,7 @@
 
 #include "cpu.h"
 #include "syscall.h"
+#include "gdbstub.h"
 
 /* This struct is used to hold certain information about the image.
  * Basically, it replicates in user space what would be certain

Index: linux-user/signal.c
===================================================================
RCS file: /cvsroot/qemu/qemu/linux-user/signal.c,v retrieving revision 1.27

signal.c +6 -0
diff -u -p -r1.27 signal.c
@@ -1680,6 +1680,12 @@ void process_pending_signals(void *cpu_e
     k->first = q->next;
     if (!k->first)
         k->pending = 0;
+      
+    sig = gdb_handlesig (cpu_env, sig);
+    if (!sig) {
+        fprintf (stderr, "Lost signal\n");
+        abort();
+    }
 
     handler = k->sa._sa_handler;
     if (handler == TARGET_SIG_DFL) {

Index: target-arm/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/cpu.h,v
retrieving revision 1.8

cpu.h +7 -0
diff -u -p -r1.8 cpu.h
@@ -26,6 +26,8 @@
 
 #include "softfloat.h"
 
+#define TARGET_HAS_ICE 1
+
 #define EXCP_UDEF            1   /* undefined instruction */
 #define EXCP_SWI             2   /* software interrupt */
 #define EXCP_PREFETCH_ABORT  3
@@ -62,6 +64,11 @@ typedef struct CPUARMState {
     int user_mode_only;
     uint32_t address;
 
+    /* ICE debug support.  */
+    target_ulong breakpoints[MAX_BREAKPOINTS];
+    int nb_breakpoints;
+    int singlestep_enabled;
+
     /* in order to avoid passing too many arguments to the memory
        write helpers, we store some rarely used information in the CPU
        context) */

Index: target-arm/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/op.c,v
retrieving revision 1.10

op.c +6 -0
diff -u -p -r1.10 op.c
@@ -858,6 +858,12 @@ void OPPROTO op_undef_insn(void)
     cpu_loop_exit();
 }
 
+void OPPROTO op_debug(void)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit();
+}
+
 /* VFP support.  We follow the convention used for VFP instrunctions:
    Single precition routines have a "s" suffix, double precision a
    "d" suffix.  */

Index: target-arm/translate.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-arm/translate.c,v retrieving revision 1.18

translate.c +13 -1
diff -u -p -r1.18 translate.c
@@ -2013,6 +2013,17 @@ static inline int gen_intermediate_code_
     dc->pc = pc_start;
     lj = -1;
     do {
+        if (env->nb_breakpoints > 0) {
+            for(j = 0; j < env->nb_breakpoints; j++) {
+                if (env->breakpoints[j] == dc->pc) {
+                    gen_op_movl_T0_im((long)dc->pc);
+                    gen_op_movl_reg_TN[0][15]();
+                    gen_op_debug();
+                    dc->is_jmp = DISAS_JUMP;
+                    break;
+                }
+            }
+        }
         if (search_pc) {
             j = gen_opc_ptr - gen_opc_buf;
             if (lj < j) {
@@ -2027,7 +2038,8 @@ static inline int gen_intermediate_code_
           disas_thumb_insn(dc);
         else
           disas_arm_insn(env, dc);
-    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && 
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
+             !env->singlestep_enabled &&
              (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
     switch(dc->is_jmp) {
     case DISAS_JUMP_NEXT:

Index: target-i386/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/cpu.h,v
retrieving revision 1.28

cpu.h +2 -0
diff -u -p -r1.28 cpu.h
@@ -34,6 +34,8 @@
    close to the modifying instruction */
 #define TARGET_HAS_PRECISE_SMC
 
+#define TARGET_HAS_ICE 1
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"

Index: target-ppc/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-ppc/cpu.h,v
retrieving revision 1.16

cpu.h +2 -0
diff -u -p -r1.16 cpu.h
@@ -29,6 +29,8 @@
 
 #include "softfloat.h"
 
+#define TARGET_HAS_ICE 1
+
 /* Instruction types */
 enum {
     PPC_NONE     = 0x0000,

Index: target-sparc/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-sparc/cpu.h,v
retrieving revision 1.16

cpu.h +2 -0
diff -u -p -r1.16 cpu.h
@@ -17,6 +17,8 @@
 
 #include "softfloat.h"
 
+#define TARGET_HAS_ICE 1
+
 /*#define EXCP_INTERRUPT 0x100*/
 
 /* trap definitions */