]> git.proxmox.com Git - qemu.git/blobdiff - gdbstub.c
Store VNC auth scheme per-client as well as per-server
[qemu.git] / gdbstub.c
index 7b32fab589343c4e231dacfdf2c1fc30b8abc875..c085a5afb33cc0ae2cab61cfe087cfa6da51a428 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -14,8 +14,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "config.h"
 #include "qemu-common.h"
@@ -38,6 +37,7 @@
 
 #define MAX_PACKET_LENGTH 4096
 
+#include "cpu.h"
 #include "qemu_socket.h"
 #include "kvm.h"
 
 enum {
     GDB_SIGNAL_0 = 0,
     GDB_SIGNAL_INT = 2,
+    GDB_SIGNAL_QUIT = 3,
     GDB_SIGNAL_TRAP = 5,
+    GDB_SIGNAL_ABRT = 6,
+    GDB_SIGNAL_ALRM = 14,
+    GDB_SIGNAL_IO = 23,
+    GDB_SIGNAL_XCPU = 24,
     GDB_SIGNAL_UNKNOWN = 143
 };
 
@@ -506,116 +511,169 @@ static const int gpr_map[16] = {
     8, 9, 10, 11, 12, 13, 14, 15
 };
 #else
-static const int gpr_map[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+#define gpr_map gpr_map32
 #endif
+static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
 
 #define NUM_CORE_REGS (CPU_NB_REGS * 2 + 25)
 
+#define IDX_IP_REG      CPU_NB_REGS
+#define IDX_FLAGS_REG   (IDX_IP_REG + 1)
+#define IDX_SEG_REGS    (IDX_FLAGS_REG + 1)
+#define IDX_FP_REGS     (IDX_SEG_REGS + 6)
+#define IDX_XMM_REGS    (IDX_FP_REGS + 16)
+#define IDX_MXCSR_REG   (IDX_XMM_REGS + CPU_NB_REGS)
+
 static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
     if (n < CPU_NB_REGS) {
-        GET_REGL(env->regs[gpr_map[n]]);
-    } else if (n >= CPU_NB_REGS + 8 && n < CPU_NB_REGS + 16) {
-        /* FIXME: byteswap float values.  */
+        if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+            GET_REG64(env->regs[gpr_map[n]]);
+        } else if (n < CPU_NB_REGS32) {
+            GET_REG32(env->regs[gpr_map32[n]]);
+        }
+    } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
 #ifdef USE_X86LDOUBLE
-        memcpy(mem_buf, &env->fpregs[n - (CPU_NB_REGS + 8)], 10);
+        /* FIXME: byteswap float values - after fixing fpregs layout. */
+        memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
 #else
         memset(mem_buf, 0, 10);
 #endif
         return 10;
-    } else if (n >= CPU_NB_REGS + 24) {
-        n -= CPU_NB_REGS + 24;
-        if (n < CPU_NB_REGS) {
+    } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
+        n -= IDX_XMM_REGS;
+        if (n < CPU_NB_REGS32 ||
+            (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
             stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
             stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1));
             return 16;
-        } else if (n == CPU_NB_REGS) {
-            GET_REG32(env->mxcsr);
-        } 
+        }
     } else {
-        n -= CPU_NB_REGS;
         switch (n) {
-        case 0: GET_REGL(env->eip);
-        case 1: GET_REG32(env->eflags);
-        case 2: GET_REG32(env->segs[R_CS].selector);
-        case 3: GET_REG32(env->segs[R_SS].selector);
-        case 4: GET_REG32(env->segs[R_DS].selector);
-        case 5: GET_REG32(env->segs[R_ES].selector);
-        case 6: GET_REG32(env->segs[R_FS].selector);
-        case 7: GET_REG32(env->segs[R_GS].selector);
-        /* 8...15 x87 regs.  */
-        case 16: GET_REG32(env->fpuc);
-        case 17: GET_REG32((env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11);
-        case 18: GET_REG32(0); /* ftag */
-        case 19: GET_REG32(0); /* fiseg */
-        case 20: GET_REG32(0); /* fioff */
-        case 21: GET_REG32(0); /* foseg */
-        case 22: GET_REG32(0); /* fooff */
-        case 23: GET_REG32(0); /* fop */
-        /* 24+ xmm regs.  */
+        case IDX_IP_REG:
+            if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+                GET_REG64(env->eip);
+            } else {
+                GET_REG32(env->eip);
+            }
+        case IDX_FLAGS_REG: GET_REG32(env->eflags);
+
+        case IDX_SEG_REGS:     GET_REG32(env->segs[R_CS].selector);
+        case IDX_SEG_REGS + 1: GET_REG32(env->segs[R_SS].selector);
+        case IDX_SEG_REGS + 2: GET_REG32(env->segs[R_DS].selector);
+        case IDX_SEG_REGS + 3: GET_REG32(env->segs[R_ES].selector);
+        case IDX_SEG_REGS + 4: GET_REG32(env->segs[R_FS].selector);
+        case IDX_SEG_REGS + 5: GET_REG32(env->segs[R_GS].selector);
+
+        case IDX_FP_REGS + 8:  GET_REG32(env->fpuc);
+        case IDX_FP_REGS + 9:  GET_REG32((env->fpus & ~0x3800) |
+                                         (env->fpstt & 0x7) << 11);
+        case IDX_FP_REGS + 10: GET_REG32(0); /* ftag */
+        case IDX_FP_REGS + 11: GET_REG32(0); /* fiseg */
+        case IDX_FP_REGS + 12: GET_REG32(0); /* fioff */
+        case IDX_FP_REGS + 13: GET_REG32(0); /* foseg */
+        case IDX_FP_REGS + 14: GET_REG32(0); /* fooff */
+        case IDX_FP_REGS + 15: GET_REG32(0); /* fop */
+
+        case IDX_MXCSR_REG: GET_REG32(env->mxcsr);
         }
     }
     return 0;
 }
 
