Usermode support for GDB Stub
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
@@ -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
@@ -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
@@ -1076,7 +1076,7 @@ static void tb_reset_jump_recursive(Trantb_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(CPUStabreakpoint 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
@@ -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
@@ -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(unsignevoid 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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); elsedisas_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
@@ -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
@@ -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
@@ -17,6 +17,8 @@#include "softfloat.h" +#define TARGET_HAS_ICE 1 +/*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */