]> git.proxmox.com Git - mirror_qemu.git/blobdiff - gdbstub.c
sparc64 marge (Blue Swirl)
[mirror_qemu.git] / gdbstub.c
index 3560b269b93dcf3c74b6d10385771848bec8d6e7..5586df29fbd636c023b0e3f014de445606f9b0c0 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1,7 +1,7 @@
 /*
  * gdb server stub
  * 
- * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2003-2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms 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
  */
+#ifdef CONFIG_USER_ONLY
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "qemu.h"
+#else
 #include "vl.h"
+#endif
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -32,17 +43,25 @@ enum RSState {
     RS_CHKSUM1,
     RS_CHKSUM2,
 };
-
-static int gdbserver_fd;
+/* XXX: This is not thread safe.  Do we care?  */
+static int gdbserver_fd = -1;
 
 typedef struct GDBState {
-    enum RSState state;
+    enum RSState state; /* parsing state */
     int fd;
     char line_buf[4096];
     int line_buf_index;
     int line_csum;
+#ifdef CONFIG_USER_ONLY
+    int running_state;
+#endif
 } GDBState;
 
+#ifdef CONFIG_USER_ONLY
+/* XXX: remove this hack.  */
+static GDBState gdbserver_state;
+#endif
+
 static int get_char(GDBState *s)
 {
     uint8_t ch;
@@ -157,42 +176,40 @@ static int put_packet(GDBState *s, char *buf)
 
 #if defined(TARGET_I386)
 
-static void to_le32(uint8_t *p, int v)
-{
-    p[0] = v;
-    p[1] = v >> 8;
-    p[2] = v >> 16;
-    p[3] = v >> 24;
-}
-
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 {
+    uint32_t *registers = (uint32_t *)mem_buf;
     int i, fpus;
 
     for(i = 0; i < 8; i++) {
-        to_le32(mem_buf + i * 4, env->regs[i]);
+        registers[i] = env->regs[i];
     }
-    to_le32(mem_buf + 8 * 4, env->eip);
-    to_le32(mem_buf + 9 * 4, env->eflags);
-    to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
-    to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
-    to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
-    to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
-    to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
-    to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
+    registers[8] = env->eip;
+    registers[9] = env->eflags;
+    registers[10] = env->segs[R_CS].selector;
+    registers[11] = env->segs[R_SS].selector;
+    registers[12] = env->segs[R_DS].selector;
+    registers[13] = env->segs[R_ES].selector;
+    registers[14] = env->segs[R_FS].selector;
+    registers[15] = env->segs[R_GS].selector;
     /* XXX: convert floats */
     for(i = 0; i < 8; i++) {
         memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
     }
-    to_le32(mem_buf + 36 * 4, env->fpuc);
+    registers[36] = env->fpuc;
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
-    to_le32(mem_buf + 37 * 4, fpus);
-    to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
-    to_le32(mem_buf + 39 * 4, 0); /* fiseg */
-    to_le32(mem_buf + 40 * 4, 0); /* fioff */
-    to_le32(mem_buf + 41 * 4, 0); /* foseg */
-    to_le32(mem_buf + 42 * 4, 0); /* fooff */
-    to_le32(mem_buf + 43 * 4, 0); /* fop */
+    registers[37] = fpus;
+    registers[38] = 0; /* XXX: convert tags */
+    registers[39] = 0; /* fiseg */
+    registers[40] = 0; /* fioff */
+    registers[41] = 0; /* foseg */
+    registers[42] = 0; /* fooff */
+    registers[43] = 0; /* fop */
+    
+    for(i = 0; i < 16; i++)
+        tswapls(&registers[i]);
+    for(i = 36; i < 44; i++)
+        tswapls(&registers[i]);
     return 44 * 4;
 }
 
@@ -204,8 +221,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
     for(i = 0; i < 8; i++) {
         env->regs[i] = tswapl(registers[i]);
     }
-    env->eip = registers[8];
-    env->eflags = registers[9];
+    env->eip = tswapl(registers[8]);
+    env->eflags = tswapl(registers[9]);
 #if defined(CONFIG_USER_ONLY)
 #define LOAD_SEG(index, sreg)\
             if (tswapl(registers[index]) != env->segs[sreg].selector)\
@@ -220,22 +237,6 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
 }
 
 #elif defined (TARGET_PPC)