-static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int i)
+static int cpu_x86_gdb_load_seg(CPUState *env, int sreg, uint8_t *mem_buf)
+{
+    uint16_t selector = ldl_p(mem_buf);
+
+    if (selector != env->segs[sreg].selector) {
+#if defined(CONFIG_USER_ONLY)
+        cpu_x86_load_seg(env, sreg, selector);
+#else
+        unsigned int limit, flags;
+        target_ulong base;
+
+        if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+            base = selector << 4;
+            limit = 0xffff;
+            flags = 0;
+        } else {
+            if (!cpu_x86_get_descr_debug(env, selector, &base, &limit, &flags))
+                return 4;
+        }
+        cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags);
+#endif
+    }
+    return 4;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
     uint32_t tmp;
 
-    if (i < CPU_NB_REGS) {
-        env->regs[gpr_map[i]] = ldtul_p(mem_buf);
-        return sizeof(target_ulong);
-    } else if (i >= CPU_NB_REGS + 8 && i < CPU_NB_REGS + 16) {
-        i -= CPU_NB_REGS + 8;
+    if (n < CPU_NB_REGS) {
+        if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+            env->regs[gpr_map[n]] = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        } else if (n < CPU_NB_REGS32) {
+            n = gpr_map32[n];
+            env->regs[n] &= ~0xffffffffUL;
+            env->regs[n] |= (uint32_t)ldl_p(mem_buf);
+            return 4;
+        }
+    } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
 #ifdef USE_X86LDOUBLE
-        memcpy(&env->fpregs[i], mem_buf, 10);
+        /* FIXME: byteswap float values - after fixing fpregs layout. */
+        memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
 #endif
         return 10;
