added verr, verw, arpl - more precise segment rights checks
[qemu] / gdbstub.c
index 2d1f478..bb3fed9 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
 #include <signal.h>
 
 #include "config.h"
-#ifdef TARGET_I386
-#include "cpu-i386.h"
-#endif
-#ifdef TARGET_ARM
-#include "cpu-arm.h"
-#endif
+#include "cpu.h"
 #include "thunk.h"
-#include "exec.h"
+#include "exec-all.h"
 
 //#define DEBUG_GDB
 
@@ -283,11 +278,11 @@ static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
 }
 
 /* port = 0 means default port */
-int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
+int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
 {
     CPUState *env;
     const char *p;
-    int ret, ch, nb_regs, i;
+    int ret, ch, nb_regs, i, type;
     char buf[4096];
     uint8_t mem_buf[2000];
     uint32_t *registers;
@@ -309,8 +304,37 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
             put_packet(buf);
             break;
         case 'c':
-            main_loop(opaque);
-            snprintf(buf, sizeof(buf), "S%02x", 0);
+            if (*p != '\0') {
+                addr = strtoul(p, (char **)&p, 16);
+                env = cpu_gdbstub_get_env(opaque);
+#if defined(TARGET_I386)
+                env->eip = addr;
+#endif
+            }
+            ret = main_loop(opaque);
+            if (ret == EXCP_DEBUG)
+                ret = SIGTRAP;
+            else
+                ret = 0;
+            snprintf(buf, sizeof(buf), "S%02x", ret);
+            put_packet(buf);
+            break;
+        case 's':
+            env = cpu_gdbstub_get_env(opaque);
+            if (*p != '\0') {
+                addr = strtoul(p, (char **)&p, 16);
+#if defined(TARGET_I386)
+                env->eip = addr;
+#endif
+            }
+            cpu_single_step(env, 1);
+            ret = main_loop(opaque);
+            cpu_single_step(env, 0);
+            if (ret == EXCP_DEBUG)
+                ret = SIGTRAP;
+            else
+                ret = 0;
+            snprintf(buf, sizeof(buf), "S%02x", ret);
             put_packet(buf);
             break;
         case 'g':
@@ -344,6 +368,7 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
             }
             env->eip = registers[8];
             env->eflags = registers[9];
+#if defined(CONFIG_USER_ONLY)
 #define LOAD_SEG(index, sreg)\
             if (tswapl(registers[index]) != env->segs[sreg].selector)\
                 cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
@@ -354,6 +379,7 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
             LOAD_SEG(14, R_FS);
             LOAD_SEG(15, R_GS);
 #endif
+#endif
             put_packet("OK");
             break;
         case 'm':
@@ -379,7 +405,58 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
             else
                 put_packet("OK");
             break;
+        case 'Z':
+            type = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            addr = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            len = strtoul(p, (char **)&p, 16);
+            if (type == 0 || type == 1) {
+                env = cpu_gdbstub_get_env(opaque);
+                if (cpu_breakpoint_insert(env, addr) < 0)
+                    goto breakpoint_error;
+                put_packet("OK");
+            } else {
+            breakpoint_error:
+                put_packet("ENN");
+            }
+            break;
+        case 'z':
+            type = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            addr = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            len = strtoul(p, (char **)&p, 16);
+            if (type == 0 || type == 1) {
+                env = cpu_gdbstub_get_env(opaque);
+                cpu_breakpoint_remove(env, addr);
+                put_packet("OK");
+            } else {
+                goto breakpoint_error;
+            }
+            break;
+        case 'Q':
+            if (!strncmp(p, "Tinit", 5)) {
+                /* init traces */
+                put_packet("OK");
+            } else if (!strncmp(p, "TStart", 6)) {
+                /* start log (gdb 'tstart' command) */
+                cpu_set_log(CPU_LOG_ALL);
+                put_packet("OK");
+            } else if (!strncmp(p, "TStop", 5)) {
+                /* stop log (gdb 'tstop' command) */
+                cpu_set_log(0);
+                put_packet("OK");
+            } else {
+                goto unknown_command;
+            }
+            break;
         default:
+        unknown_command:
             /* put empty packet */
             buf[0] = '\0';
             put_packet(buf);