-static void to_le32(uint32_t *buf, uint32_t v)
-{
-    uint8_t *p = (uint8_t *)buf;
-    p[3] = v;
-    p[2] = v >> 8;
-    p[1] = v >> 16;
-    p[0] = v >> 24;
-}
-
-static uint32_t from_le32 (uint32_t *buf)
-{
-    uint8_t *p = (uint8_t *)buf;
-
-    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-}
-
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 {
     uint32_t *registers = (uint32_t *)mem_buf, tmp;
@@ -243,24 +244,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 
     /* fill in gprs */
     for(i = 0; i < 32; i++) {
-        to_le32(&registers[i], env->gpr[i]);
+        registers[i] = tswapl(env->gpr[i]);
     }
     /* fill in fprs */
     for (i = 0; i < 32; i++) {
-        to_le32(&registers[(i * 2) + 32], *((uint32_t *)&env->fpr[i]));
-       to_le32(&registers[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1));
+        registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
+       registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1));
     }
     /* nip, msr, ccr, lnk, ctr, xer, mq */
-    to_le32(&registers[96], (uint32_t)env->nip/* - 4*/);
-    to_le32(&registers[97], _load_msr(env));
+    registers[96] = tswapl(env->nip);
+    registers[97] = tswapl(_load_msr(env));
     tmp = 0;
     for (i = 0; i < 8; i++)
         tmp |= env->crf[i] << (32 - ((i + 1) * 4));
-    to_le32(&registers[98], tmp);
-    to_le32(&registers[99], env->lr);
-    to_le32(&registers[100], env->ctr);
-    to_le32(&registers[101], _load_xer(env));
-    to_le32(&registers[102], 0);
+    registers[98] = tswapl(tmp);
+    registers[99] = tswapl(env->lr);
+    registers[100] = tswapl(env->ctr);
+    registers[101] = tswapl(_load_xer(env));
+    registers[102] = 0;
 
     return 103 * 4;
 }
@@ -272,25 +273,154 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
 
     /* fill in gprs */
     for (i = 0; i < 32; i++) {
-        env->gpr[i] = from_le32(&registers[i]);
+        env->gpr[i] = tswapl(registers[i]);
     }
     /* fill in fprs */
     for (i = 0; i < 32; i++) {
-        *((uint32_t *)&env->fpr[i]) = from_le32(&registers[(i * 2) + 32]);
-       *((uint32_t *)&env->fpr[i] + 1) = from_le32(&registers[(i * 2) + 33]);
+        *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]);
+       *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]);
     }
     /* nip, msr, ccr, lnk, ctr, xer, mq */
-    env->nip = from_le32(&registers[96]);
-    _store_msr(env, from_le32(&registers[97]));
-    registers[98] = from_le32(&registers[98]);
+    env->nip = tswapl(registers[96]);
+    _store_msr(env, tswapl(registers[97]));
+    registers[98] = tswapl(registers[98]);
     for (i = 0; i < 8; i++)
         env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
-    env->lr = from_le32(&registers[99]);
-    env->ctr = from_le32(&registers[100]);
-    _store_xer(env, from_le32(&registers[101]));
+    env->lr = tswapl(registers[99]);
+    env->ctr = tswapl(registers[100]);
+    _store_xer(env, tswapl(registers[101]));
+}
+#elif defined (TARGET_SPARC)
+static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+{
+    target_ulong *registers = (target_ulong *)mem_buf;
+    int i;
+
+    /* fill in g0..g7 */
+    for(i = 0; i < 7; i++) {
+        registers[i] = tswapl(env->gregs[i]);
+    }
+    /* fill in register window */
+    for(i = 0; i < 24; i++) {
+        registers[i + 8] = tswapl(env->regwptr[i]);
+    }
+    /* fill in fprs */
+    for (i = 0; i < 32; i++) {
+        registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
+    }
+#ifndef TARGET_SPARC64
+    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+    registers[64] = tswapl(env->y);
+    {
+       target_ulong tmp;
+
+       tmp = GET_PSR(env);
+       registers[65] = tswapl(tmp);
+    }
+    registers[66] = tswapl(env->wim);
+    registers[67] = tswapl(env->tbr);
+    registers[68] = tswapl(env->pc);
+    registers[69] = tswapl(env->npc);
+    registers[70] = tswapl(env->fsr);
+    registers[71] = 0; /* csr */
+    registers[72] = 0;
+    return 73 * sizeof(target_ulong);
+#else
+    for (i = 0; i < 32; i += 2) {
+        registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
+    }
+    registers[81] = tswapl(env->pc);
+    registers[82] = tswapl(env->npc);
+    registers[83] = tswapl(env->tstate[env->tl]);
+    registers[84] = tswapl(env->fsr);
+    registers[85] = tswapl(env->fprs);
+    registers[86] = tswapl(env->y);
+    return 87 * sizeof(target_ulong);
+#endif
 }