-    } else if (i >= CPU_NB_REGS + 24) {
-        i -= CPU_NB_REGS + 24;
-        if (i < CPU_NB_REGS) {
-            env->xmm_regs[i].XMM_Q(0) = ldq_p(mem_buf);
-            env->xmm_regs[i].XMM_Q(1) = ldq_p(mem_buf + 8);
+    } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
+        n -= IDX_XMM_REGS;
+        if (n < CPU_NB_REGS32 ||
+            (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
+            env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf);
+            env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8);
             return 16;
-        } else if (i == CPU_NB_REGS) {
-            env->mxcsr = ldl_p(mem_buf);
-            return 4;
         }
     } else {
-        i -= CPU_NB_REGS;
-        switch (i) {
-        case 0: env->eip = ldtul_p(mem_buf); return sizeof(target_ulong);
-        case 1: env->eflags = ldl_p(mem_buf); return 4;
-#if defined(CONFIG_USER_ONLY)
-#define LOAD_SEG(index, sreg)\
-            tmp = ldl_p(mem_buf);\
-            if (tmp != env->segs[sreg].selector)\
-                cpu_x86_load_seg(env, sreg, tmp);
-#else
-/* FIXME: Honor segment registers.  Needs to avoid raising an exception
-   when the selector is invalid.  */
-#define LOAD_SEG(index, sreg) do {} while(0)
-#endif
-        case 2: LOAD_SEG(10, R_CS); return 4;
-        case 3: LOAD_SEG(11, R_SS); return 4;
-        case 4: LOAD_SEG(12, R_DS); return 4;
-        case 5: LOAD_SEG(13, R_ES); return 4;
-        case 6: LOAD_SEG(14, R_FS); return 4;
-        case 7: LOAD_SEG(15, R_GS); return 4;
-        /* 8...15 x87 regs.  */
-        case 16: env->fpuc = ldl_p(mem_buf); return 4;
-        case 17:
-                 tmp = ldl_p(mem_buf);
-                 env->fpstt = (tmp >> 11) & 7;
-                 env->fpus = tmp & ~0x3800;
-                 return 4;
-        case 18: /* ftag */ return 4;
-        case 19: /* fiseg */ return 4;
-        case 20: /* fioff */ return 4;
-        case 21: /* foseg */ return 4;
-        case 22: /* fooff */ return 4;
-        case 23: /* fop */ return 4;
-        /* 24+ xmm regs.  */
+        switch (n) {
+        case IDX_IP_REG:
+            if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+                env->eip = ldq_p(mem_buf);
+                return 8;
+            } else {
+                env->eip &= ~0xffffffffUL;
+                env->eip |= (uint32_t)ldl_p(mem_buf);
+                return 4;
+            }
+        case IDX_FLAGS_REG:
+            env->eflags = ldl_p(mem_buf);
+            return 4;
+
+        case IDX_SEG_REGS:     return cpu_x86_gdb_load_seg(env, R_CS, mem_buf);
+        case IDX_SEG_REGS + 1: return cpu_x86_gdb_load_seg(env, R_SS, mem_buf);
+        case IDX_SEG_REGS + 2: return cpu_x86_gdb_load_seg(env, R_DS, mem_buf);
+        case IDX_SEG_REGS + 3: return cpu_x86_gdb_load_seg(env, R_ES, mem_buf);
+        case IDX_SEG_REGS + 4: return cpu_x86_gdb_load_seg(env, R_FS, mem_buf);
+        case IDX_SEG_REGS + 5: return cpu_x86_gdb_load_seg(env, R_GS, mem_buf);
+
+        case IDX_FP_REGS + 8:
+            env->fpuc = ldl_p(mem_buf);
+            return 4;
+        case IDX_FP_REGS + 9:
+            tmp = ldl_p(mem_buf);
+            env->fpstt = (tmp >> 11) & 7;
+            env->fpus = tmp & ~0x3800;
+            return 4;
+        case IDX_FP_REGS + 10: /* ftag */  return 4;
+        case IDX_FP_REGS + 11: /* fiseg */ return 4;
+        case IDX_FP_REGS + 12: /* fioff */ return 4;
+        case IDX_FP_REGS + 13: /* foseg */ return 4;
+        case IDX_FP_REGS + 14: /* fooff */ return 4;
+        case IDX_FP_REGS + 15: /* fop */   return 4;
+
+        case IDX_MXCSR_REG:
+            env->mxcsr = ldl_p(mem_buf);
+            return 4;
         }
     }
     /* Unrecognised register.  */
@@ -752,7 +810,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
     switch (n) {
     case 64: GET_REGA(env->y);
-    case 65: GET_REGA(GET_PSR(env));
+    case 65: GET_REGA(cpu_get_psr(env));
     case 66: GET_REGA(env->wim);
     case 67: GET_REGA(env->tbr);
     case 68: GET_REGA(env->pc);
@@ -777,10 +835,10 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
     switch (n) {
     case 80: GET_REGL(env->pc);
     case 81: GET_REGL(env->npc);
-    case 82: GET_REGL(((uint64_t)GET_CCR(env) << 32) |
-                           ((env->asi & 0xff) << 24) |
-                           ((env->pstate & 0xfff) << 8) |
-                           GET_CWP64(env));
+    case 82: GET_REGL((cpu_get_ccr(env) << 32) |
+                      ((env->asi & 0xff) << 24) |
+                      ((env->pstate & 0xfff) << 8) |
+                      cpu_get_cwp64(env));
     case 83: GET_REGL(env->fsr);
     case 84: GET_REGL(env->fprs);
     case 85: GET_REGL(env->y);
@@ -816,7 +874,7 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
         /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
         switch (n) {
         case 64: env->y = tmp; break;
-        case 65: PUT_PSR(env, tmp); break;
+        case 65: cpu_put_psr(env, tmp); break;
         case 66: env->wim = tmp; break;
         case 67: env->tbr = tmp; break;
         case 68: env->pc = tmp; break;
@@ -840,10 +898,10 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
         case 80: env->pc = tmp; break;
         case 81: env->npc = tmp; break;
         case 82:
-           PUT_CCR(env, tmp >> 32);
+            cpu_put_ccr(env, tmp >> 32);
            env->asi = (tmp >> 24) & 0xff;
            env->pstate = (tmp >> 8) & 0xfff;
-           PUT_CWP64(env, tmp & 0xff);
+            cpu_put_cwp64(env, tmp & 0xff);
            break;
         case 83: env->fsr = tmp; break;
         case 84: env->fprs = tmp; break;
@@ -962,7 +1020,7 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
     if (n < 8) {
         /* D0-D7 */
         env->dregs[n] = tmp;
-    } else if (n < 8) {
+    } else if (n < 16) {
         /* A0-A7 */
         env->aregs[n - 8] = tmp;
     } else {
@@ -1001,7 +1059,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
     case 34: GET_REGL(env->active_tc.HI[0]);
     case 35: GET_REGL(env->CP0_BadVAddr);
     case 36: GET_REGL((int32_t)env->CP0_Cause);
-    case 37: GET_REGL(env->active_tc.PC);
+    case 37: GET_REGL(env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16));
     case 72: GET_REGL(0); /* fp */
     case 89: GET_REGL((int32_t)env->CP0_PRid);
     }
@@ -1047,10 +1105,6 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
             env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
             /* set rounding mode */
             RESTORE_ROUNDING_MODE;
-#ifndef CONFIG_SOFTFLOAT
-            /* no floating point exception for native float */
-            SET_FP_ENABLE(env->active_fpu.fcr31, 0);
-#endif
             break;
         case 71: env->active_fpu.fcr0 = tmp; break;
         }
@@ -1062,7 +1116,14 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
     case 34: env->active_tc.HI[0] = tmp; break;
     case 35: env->CP0_BadVAddr = tmp; break;
     case 36: env->CP0_Cause = tmp; break;
-    case 37: env->active_tc.PC = tmp; break;
+    case 37:
+        env->active_tc.PC = tmp & ~(target_ulong)1;
+        if (tmp & 1) {
+            env->hflags |= MIPS_HFLAG_M16;
+        } else {
+            env->hflags &= ~(MIPS_HFLAG_M16);
+        }
+        break;
     case 72: /* fp, ignored */ break;
     default: 
        if (n > 89)
@@ -1089,7 +1150,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
             GET_REGL(env->gregs[n]);
         }
     } else if (n < 16) {
-        GET_REGL(env->gregs[n - 8]);
+        GET_REGL(env->gregs[n]);
     } else if (n >= 25 && n < 41) {
        GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
     } else if (n >= 43 && n < 51) {
@@ -1128,10 +1189,11 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
         }
        return 4;
     } else if (n < 16) {
-        env->gregs[n - 8] = tmp;
+        env->gregs[n] = tmp;
        return 4;
     } else if (n >= 25 && n < 41) {
        env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp;
+       return 4;
     } else if (n >= 43 && n < 51) {
        env->gregs[n - 43] = tmp;
        return 4;
@@ -1140,17 +1202,17 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
        return 4;
     }
     switch (n) {
-    case 16: env->pc = tmp;
-    case 17: env->pr = tmp;
-    case 18: env->gbr = tmp;
-    case 19: env->vbr = tmp;
-    case 20: env->mach = tmp;
-    case 21: env->macl = tmp;
-    case 22: env->sr = tmp;
-    case 23: env->fpul = tmp;
-    case 24: env->fpscr = tmp;
-    case 41: env->ssr = tmp;
-    case 42: env->spc = tmp;
+    case 16: env->pc = tmp; break;
+    case 17: env->pr = tmp; break;
+    case 18: env->gbr = tmp; break;
+    case 19: env->vbr = tmp; break;
+    case 20: env->mach = tmp; break;
+    case 21: env->macl = tmp; break;
+    case 22: env->sr = tmp; break;
+    case 23: env->fpul = tmp; break;
+    case 24: env->fpscr = tmp; break;
+    case 41: env->ssr = tmp; break;
+    case 42: env->spc = tmp; break;
     default: return 0;
     }
 
@@ -1190,10 +1252,46 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 
 #define NUM_CORE_REGS 49
 
+static int
+read_register_crisv10(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 15) {
+        GET_REG32(env->regs[n]);
+    }
+
+    if (n == 15) {
+        GET_REG32(env->pc);
+    }
+
+    if (n < 32) {
+        switch (n) {
+        case 16:
+            GET_REG8(env->pregs[n - 16]);
+            break;
+        case 17:
+            GET_REG8(env->pregs[n - 16]);
+            break;
+        case 20:
+        case 21:
+            GET_REG16(env->pregs[n - 16]);
+            break;
+        default:
+            if (n >= 23) {
+                GET_REG32(env->pregs[n - 16]);
+            }
+            break;
+        }
+    }
+    return 0;
+}
+
 static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
     uint8_t srs;
 
+    if (env->pregs[PR_VR] < 32)
+        return read_register_crisv10(env, mem_buf, n);
+
     srs = env->pregs[PR_SRS];
     if (n < 16) {
        GET_REG32(env->regs[n]);
@@ -1248,30 +1346,97 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 }
 #elif defined (TARGET_ALPHA)
 