+
+static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+{
+    target_ulong *registers = (target_ulong *)mem_buf;
+    int i;
+
+    /* fill in g0..g7 */
+    for(i = 0; i < 7; i++) {
+        env->gregs[i] = tswapl(registers[i]);
+    }
+    /* fill in register window */
+    for(i = 0; i < 24; i++) {
+        env->regwptr[i] = tswapl(registers[i + 8]);
+    }
+    /* fill in fprs */
+    for (i = 0; i < 32; i++) {
+        *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
+    }
+#ifndef TARGET_SPARC64
+    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+    env->y = tswapl(registers[64]);
+    PUT_PSR(env, tswapl(registers[65]));
+    env->wim = tswapl(registers[66]);
+    env->tbr = tswapl(registers[67]);
+    env->pc = tswapl(registers[68]);
+    env->npc = tswapl(registers[69]);
+    env->fsr = tswapl(registers[70]);
 #else
+    for (i = 0; i < 32; i += 2) {
+       uint64_t tmp;
+       tmp = tswapl(registers[i/2 + 64]) << 32;
+       tmp |= tswapl(registers[i/2 + 64 + 1]);
+        *((uint64_t *)&env->fpr[i]) = tmp;
+    }
+    env->pc = tswapl(registers[81]);
+    env->npc = tswapl(registers[82]);
+    env->tstate[env->tl] = tswapl(registers[83]);
+    env->fsr = tswapl(registers[84]);
+    env->fprs = tswapl(registers[85]);
+    env->y = tswapl(registers[86]);
+#endif
+}
+#elif defined (TARGET_ARM)
+static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+{
+    int i;
+    uint8_t *ptr;
+
+    ptr = mem_buf;
+    /* 16 core integer registers (4 bytes each).  */
+    for (i = 0; i < 16; i++)
+      {
+        *(uint32_t *)ptr = tswapl(env->regs[i]);
+        ptr += 4;
+      }
+    /* 8 FPA registers (12 bytes each), FPS (4 bytes).
+       Not yet implemented.  */
+    memset (ptr, 0, 8 * 12 + 4);
+    ptr += 8 * 12 + 4;
+    /* CPSR (4 bytes).  */
+    *(uint32_t *)ptr = tswapl (env->cpsr);
+    ptr += 4;
+
+    return ptr - mem_buf;
+}
 
+static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+{
+    int i;
+    uint8_t *ptr;
+
+    ptr = mem_buf;
+    /* Core integer registers.  */
+    for (i = 0; i < 16; i++)
+      {
+        env->regs[i] = tswapl(*(uint32_t *)ptr);
+        ptr += 4;
+      }
+    /* Ignore FPA regs and scr.  */
+    ptr += 8 * 12 + 4;
+    env->cpsr = tswapl(*(uint32_t *)ptr);
+}
+#else
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 {
     return 0;
@@ -302,10 +432,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
 
 #endif
 
-/* port = 0 means default port */
-static int gdb_handle_packet(GDBState *s, const char *line_buf)
+static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
 {
-    CPUState *env = cpu_single_env;
     const char *p;
     int ch, reg_size, type;
     char buf[4096];
@@ -320,6 +448,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
     ch = *p++;
     switch(ch) {
     case '?':
+        /* TODO: Make this return the correct value for user-mode.  */
         snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
         put_packet(s, buf);
         break;
@@ -330,10 +459,17 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             env->eip = addr;
 #elif defined (TARGET_PPC)
             env->nip = addr;
+#elif defined (TARGET_SPARC)
+            env->pc = addr;
+            env->npc = addr + 4;
 #endif
         }
+#ifdef CONFIG_USER_ONLY
+        s->running_state = 1;
+#else
         vm_start();
-        break;
+#endif
+       return RS_IDLE;
     case 's':
         if (*p != '\0') {
             addr = strtoul(p, (char **)&p, 16);
@@ -341,11 +477,18 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             env->eip = addr;
 #elif defined (TARGET_PPC)
             env->nip = addr;
+#elif defined (TARGET_SPARC)
+            env->pc = addr;
+            env->npc = addr + 4;
 #endif
         }
         cpu_single_step(env, 1);
+#ifdef CONFIG_USER_ONLY
+        s->running_state = 1;
+#else
         vm_start();
-        break;
+#endif
+       return RS_IDLE;
     case 'g':
         reg_size = cpu_gdb_read_registers(env, mem_buf);
         memtohex(buf, mem_buf, reg_size);
@@ -373,11 +516,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ',')
             p++;
         len = strtoul(p, (char **)&p, 16);
-        if (*p == ',')
+        if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
         if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
-            put_packet(s, "ENN");
+            put_packet(s, "E14");
         else
             put_packet(s, "OK");
         break;
@@ -395,7 +538,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             put_packet(s, "OK");
         } else {
         breakpoint_error:
-            put_packet(s, "ENN");
+            put_packet(s, "E22");
         }
         break;
     case 'z':
@@ -423,6 +566,9 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
     return RS_IDLE;
 }
 