-#define NUM_CORE_REGS 65
+#define NUM_CORE_REGS 67
 
 static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    if (n < 31) {
-       GET_REGL(env->ir[n]);
-    }
-    else if (n == 31) {
-       GET_REGL(0);
-    }
-    else if (n<63) {
-       uint64_t val;
+    uint64_t val;
+    CPU_DoubleU d;
 
-       val=*((uint64_t *)&env->fir[n-32]);
-       GET_REGL(val);
-    }
-    else if (n==63) {
-       GET_REGL(env->fpcr);
+    switch (n) {
+    case 0 ... 30:
+        val = env->ir[n];
+        break;
+    case 32 ... 62:
+        d.d = env->fir[n - 32];
+        val = d.ll;
+        break;
+    case 63:
+        val = cpu_alpha_load_fpcr(env);
+        break;
+    case 64:
+        val = env->pc;
+        break;
+    case 66:
+        val = env->unique;
+        break;
+    case 31:
+    case 65:
+        /* 31 really is the zero register; 65 is unassigned in the
+           gdb protocol, but is still required to occupy 8 bytes. */
+        val = 0;
+        break;
+    default:
+        return 0;
     }
-    else if (n==64) {
-       GET_REGL(env->pc);
+    GET_REGL(val);
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    target_ulong tmp = ldtul_p(mem_buf);
+    CPU_DoubleU d;
+
+    switch (n) {
+    case 0 ... 30:
+        env->ir[n] = tmp;
+        break;
+    case 32 ... 62:
+        d.ll = tmp;
+        env->fir[n - 32] = d.d;
+        break;
+    case 63:
+        cpu_alpha_store_fpcr(env, tmp);
+        break;
+    case 64:
+        env->pc = tmp;
+        break;
+    case 66:
+        env->unique = tmp;
+        break;
+    case 31:
+    case 65:
+        /* 31 really is the zero register; 65 is unassigned in the
+           gdb protocol, but is still required to occupy 8 bytes. */
+        break;
+    default:
+        return 0;
     }
-    else {
-       GET_REGL(0);
+    return 8;
+}
+#elif defined (TARGET_S390X)
+
+#define NUM_CORE_REGS S390_NUM_TOTAL_REGS
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    switch (n) {
+        case S390_PSWM_REGNUM: GET_REGL(env->psw.mask); break;
+        case S390_PSWA_REGNUM: GET_REGL(env->psw.addr); break;
+        case S390_R0_REGNUM ... S390_R15_REGNUM:
+            GET_REGL(env->regs[n-S390_R0_REGNUM]); break;
+        case S390_A0_REGNUM ... S390_A15_REGNUM:
+            GET_REG32(env->aregs[n-S390_A0_REGNUM]); break;
+        case S390_FPC_REGNUM: GET_REG32(env->fpc); break;
+        case S390_F0_REGNUM ... S390_F15_REGNUM:
+            /* XXX */
+            break;
+        case S390_PC_REGNUM: GET_REGL(env->psw.addr); break;
+        case S390_CC_REGNUM:
+            env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
+                                 env->cc_vr);
+            GET_REG32(env->cc_op);
+            break;
     }
 
     return 0;
@@ -1279,22 +1444,102 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 
 static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    target_ulong tmp;
-    tmp = ldtul_p(mem_buf);
+    target_ulong tmpl;
+    uint32_t tmp32;
+    int r = 8;
+    tmpl = ldtul_p(mem_buf);
+    tmp32 = ldl_p(mem_buf);
 
-    if (n < 31) {
-        env->ir[n] = tmp;
+    switch (n) {
+        case S390_PSWM_REGNUM: env->psw.mask = tmpl; break;
+        case S390_PSWA_REGNUM: env->psw.addr = tmpl; break;
+        case S390_R0_REGNUM ... S390_R15_REGNUM:
+            env->regs[n-S390_R0_REGNUM] = tmpl; break;
+        case S390_A0_REGNUM ... S390_A15_REGNUM:
+            env->aregs[n-S390_A0_REGNUM] = tmp32; r=4; break;
+        case S390_FPC_REGNUM: env->fpc = tmp32; r=4; break;
+        case S390_F0_REGNUM ... S390_F15_REGNUM:
+            /* XXX */
+            break;
+        case S390_PC_REGNUM: env->psw.addr = tmpl; break;
+        case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break;
     }
 
-    if (n > 31 && n < 63) {
-        env->fir[n - 32] = ldfl_p(mem_buf);
+    return r;
+}
+#elif defined (TARGET_LM32)
+
+#include "hw/lm32_pic.h"
+#define NUM_CORE_REGS (32 + 7)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        GET_REG32(env->regs[n]);
+    } else {
+        switch (n) {
+        case 32:
+            GET_REG32(env->pc);
+            break;
+        /* FIXME: put in right exception ID */
+        case 33:
+            GET_REG32(0);
+            break;
+        case 34:
+            GET_REG32(env->eba);
+            break;
+        case 35:
+            GET_REG32(env->deba);
+            break;
+        case 36:
+            GET_REG32(env->ie);
+            break;
+        case 37:
+            GET_REG32(lm32_pic_get_im(env->pic_state));
+            break;
+        case 38:
+            GET_REG32(lm32_pic_get_ip(env->pic_state));
+            break;
+        }
     }
+    return 0;
+}
 