+extern void tb_flush(CPUState *env);
+
+#ifndef CONFIG_USER_ONLY
 static void gdb_vm_stopped(void *opaque, int reason)
 {
     GDBState *s = opaque;
@@ -432,24 +578,30 @@ static void gdb_vm_stopped(void *opaque, int reason)
     /* disable single step if it was enable */
     cpu_single_step(cpu_single_env, 0);
 
-    if (reason == EXCP_DEBUG)
+    if (reason == EXCP_DEBUG) {
+       tb_flush(cpu_single_env);
         ret = SIGTRAP;
+    }
     else
         ret = 0;
     snprintf(buf, sizeof(buf), "S%02x", ret);
     put_packet(s, buf);
 }
+#endif
 
-static void gdb_read_byte(GDBState *s, int ch)
+static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
 {
     int i, csum;
     char reply[1];
 
+#ifndef CONFIG_USER_ONLY
     if (vm_running) {
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
         vm_stop(EXCP_INTERRUPT);
-    } else {
+    } else 
+#endif
+    {
         switch(s->state) {
         case RS_IDLE:
             if (ch == '$') {
@@ -484,13 +636,74 @@ static void gdb_read_byte(GDBState *s, int ch)
             } else {
                 reply[0] = '+';
                 put_buffer(s, reply, 1);
-                s->state = gdb_handle_packet(s, s->line_buf);
+                s->state = gdb_handle_packet(s, env, s->line_buf);
             }
             break;
         }
     }
 }
 
+#ifdef CONFIG_USER_ONLY
+int
+gdb_handlesig (CPUState *env, int sig)
+{
+  GDBState *s;
+  char buf[256];
+  int n;
+
+  if (gdbserver_fd < 0)
+    return sig;
+
+  s = &gdbserver_state;
+
+  /* disable single step if it was enabled */
+  cpu_single_step(env, 0);
+  tb_flush(env);
+
+  if (sig != 0)
+    {
+      snprintf(buf, sizeof(buf), "S%02x", sig);
+      put_packet(s, buf);
+    }
+
+  sig = 0;
+  s->state = RS_IDLE;
+  s->running_state = 0;
+  while (s->running_state == 0) {
+      n = read (s->fd, buf, 256);
+      if (n > 0)
+        {
+          int i;
+
+          for (i = 0; i < n; i++)
+            gdb_read_byte (s, env, buf[i]);
+        }
+      else if (n == 0 || errno != EAGAIN)
+        {
+          /* XXX: Connection closed.  Should probably wait for annother
+             connection before continuing.  */
+          return sig;
+        }
+  }
+  return sig;
+}
+
+/* Tell the remote gdb that the process has exited.  */
+void gdb_exit(CPUState *env, int code)
+{
+  GDBState *s;
+  char buf[4];
+
+  if (gdbserver_fd < 0)
+    return;
+
+  s = &gdbserver_state;
+
+  snprintf(buf, sizeof(buf), "W%02x", code);
+  put_packet(s, buf);
+}
+
+#else
 static int gdb_can_read(void *opaque)
 {
     return 256;
@@ -508,10 +721,12 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size)
         vm_start();
     } else {
         for(i = 0; i < size; i++)
-            gdb_read_byte(s, buf[i]);
+            gdb_read_byte(s, cpu_single_env, buf[i]);
     }
 }
 
+#endif
+
 static void gdb_accept(void *opaque, const uint8_t *buf, int size)
 {
     GDBState *s;
@@ -532,17 +747,23 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
 
     /* set short latency */
     val = 1;
-    setsockopt(fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
+    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
     
+#ifdef CONFIG_USER_ONLY
+    s = &gdbserver_state;
+    memset (s, 0, sizeof (GDBState));
+#else
     s = qemu_mallocz(sizeof(GDBState));
     if (!s) {
         close(fd);
         return;
     }
+#endif
     s->fd = fd;
 
     fcntl(fd, F_SETFL, O_NONBLOCK);
 
+#ifndef CONFIG_USER_ONLY
     /* stop the VM */
     vm_stop(EXCP_INTERRUPT);
 
@@ -550,6 +771,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
     qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
     /* when the VM is stopped, the following callback is called */
     qemu_add_vm_stop_handler(gdb_vm_stopped, s);
+#endif
 }
 
 static int gdbserver_open(int port)
@@ -580,7 +802,9 @@ static int gdbserver_open(int port)
         perror("listen");
         return -1;
     }
+#ifndef CONFIG_USER_ONLY
     fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
     return fd;
 }
 
@@ -590,6 +814,10 @@ int gdbserver_start(int port)
     if (gdbserver_fd < 0)
         return -1;
     /* accept connections */
+#ifdef CONFIG_USER_ONLY
+    gdb_accept (NULL, NULL, 0);
+#else
     qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
+#endif
     return 0;
 }