-    if (n == 64 ) {
-       env->pc=tmp;
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > NUM_CORE_REGS) {
+        return 0;
     }
 
-    return 8;
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+        env->regs[n] = tmp;
+    } else {
+        switch (n) {
+        case 32:
+            env->pc = tmp;
+            break;
+        case 34:
+            env->eba = tmp;
+            break;
+        case 35:
+            env->deba = tmp;
+            break;
+        case 36:
+            env->ie = tmp;
+            break;
+        case 37:
+            lm32_pic_set_im(env->pic_state, tmp);
+            break;
+        case 38:
+            lm32_pic_set_ip(env->pic_state, tmp);
+            break;
+        }
+    }
+    return 4;
 }
 #else
 
@@ -1338,7 +1583,6 @@ static int memtox(char *buf, const char *mem, int len)
 
 static const char *get_feature_xml(const char *p, const char **newp)
 {
-    extern const char *const xml_builtin[][2];
     size_t len;
     int i;
     const char *name;
@@ -1545,8 +1789,8 @@ static void gdb_breakpoint_remove_all(void)
 static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 {
 #if defined(TARGET_I386)
+    cpu_synchronize_state(s->c_cpu);
     s->c_cpu->eip = pc;
-    cpu_synchronize_state(s->c_cpu, 1);
 #elif defined (TARGET_PPC)
     s->c_cpu->nip = pc;
 #elif defined (TARGET_SPARC)
@@ -1557,21 +1801,54 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #elif defined (TARGET_SH4)
     s->c_cpu->pc = pc;
 #elif defined (TARGET_MIPS)
-    s->c_cpu->active_tc.PC = pc;
+    s->c_cpu->active_tc.PC = pc & ~(target_ulong)1;
+    if (pc & 1) {
+        s->c_cpu->hflags |= MIPS_HFLAG_M16;
+    } else {
+        s->c_cpu->hflags &= ~(MIPS_HFLAG_M16);
+    }
 #elif defined (TARGET_MICROBLAZE)
     s->c_cpu->sregs[SR_PC] = pc;
 #elif defined (TARGET_CRIS)
     s->c_cpu->pc = pc;
 #elif defined (TARGET_ALPHA)
     s->c_cpu->pc = pc;
+#elif defined (TARGET_S390X)
+    cpu_synchronize_state(s->c_cpu);
+    s->c_cpu->psw.addr = pc;
+#elif defined (TARGET_LM32)
+    s->c_cpu->pc = pc;
+#endif
+}
+
+static inline int gdb_id(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+    return env->host_tid;
+#else
+    return env->cpu_index + 1;
 #endif
 }
 
+static CPUState *find_cpu(uint32_t thread_id)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (gdb_id(env) == thread_id) {
+            return env;
+        }
+    }
+
+    return NULL;
+}
+
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
     CPUState *env;
     const char *p;
-    int ch, reg_size, type, res, thread;
+    uint32_t thread;
+    int ch, reg_size, type, res;
     char buf[MAX_PACKET_LENGTH];
     uint8_t mem_buf[MAX_PACKET_LENGTH];
     uint8_t *registers;
@@ -1586,7 +1863,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
     case '?':
         /* TODO: Make this return the correct value for user-mode.  */
         snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
-                 s->c_cpu->cpu_index+1);
+                 gdb_id(s->c_cpu));
         put_packet(s, buf);
         /* Remove all the breakpoints when this query is issued,
          * because gdb is doing and initial connect and the state
@@ -1608,6 +1885,64 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             s->signal = 0;
         gdb_continue(s);
         return RS_IDLE;
+    case 'v':
+        if (strncmp(p, "Cont", 4) == 0) {
+            int res_signal, res_thread;
+
+            p += 4;
+            if (*p == '?') {
+                put_packet(s, "vCont;c;C;s;S");
+                break;
+            }
+            res = 0;
+            res_signal = 0;
+            res_thread = 0;
+            while (*p) {
+                int action, signal;
+
+                if (*p++ != ';') {
+                    res = 0;
+                    break;
+                }
+                action = *p++;
+                signal = 0;
+                if (action == 'C' || action == 'S') {
+                    signal = strtoul(p, (char **)&p, 16);
+                } else if (action != 'c' && action != 's') {
+                    res = 0;
+                    break;
+                }
+                thread = 0;
+                if (*p == ':') {
+                    thread = strtoull(p+1, (char **)&p, 16);
+                }
+                action = tolower(action);
+                if (res == 0 || (res == 'c' && action == 's')) {
+                    res = action;
+                    res_signal = signal;
+                    res_thread = thread;
+                }
+            }
+            if (res) {
+                if (res_thread != -1 && res_thread != 0) {
+                    env = find_cpu(res_thread);
+                    if (env == NULL) {
+                        put_packet(s, "E22");
+                        break;
+                    }
+                    s->c_cpu = env;
+                }
+                if (res == 's') {
+                    cpu_single_step(s->c_cpu, sstep_flags);
+                }
+                s->signal = res_signal;
+                gdb_continue(s);
+                return RS_IDLE;
+            }
+            break;
+        } else {
+            goto unknown_command;
+        }
     case 'k':
         /* Kill the target */
         fprintf(stderr, "\nQEMU: Terminated via GDBstub\n");
@@ -1615,6 +1950,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
     case 'D':
         /* Detach packet */
         gdb_breakpoint_remove_all();
+        gdb_syscall_mode = GDB_SYS_DISABLED;
         gdb_continue(s);
         put_packet(s, "OK");
         break;
@@ -1651,7 +1987,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         }
         break;
     case 'g':
-        cpu_synchronize_state(s->g_cpu, 0);
+        cpu_synchronize_state(s->g_cpu);
         len = 0;
         for (addr = 0; addr < num_g_regs; addr++) {
             reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -1661,6 +1997,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         put_packet(s, buf);
         break;
     case 'G':
+        cpu_synchronize_state(s->g_cpu);
         registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
@@ -1669,7 +2006,6 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             len -= reg_size;
             registers += reg_size;
         }
-        cpu_synchronize_state(s->g_cpu, 1);
         put_packet(s, "OK");
         break;
     case 'm':
@@ -1750,9 +2086,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             put_packet(s, "OK");
             break;
         }
-        for (env = first_cpu; env != NULL; env = env->next_cpu)
-            if (env->cpu_index + 1 == thread)
-                break;
+        env = find_cpu(thread);
         if (env == NULL) {
             put_packet(s, "E22");
             break;
@@ -1773,14 +2107,13 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'T':
         thread = strtoull(p, (char **)&p, 16);
-#ifndef CONFIG_USER_ONLY
-        if (thread > 0 && thread < smp_cpus + 1)
-#else
-        if (thread == 1)
-#endif
-             put_packet(s, "OK");
-        else
+        env = find_cpu(thread);
+
+        if (env != NULL) {
+            put_packet(s, "OK");
+        } else {
             put_packet(s, "E22");
+        }
         break;
     case 'q':
     case 'Q':
@@ -1818,7 +2151,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         } else if (strcmp(p,"sThreadInfo") == 0) {
         report_cpuinfo:
             if (s->query_cpu) {
-                snprintf(buf, sizeof(buf), "m%x", s->query_cpu->cpu_index+1);
+                snprintf(buf, sizeof(buf), "m%x", gdb_id(s->query_cpu));
                 put_packet(s, buf);
                 s->query_cpu = s->query_cpu->next_cpu;
             } else
@@ -1826,16 +2159,15 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             break;
         } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
             thread = strtoull(p+16, (char **)&p, 16);
-            for (env = first_cpu; env != NULL; env = env->next_cpu)
-                if (env->cpu_index + 1 == thread) {
-                    cpu_synchronize_state(env, 0);
-                    len = snprintf((char *)mem_buf, sizeof(mem_buf),
-                                   "CPU#%d [%s]", env->cpu_index,
-                                   env->halted ? "halted " : "running");
-                    memtohex(buf, mem_buf, len);
-                    put_packet(s, buf);
-                    break;
-                }
+            env = find_cpu(thread);
+            if (env != NULL) {
+                cpu_synchronize_state(env);
+                len = snprintf((char *)mem_buf, sizeof(mem_buf),
+                               "CPU#%d [%s]", env->cpu_index,
+                               env->halted ? "halted " : "running");
+                memtohex(buf, mem_buf, len);
+                put_packet(s, buf);
+            }
             break;
         }
 #ifdef CONFIG_USER_ONLY
@@ -1943,14 +2275,11 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
     const char *type;
     int ret;
 
-    if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
-        s->state == RS_INACTIVE || s->state == RS_SYSCALL)
+    if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
         return;
-
-    /* disable single step if it was enable */
-    cpu_single_step(env, 0);
-
-    if (reason == EXCP_DEBUG) {
+    }
+    switch (reason) {
+    case VMSTOP_DEBUG:
         if (env->watchpoint_hit) {
             switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
@@ -1965,19 +2294,46 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
             }
             snprintf(buf, sizeof(buf),
                      "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
-                     GDB_SIGNAL_TRAP, env->cpu_index+1, type,
+                     GDB_SIGNAL_TRAP, gdb_id(env), type,
                      env->watchpoint_hit->vaddr);
-            put_packet(s, buf);
             env->watchpoint_hit = NULL;
-            return;
+            goto send_packet;
         }
-       tb_flush(env);
+        tb_flush(env);
         ret = GDB_SIGNAL_TRAP;
-    } else {
+        break;
+    case VMSTOP_USER:
         ret = GDB_SIGNAL_INT;
+        break;
+    case VMSTOP_SHUTDOWN:
+        ret = GDB_SIGNAL_QUIT;
+        break;
+    case VMSTOP_DISKFULL:
+        ret = GDB_SIGNAL_IO;
+        break;
+    case VMSTOP_WATCHDOG:
+        ret = GDB_SIGNAL_ALRM;
+        break;
+    case VMSTOP_PANIC:
+        ret = GDB_SIGNAL_ABRT;
+        break;
+    case VMSTOP_SAVEVM:
+    case VMSTOP_LOADVM:
+        return;
+    case VMSTOP_MIGRATE:
+        ret = GDB_SIGNAL_XCPU;
+        break;
+    default:
+        ret = GDB_SIGNAL_UNKNOWN;
+        break;
     }
-    snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, env->cpu_index+1);
+    snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env));
+
+send_packet:
     put_packet(s, buf);
+
+    /* disable single step if it was enabled */
+    cpu_single_step(env, 0);
 }
 #endif
 
@@ -2001,7 +2357,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
     gdb_current_syscall_cb = cb;
     s->state = RS_SYSCALL;
 #ifndef CONFIG_USER_ONLY
-    vm_stop(EXCP_DEBUG);
+    vm_stop(VMSTOP_DEBUG);
 #endif
     s->state = RS_IDLE;
     va_start(va, fmt);
@@ -2075,7 +2431,7 @@ static void gdb_read_byte(GDBState *s, int ch)
     if (vm_running) {
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
-        vm_stop(EXCP_INTERRUPT);
+        vm_stop(VMSTOP_USER);
     } else
 #endif
     {
@@ -2122,6 +2478,32 @@ static void gdb_read_byte(GDBState *s, int ch)
     }
 }
 
+/* Tell the remote gdb that the process has exited.  */
+void gdb_exit(CPUState *env, int code)
+{
+  GDBState *s;
+  char buf[4];
+
+  s = gdbserver_state;
+  if (!s) {
+      return;
+  }
+#ifdef CONFIG_USER_ONLY
+  if (gdbserver_fd < 0 || s->fd < 0) {
+      return;
+  }
+#endif
+
+  snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+  put_packet(s, buf);
+
+#ifndef CONFIG_USER_ONLY
+  if (s->chr) {
+      qemu_chr_close(s->chr);
+  }
+#endif
+}
+
 #ifdef CONFIG_USER_ONLY
 int
 gdb_queuesig (void)
@@ -2185,20 +2567,6 @@ gdb_handlesig (CPUState *env, int sig)
   return sig;
 }
 
-/* Tell the remote gdb that the process has exited.  */
-void gdb_exit(CPUState *env, int code)
-{
-  GDBState *s;
-  char buf[4];
-
-  s = gdbserver_state;
-  if (gdbserver_fd < 0 || s->fd < 0)
-    return;
-
-  snprintf(buf, sizeof(buf), "W%02x", code);
-  put_packet(s, buf);
-}
-
 /* Tell the remote gdb that the process has exited due to SIG.  */
 void gdb_signalled(CPUState *env, int sig)
 {
@@ -2227,6 +2595,9 @@ static void gdb_accept(void)
             perror("accept");
             return;
         } else if (fd >= 0) {
+#ifndef _WIN32
+            fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
             break;
         }
     }
@@ -2256,6 +2627,9 @@ static int gdbserver_open(int port)
         perror("socket");
         return -1;
     }
+#ifndef _WIN32
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
 
     /* allow fast reuse */
     val = 1;
@@ -2318,8 +2692,8 @@ static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
 static void gdb_chr_event(void *opaque, int event)
 {
     switch (event) {
-    case CHR_EVENT_RESET:
-        vm_stop(EXCP_INTERRUPT);
+    case CHR_EVENT_OPENED:
+        vm_stop(VMSTOP_USER);
         gdb_has_xml = 0;
         break;
     default:
@@ -2359,8 +2733,9 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
 #ifndef _WIN32
 static void gdb_sigterm_handler(int signal)
 {
-    if (vm_running)
-        vm_stop(EXCP_INTERRUPT);
+    if (vm_running) {
+        vm_stop(VMSTOP_USER);
+    }
 }
 #endif