summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--exec.c5
-rw-r--r--gdbstub.c1382
-rw-r--r--include/exec/gdbstub.h45
-rw-r--r--include/qom/cpu.h13
-rw-r--r--include/sysemu/kvm.h2
-rw-r--r--kvm-all.c17
-rw-r--r--kvm-stub.c2
-rw-r--r--linux-user/main.c2
-rw-r--r--qom/cpu.c22
-rw-r--r--stubs/Makefile.objs1
-rw-r--r--stubs/gdbstub.c5
-rw-r--r--target-alpha/Makefile.objs1
-rw-r--r--target-alpha/cpu-qom.h2
-rw-r--r--target-alpha/cpu.c3
-rw-r--r--target-alpha/gdbstub.c93
-rw-r--r--target-arm/Makefile.objs1
-rw-r--r--target-arm/cpu-qom.h3
-rw-r--r--target-arm/cpu.c4
-rw-r--r--target-arm/gdbstub.c102
-rw-r--r--target-cris/Makefile.objs1
-rw-r--r--target-cris/cpu-qom.h4
-rw-r--r--target-cris/cpu.c8
-rw-r--r--target-cris/gdbstub.c130
-rw-r--r--target-i386/Makefile.objs1
-rw-r--r--target-i386/cpu-qom.h3
-rw-r--r--target-i386/cpu.c3
-rw-r--r--target-i386/gdbstub.c231
-rw-r--r--target-i386/kvm.c2
-rw-r--r--target-lm32/Makefile.objs1
-rw-r--r--target-lm32/cpu-qom.h2
-rw-r--r--target-lm32/cpu.c3
-rw-r--r--target-lm32/gdbstub.c92
-rw-r--r--target-m68k/Makefile.objs1
-rw-r--r--target-m68k/cpu-qom.h2
-rw-r--r--target-m68k/cpu.c4
-rw-r--r--target-m68k/gdbstub.c75
-rw-r--r--target-microblaze/Makefile.objs1
-rw-r--r--target-microblaze/cpu-qom.h2
-rw-r--r--target-microblaze/cpu.c3
-rw-r--r--target-microblaze/gdbstub.c56
-rw-r--r--target-mips/Makefile.objs1
-rw-r--r--target-mips/cpu-qom.h2
-rw-r--r--target-mips/cpu.c4
-rw-r--r--target-mips/gdbstub.c155
-rw-r--r--target-openrisc/Makefile.objs1
-rw-r--r--target-openrisc/cpu.c3
-rw-r--r--target-openrisc/cpu.h2
-rw-r--r--target-openrisc/gdbstub.c83
-rw-r--r--target-ppc/Makefile.objs1
-rw-r--r--target-ppc/cpu-qom.h2
-rw-r--r--target-ppc/gdbstub.c131
-rw-r--r--target-ppc/translate_init.c9
-rw-r--r--target-s390x/Makefile.objs1
-rw-r--r--target-s390x/cpu-qom.h2
-rw-r--r--target-s390x/cpu.c3
-rw-r--r--target-s390x/gdbstub.c88
-rw-r--r--target-s390x/kvm.c12
-rw-r--r--target-sh4/Makefile.objs1
-rw-r--r--target-sh4/cpu-qom.h2
-rw-r--r--target-sh4/cpu.c3
-rw-r--r--target-sh4/gdbstub.c146
-rw-r--r--target-sparc/Makefile.objs1
-rw-r--r--target-sparc/cpu-qom.h2
-rw-r--r--target-sparc/cpu.c8
-rw-r--r--target-sparc/gdbstub.c208
-rw-r--r--target-xtensa/Makefile.objs1
-rw-r--r--target-xtensa/cpu-qom.h5
-rw-r--r--target-xtensa/cpu.c29
-rw-r--r--target-xtensa/gdbstub.c109
-rw-r--r--target-xtensa/helper.c40
70 files changed, 1993 insertions, 1392 deletions
diff --git a/exec.c b/exec.c
index 3ba9525bd3..c4f2894ea1 100644
--- a/exec.c
+++ b/exec.c
@@ -590,15 +590,14 @@ void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
 void cpu_single_step(CPUState *cpu, int enabled)
 {
 #if defined(TARGET_HAS_ICE)
-    CPUArchState *env = cpu->env_ptr;
-
     if (cpu->singlestep_enabled != enabled) {
         cpu->singlestep_enabled = enabled;
         if (kvm_enabled()) {
-            kvm_update_guest_debug(env, 0);
+            kvm_update_guest_debug(cpu, 0);
         } else {
             /* must flush all the translated code to avoid inconsistencies */
             /* XXX: only flush what is necessary */
+            CPUArchState *env = cpu->env_ptr;
             tb_flush(env);
         }
     }
diff --git a/gdbstub.c b/gdbstub.c
index 35ca7c2c1e..1af25a6fe6 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -40,7 +40,6 @@
 #include "cpu.h"
 #include "qemu/sockets.h"
 #include "sysemu/kvm.h"
-#include "qemu/bitops.h"
 
 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
                                          uint8_t *buf, int len, bool is_write)
@@ -316,10 +315,7 @@ static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
 
 static GDBState *gdbserver_state;
 
-/* This is an ugly hack to cope with both new and old gdb.
-   If gdb sends qXfer:features:read then assume we're talking to a newish
-   gdb that understands target descriptions.  */
-static int gdb_has_xml;
+bool gdb_has_xml;
 
 #ifdef CONFIG_USER_ONLY
 /* XXX: This is not thread safe.  Do we care?  */
@@ -489,1319 +485,6 @@ static int put_packet(GDBState *s, const char *buf)
     return put_packet_binary(s, buf, strlen(buf));
 }
 
-/* The GDB remote protocol transfers values in target byte order.  This means
-   we can use the raw memory access routines to access the value buffer.
-   Conveniently, these also handle the case where the buffer is mis-aligned.
- */
-#define GET_REG8(val) do { \
-    stb_p(mem_buf, val); \
-    return 1; \
-    } while(0)
-#define GET_REG16(val) do { \
-    stw_p(mem_buf, val); \
-    return 2; \
-    } while(0)
-#define GET_REG32(val) do { \
-    stl_p(mem_buf, val); \
-    return 4; \
-    } while(0)
-#define GET_REG64(val) do { \
-    stq_p(mem_buf, val); \
-    return 8; \
-    } while(0)
-
-#if TARGET_LONG_BITS == 64
-#define GET_REGL(val) GET_REG64(val)
-#define ldtul_p(addr) ldq_p(addr)
-#else
-#define GET_REGL(val) GET_REG32(val)
-#define ldtul_p(addr) ldl_p(addr)
-#endif
-
-#if defined(TARGET_I386)
-
-#ifdef TARGET_X86_64
-static const int gpr_map[16] = {
-    R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
-    8, 9, 10, 11, 12, 13, 14, 15
-};
-#else
-#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(CPUX86State *env, uint8_t *mem_buf, int n)
-{
-    if (n < CPU_NB_REGS) {
-        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
-        /* 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 >= 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 {
-        switch (n) {
-        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_x86_gdb_load_seg(CPUX86State *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(CPUX86State *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    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
-        /* FIXME: byteswap float values - after fixing fpregs layout. */
-        memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
-#endif
-        return 10;
-    } 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 {
-        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.  */
-    return 0;
-}
-
-#elif defined (TARGET_PPC)
-
-/* Old gdb always expects FP registers.  Newer (xml-aware) gdb only
-   expects whatever the target description contains.  Due to a
-   historical mishap the FP registers appear in between core integer
-   regs and PC, MSR, CR, and so forth.  We hack round this by giving the
-   FP regs zero size when talking to a newer gdb.  */
-#define NUM_CORE_REGS 71
-#if defined (TARGET_PPC64)
-#define GDB_CORE_XML "power64-core.xml"
-#else
-#define GDB_CORE_XML "power-core.xml"
-#endif
-
-static int cpu_gdb_read_register(CPUPPCState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 32) {
-        /* gprs */
-        GET_REGL(env->gpr[n]);
-    } else if (n < 64) {
-        /* fprs */
-        if (gdb_has_xml)
-            return 0;
-        stfq_p(mem_buf, env->fpr[n-32]);
-        return 8;
-    } else {
-        switch (n) {
-        case 64: GET_REGL(env->nip);
-        case 65: GET_REGL(env->msr);
-        case 66:
-            {
-                uint32_t cr = 0;
-                int i;
-                for (i = 0; i < 8; i++)
-                    cr |= env->crf[i] << (32 - ((i + 1) * 4));
-                GET_REG32(cr);
-            }
-        case 67: GET_REGL(env->lr);
-        case 68: GET_REGL(env->ctr);
-        case 69: GET_REGL(env->xer);
-        case 70:
-            {
-                if (gdb_has_xml)
-                    return 0;
-                GET_REG32(env->fpscr);
-            }
-        }
-    }
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUPPCState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 32) {
-        /* gprs */
-        env->gpr[n] = ldtul_p(mem_buf);
-        return sizeof(target_ulong);
-    } else if (n < 64) {
-        /* fprs */
-        if (gdb_has_xml)
-            return 0;
-        env->fpr[n-32] = ldfq_p(mem_buf);
-        return 8;
-    } else {
-        switch (n) {
-        case 64:
-            env->nip = ldtul_p(mem_buf);
-            return sizeof(target_ulong);
-        case 65:
-            ppc_store_msr(env, ldtul_p(mem_buf));
-            return sizeof(target_ulong);
-        case 66:
-            {
-                uint32_t cr = ldl_p(mem_buf);
-                int i;
-                for (i = 0; i < 8; i++)
-                    env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
-                return 4;
-            }
-        case 67:
-            env->lr = ldtul_p(mem_buf);
-            return sizeof(target_ulong);
-        case 68:
-            env->ctr = ldtul_p(mem_buf);
-            return sizeof(target_ulong);
-        case 69:
-            env->xer = ldtul_p(mem_buf);
-            return sizeof(target_ulong);
-        case 70:
-            /* fpscr */
-            if (gdb_has_xml)
-                return 0;
-            store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
-            return sizeof(target_ulong);
-        }
-    }
-    return 0;
-}
-
-#elif defined (TARGET_SPARC)
-
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-#define NUM_CORE_REGS 86
-#else
-#define NUM_CORE_REGS 72
-#endif
-
-#ifdef TARGET_ABI32
-#define GET_REGA(val) GET_REG32(val)
-#else
-#define GET_REGA(val) GET_REGL(val)
-#endif
-
-static int cpu_gdb_read_register(CPUSPARCState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 8) {
-        /* g0..g7 */
-        GET_REGA(env->gregs[n]);
-    }
-    if (n < 32) {
-        /* register window */
-        GET_REGA(env->regwptr[n - 8]);
-    }
-#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
-    if (n < 64) {
-        /* fprs */
-        if (n & 1) {
-            GET_REG32(env->fpr[(n - 32) / 2].l.lower);
-        } else {
-            GET_REG32(env->fpr[(n - 32) / 2].l.upper);
-        }
-    }
-    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
-    switch (n) {
-    case 64: GET_REGA(env->y);
-    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);
-    case 69: GET_REGA(env->npc);
-    case 70: GET_REGA(env->fsr);
-    case 71: GET_REGA(0); /* csr */
-    default: GET_REGA(0);
-    }
-#else
-    if (n < 64) {
-        /* f0-f31 */
-        if (n & 1) {
-            GET_REG32(env->fpr[(n - 32) / 2].l.lower);
-        } else {
-            GET_REG32(env->fpr[(n - 32) / 2].l.upper);
-        }
-    }
-    if (n < 80) {
-        /* f32-f62 (double width, even numbers only) */
-        GET_REG64(env->fpr[(n - 32) / 2].ll);
-    }
-    switch (n) {
-    case 80: GET_REGL(env->pc);
-    case 81: GET_REGL(env->npc);
-    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);
-    }
-#endif
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUSPARCState *env, uint8_t *mem_buf, int n)
-{
-#if defined(TARGET_ABI32)
-    abi_ulong tmp;
-
-    tmp = ldl_p(mem_buf);
-#else
-    target_ulong tmp;
-
-    tmp = ldtul_p(mem_buf);
-#endif
-
-    if (n < 8) {
-        /* g0..g7 */
-        env->gregs[n] = tmp;
-    } else if (n < 32) {
-        /* register window */
-        env->regwptr[n - 8] = tmp;
-    }
-#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
-    else if (n < 64) {
-        /* fprs */
-        /* f0-f31 */
-        if (n & 1) {
-            env->fpr[(n - 32) / 2].l.lower = tmp;
-        } else {
-            env->fpr[(n - 32) / 2].l.upper = tmp;
-        }
-    } else {
-        /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
-        switch (n) {
-        case 64: env->y = 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;
-        case 69: env->npc = tmp; break;
-        case 70: env->fsr = tmp; break;
-        default: return 0;
-        }
-    }
-    return 4;
-#else
-    else if (n < 64) {
-        /* f0-f31 */
-        tmp = ldl_p(mem_buf);
-        if (n & 1) {
-            env->fpr[(n - 32) / 2].l.lower = tmp;
-        } else {
-            env->fpr[(n - 32) / 2].l.upper = tmp;
-        }
-        return 4;
-    } else if (n < 80) {
-        /* f32-f62 (double width, even numbers only) */
-        env->fpr[(n - 32) / 2].ll = tmp;
-    } else {
-        switch (n) {
-        case 80: env->pc = tmp; break;
-        case 81: env->npc = tmp; break;
-        case 82:
-            cpu_put_ccr(env, tmp >> 32);
-	    env->asi = (tmp >> 24) & 0xff;
-	    env->pstate = (tmp >> 8) & 0xfff;
-            cpu_put_cwp64(env, tmp & 0xff);
-	    break;
-        case 83: env->fsr = tmp; break;
-        case 84: env->fprs = tmp; break;
-        case 85: env->y = tmp; break;
-        default: return 0;
-        }
-    }
-    return 8;
-#endif
-}
-#elif defined (TARGET_ARM)
-
-/* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
-   whatever the target description contains.  Due to a historical mishap
-   the FPA registers appear in between core integer regs and the CPSR.
-   We hack round this by giving the FPA regs zero size when talking to a
-   newer gdb.  */
-#define NUM_CORE_REGS 26
-#define GDB_CORE_XML "arm-core.xml"
-
-static int cpu_gdb_read_register(CPUARMState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 16) {
-        /* Core integer register.  */
-        GET_REG32(env->regs[n]);
-    }
-    if (n < 24) {
-        /* FPA registers.  */
-        if (gdb_has_xml)
-            return 0;
-        memset(mem_buf, 0, 12);
-        return 12;
-    }
-    switch (n) {
-    case 24:
-        /* FPA status register.  */
-        if (gdb_has_xml)
-            return 0;
-        GET_REG32(0);
-    case 25:
-        /* CPSR */
-        GET_REG32(cpsr_read(env));
-    }
-    /* Unknown register.  */
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUARMState *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    tmp = ldl_p(mem_buf);
-
-    /* Mask out low bit of PC to workaround gdb bugs.  This will probably
-       cause problems if we ever implement the Jazelle DBX extensions.  */
-    if (n == 15)
-        tmp &= ~1;
-
-    if (n < 16) {
-        /* Core integer register.  */
-        env->regs[n] = tmp;
-        return 4;
-    }
-    if (n < 24) { /* 16-23 */
-        /* FPA registers (ignored).  */
-        if (gdb_has_xml)
-            return 0;
-        return 12;
-    }
-    switch (n) {
-    case 24:
-        /* FPA status register (ignored).  */
-        if (gdb_has_xml)
-            return 0;
-        return 4;
-    case 25:
-        /* CPSR */
-        cpsr_write (env, tmp, 0xffffffff);
-        return 4;
-    }
-    /* Unknown register.  */
-    return 0;
-}
-
-#elif defined (TARGET_M68K)
-
-#define NUM_CORE_REGS 18
-
-#define GDB_CORE_XML "cf-core.xml"
-
-static int cpu_gdb_read_register(CPUM68KState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 8) {
-        /* D0-D7 */
-        GET_REG32(env->dregs[n]);
-    } else if (n < 16) {
-        /* A0-A7 */
-        GET_REG32(env->aregs[n - 8]);
-    } else {
-	switch (n) {
-        case 16: GET_REG32(env->sr);
-        case 17: GET_REG32(env->pc);
-        }
-    }
-    /* FP registers not included here because they vary between
-       ColdFire and m68k.  Use XML bits for these.  */
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUM68KState *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    tmp = ldl_p(mem_buf);
-
-    if (n < 8) {
-        /* D0-D7 */
-        env->dregs[n] = tmp;
-    } else if (n < 16) {
-        /* A0-A7 */
-        env->aregs[n - 8] = tmp;
-    } else {
-        switch (n) {
-        case 16: env->sr = tmp; break;
-        case 17: env->pc = tmp; break;
-        default: return 0;
-        }
-    }
-    return 4;
-}
-#elif defined (TARGET_MIPS)
-
-#define NUM_CORE_REGS 73
-
-static int cpu_gdb_read_register(CPUMIPSState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 32) {
-        GET_REGL(env->active_tc.gpr[n]);
-    }
-    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
-        if (n >= 38 && n < 70) {
-            if (env->CP0_Status & (1 << CP0St_FR))
-		GET_REGL(env->active_fpu.fpr[n - 38].d);
-            else
-		GET_REGL(env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
-        }
-        switch (n) {
-        case 70: GET_REGL((int32_t)env->active_fpu.fcr31);
-        case 71: GET_REGL((int32_t)env->active_fpu.fcr0);
-        }
-    }
-    switch (n) {
-    case 32: GET_REGL((int32_t)env->CP0_Status);
-    case 33: GET_REGL(env->active_tc.LO[0]);
-    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 | !!(env->hflags & MIPS_HFLAG_M16));
-    case 72: GET_REGL(0); /* fp */
-    case 89: GET_REGL((int32_t)env->CP0_PRid);
-    }
-    if (n >= 73 && n <= 88) {
-	/* 16 embedded regs.  */
-	GET_REGL(0);
-    }
-
-    return 0;
-}
-
-/* convert MIPS rounding mode in FCR31 to IEEE library */
-static unsigned int ieee_rm[] =
-  {
-    float_round_nearest_even,
-    float_round_to_zero,
-    float_round_up,
-    float_round_down
-  };
-#define RESTORE_ROUNDING_MODE \
-    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
-
-static int cpu_gdb_write_register(CPUMIPSState *env, uint8_t *mem_buf, int n)
-{
-    target_ulong tmp;
-
-    tmp = ldtul_p(mem_buf);
-
-    if (n < 32) {
-        env->active_tc.gpr[n] = tmp;
-        return sizeof(target_ulong);
-    }
-    if (env->CP0_Config1 & (1 << CP0C1_FP)
-            && n >= 38 && n < 73) {
-        if (n < 70) {
-            if (env->CP0_Status & (1 << CP0St_FR))
-              env->active_fpu.fpr[n - 38].d = tmp;
-            else
-              env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
-        }
-        switch (n) {
-        case 70:
-            env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
-            /* set rounding mode */
-            RESTORE_ROUNDING_MODE;
-            break;
-        case 71: env->active_fpu.fcr0 = tmp; break;
-        }
-        return sizeof(target_ulong);
-    }
-    switch (n) {
-    case 32: env->CP0_Status = tmp; break;
-    case 33: env->active_tc.LO[0] = tmp; break;
-    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 & ~(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)
-	    return 0;
-	/* Other registers are readonly.  Ignore writes.  */
-	break;
-    }
-
-    return sizeof(target_ulong);
-}
-#elif defined(TARGET_OPENRISC)
-
-#define NUM_CORE_REGS (32 + 3)
-
-static int cpu_gdb_read_register(CPUOpenRISCState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 32) {
-        GET_REG32(env->gpr[n]);
-    } else {
-        switch (n) {
-        case 32:    /* PPC */
-            GET_REG32(env->ppc);
-            break;
-
-        case 33:    /* NPC */
-            GET_REG32(env->npc);
-            break;
-
-        case 34:    /* SR */
-            GET_REG32(env->sr);
-            break;
-
-        default:
-            break;
-        }
-    }
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUOpenRISCState *env,
-                                  uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    if (n > NUM_CORE_REGS) {
-        return 0;
-    }
-
-    tmp = ldl_p(mem_buf);
-
-    if (n < 32) {
-        env->gpr[n] = tmp;
-    } else {
-        switch (n) {
-        case 32: /* PPC */
-            env->ppc = tmp;
-            break;
-
-        case 33: /* NPC */
-            env->npc = tmp;
-            break;
-
-        case 34: /* SR */
-            env->sr = tmp;
-            break;
-
-        default:
-            break;
-        }
-    }
-    return 4;
-}
-#elif defined (TARGET_SH4)
-
-/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
-/* FIXME: We should use XML for this.  */
-
-#define NUM_CORE_REGS 59
-
-static int cpu_gdb_read_register(CPUSH4State *env, uint8_t *mem_buf, int n)
-{
-    switch (n) {
-    case 0 ... 7:
-        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
-            GET_REGL(env->gregs[n + 16]);
-        } else {
-            GET_REGL(env->gregs[n]);
-        }
-    case 8 ... 15:
-        GET_REGL(env->gregs[n]);
-    case 16:
-        GET_REGL(env->pc);
-    case 17:
-        GET_REGL(env->pr);
-    case 18:
-        GET_REGL(env->gbr);
-    case 19:
-        GET_REGL(env->vbr);
-    case 20:
-        GET_REGL(env->mach);
-    case 21:
-        GET_REGL(env->macl);
-    case 22:
-        GET_REGL(env->sr);
-    case 23:
-        GET_REGL(env->fpul);
-    case 24:
-        GET_REGL(env->fpscr);
-    case 25 ... 40:
-        if (env->fpscr & FPSCR_FR) {
-            stfl_p(mem_buf, env->fregs[n - 9]);
-        } else {
-            stfl_p(mem_buf, env->fregs[n - 25]);
-        }
-        return 4;
-    case 41:
-        GET_REGL(env->ssr);
-    case 42:
-        GET_REGL(env->spc);
-    case 43 ... 50:
-        GET_REGL(env->gregs[n - 43]);
-    case 51 ... 58:
-        GET_REGL(env->gregs[n - (51 - 16)]);
-    }
-
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUSH4State *env, uint8_t *mem_buf, int n)
-{
-    switch (n) {
-    case 0 ... 7:
-        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
-            env->gregs[n + 16] = ldl_p(mem_buf);
-        } else {
-            env->gregs[n] = ldl_p(mem_buf);
-        }
-        break;
-    case 8 ... 15:
-        env->gregs[n] = ldl_p(mem_buf);
-        break;
-    case 16:
-        env->pc = ldl_p(mem_buf);
-        break;
-    case 17:
-        env->pr = ldl_p(mem_buf);
-        break;
-    case 18:
-        env->gbr = ldl_p(mem_buf);
-        break;
-    case 19:
-        env->vbr = ldl_p(mem_buf);
-        break;
-    case 20:
-        env->mach = ldl_p(mem_buf);
-        break;
-    case 21:
-        env->macl = ldl_p(mem_buf);
-        break;
-    case 22:
-        env->sr = ldl_p(mem_buf);
-        break;
-    case 23:
-        env->fpul = ldl_p(mem_buf);
-        break;
-    case 24:
-        env->fpscr = ldl_p(mem_buf);
-        break;
-    case 25 ... 40:
-        if (env->fpscr & FPSCR_FR) {
-            env->fregs[n - 9] = ldfl_p(mem_buf);
-        } else {
-            env->fregs[n - 25] = ldfl_p(mem_buf);
-        }
-        break;
-    case 41:
-        env->ssr = ldl_p(mem_buf);
-        break;
-    case 42:
-        env->spc = ldl_p(mem_buf);
-        break;
-    case 43 ... 50:
-        env->gregs[n - 43] = ldl_p(mem_buf);
-        break;
-    case 51 ... 58:
-        env->gregs[n - (51 - 16)] = ldl_p(mem_buf);
-        break;
-    default: return 0;
-    }
-
-    return 4;
-}
-#elif defined (TARGET_MICROBLAZE)
-
-#define NUM_CORE_REGS (32 + 5)
-
-static int cpu_gdb_read_register(CPUMBState *env, uint8_t *mem_buf, int n)
-{
-    if (n < 32) {
-	GET_REG32(env->regs[n]);
-    } else {
-	GET_REG32(env->sregs[n - 32]);
-    }
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUMBState *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    if (n > NUM_CORE_REGS)
-	return 0;
-
-    tmp = ldl_p(mem_buf);
-
-    if (n < 32) {
-	env->regs[n] = tmp;
-    } else {
-	env->sregs[n - 32] = tmp;
-    }
-    return 4;
-}
-#elif defined (TARGET_CRIS)
-
-#define NUM_CORE_REGS 49
-
-static int
-read_register_crisv10(CPUCRISState *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(CPUCRISState *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]);
-    }
-
-    if (n >= 21 && n < 32) {
-	GET_REG32(env->pregs[n - 16]);
-    }
-    if (n >= 33 && n < 49) {
-	GET_REG32(env->sregs[srs][n - 33]);
-    }
-    switch (n) {
-    case 16: GET_REG8(env->pregs[0]);
-    case 17: GET_REG8(env->pregs[1]);
-    case 18: GET_REG32(env->pregs[2]);
-    case 19: GET_REG8(srs);
-    case 20: GET_REG16(env->pregs[4]);
-    case 32: GET_REG32(env->pc);
-    }
-
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUCRISState *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    if (n > 49)
-	return 0;
-
-    tmp = ldl_p(mem_buf);
-
-    if (n < 16) {
-	env->regs[n] = tmp;
-    }
-
-    if (n >= 21 && n < 32) {
-	env->pregs[n - 16] = tmp;
-    }
-
-    /* FIXME: Should support function regs be writable?  */
-    switch (n) {
-    case 16: return 1;
-    case 17: return 1;
-    case 18: env->pregs[PR_PID] = tmp; break;
-    case 19: return 1;
-    case 20: return 2;
-    case 32: env->pc = tmp; break;
-    }
-
-    return 4;
-}
-#elif defined (TARGET_ALPHA)
-
-#define NUM_CORE_REGS 67
-
-static int cpu_gdb_read_register(CPUAlphaState *env, uint8_t *mem_buf, int n)
-{
-    uint64_t val;
-    CPU_DoubleU d;
-
-    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;
-    }
-    GET_REGL(val);
-}
-
-static int cpu_gdb_write_register(CPUAlphaState *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;
-    }
-    return 8;
-}
-#elif defined (TARGET_S390X)
-
-#define NUM_CORE_REGS  S390_NUM_REGS
-
-static int cpu_gdb_read_register(CPUS390XState *env, uint8_t *mem_buf, int n)
-{
-    uint64_t val;
-    int cc_op;
-
-    switch (n) {
-    case S390_PSWM_REGNUM:
-        cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
-        val = deposit64(env->psw.mask, 44, 2, cc_op);
-        GET_REGL(val);
-        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:
-        GET_REG64(env->fregs[n-S390_F0_REGNUM].ll);
-        break;
-    }
-
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n)
-{
-    target_ulong tmpl;
-    uint32_t tmp32;
-    int r = 8;
-    tmpl = ldtul_p(mem_buf);
-    tmp32 = ldl_p(mem_buf);
-
-    switch (n) {
-    case S390_PSWM_REGNUM:
-        env->psw.mask = tmpl;
-        env->cc_op = extract64(tmpl, 44, 2);
-        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:
-        env->fregs[n-S390_F0_REGNUM].ll = tmpl;
-        break;
-    default:
-        return 0;
-    }
-    return r;
-}
-#elif defined (TARGET_LM32)
-
-#include "hw/lm32/lm32_pic.h"
-#define NUM_CORE_REGS (32 + 7)
-
-static int cpu_gdb_read_register(CPULM32State *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;
-}
-
-static int cpu_gdb_write_register(CPULM32State *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-
-    if (n > NUM_CORE_REGS) {
-        return 0;
-    }
-
-    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;
-}
-#elif defined(TARGET_XTENSA)
-
-/* Use num_core_regs to see only non-privileged registers in an unmodified gdb.
- * Use num_regs to see all registers. gdb modification is required for that:
- * reset bit 0 in the 'flags' field of the registers definitions in the
- * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
- */
-#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
-#define num_g_regs NUM_CORE_REGS
-
-static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
-{
-    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
-
-    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
-        return 0;
-    }
-
-    switch (reg->type) {
-    case 9: /*pc*/
-        GET_REG32(env->pc);
-        break;
-
-    case 1: /*ar*/
-        xtensa_sync_phys_from_window(env);
-        GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
-        break;
-
-    case 2: /*SR*/
-        GET_REG32(env->sregs[reg->targno & 0xff]);
-        break;
-
-    case 3: /*UR*/
-        GET_REG32(env->uregs[reg->targno & 0xff]);
-        break;
-
-    case 4: /*f*/
-        GET_REG32(float32_val(env->fregs[reg->targno & 0x0f]));
-        break;
-
-    case 8: /*a*/
-        GET_REG32(env->regs[reg->targno & 0x0f]);
-        break;
-
-    default:
-        qemu_log("%s from reg %d of unsupported type %d\n",
-                __func__, n, reg->type);
-        return 0;
-    }
-}
-
-static int cpu_gdb_write_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
-{
-    uint32_t tmp;
-    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
-
-    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
-        return 0;
-    }
-
-    tmp = ldl_p(mem_buf);
-
-    switch (reg->type) {
-    case 9: /*pc*/
-        env->pc = tmp;
-        break;
-
-    case 1: /*ar*/
-        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
-        xtensa_sync_window_from_phys(env);
-        break;
-
-    case 2: /*SR*/
-        env->sregs[reg->targno & 0xff] = tmp;
-        break;
-
-    case 3: /*UR*/
-        env->uregs[reg->targno & 0xff] = tmp;
-        break;
-
-    case 4: /*f*/
-        env->fregs[reg->targno & 0x0f] = make_float32(tmp);
-        break;
-
-    case 8: /*a*/
-        env->regs[reg->targno & 0x0f] = tmp;
-        break;
-
-    default:
-        qemu_log("%s to reg %d of unsupported type %d\n",
-                __func__, n, reg->type);
-        return 0;
-    }
-
-    return 4;
-}
-#else
-
-#define NUM_CORE_REGS 0
-
-static int cpu_gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int n)
-{
-    return 0;
-}
-
-static int cpu_gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int n)
-{
-    return 0;
-}
-
-#endif
-
-#if !defined(TARGET_XTENSA)
-static int num_g_regs = NUM_CORE_REGS;
-#endif
-
-#ifdef GDB_CORE_XML
 /* Encode data using the encoding for 'x' packets.  */
 static int memtox(char *buf, const char *mem, int len)
 {
@@ -1823,7 +506,8 @@ static int memtox(char *buf, const char *mem, int len)
     return p - buf;
 }
 
-static const char *get_feature_xml(const char *p, const char **newp)
+static const char *get_feature_xml(const char *p, const char **newp,
+                                   CPUClass *cc)
 {
     size_t len;
     int i;
@@ -1847,7 +531,7 @@ static const char *get_feature_xml(const char *p, const char **newp)
                      "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
                      "<target>"
                      "<xi:include href=\"%s\"/>",
-                     GDB_CORE_XML);
+                     cc->gdb_core_xml_file);
 
             for (r = cpu->gdb_regs; r; r = r->next) {
                 pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
@@ -1865,15 +549,16 @@ static const char *get_feature_xml(const char *p, const char **newp)
     }
     return name ? xml_builtin[i][1] : NULL;
 }
-#endif
 
 static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
 {
+    CPUClass *cc = CPU_GET_CLASS(cpu);
     CPUArchState *env = cpu->env_ptr;
     GDBRegisterState *r;
 
-    if (reg < NUM_CORE_REGS)
-        return cpu_gdb_read_register(env, mem_buf, reg);
+    if (reg < cc->gdb_num_core_regs) {
+        return cc->gdb_read_register(cpu, mem_buf, reg);
+    }
 
     for (r = cpu->gdb_regs; r; r = r->next) {
         if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
@@ -1885,11 +570,13 @@ static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
 
 static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
 {
+    CPUClass *cc = CPU_GET_CLASS(cpu);
     CPUArchState *env = cpu->env_ptr;
     GDBRegisterState *r;
 
-    if (reg < NUM_CORE_REGS)
-        return cpu_gdb_write_register(env, mem_buf, reg);
+    if (reg < cc->gdb_num_core_regs) {
+        return cc->gdb_write_register(cpu, mem_buf, reg);
+    }
 
     for (r = cpu->gdb_regs; r; r = r->next) {
         if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
@@ -1899,7 +586,6 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
     return 0;
 }
 
-#if !defined(TARGET_XTENSA)
 /* Register a supplemental set of CPU registers.  If g_pos is nonzero it
    specifies the first register number and these registers are included in
    a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
@@ -1912,7 +598,6 @@ void gdb_register_coprocessor(CPUState *cpu,
 {
     GDBRegisterState *s;
     GDBRegisterState **p;
-    static int last_reg = NUM_CORE_REGS;
 
     p = &cpu->gdb_regs;
     while (*p) {
@@ -1923,25 +608,22 @@ void gdb_register_coprocessor(CPUState *cpu,
     }
 
     s = g_new0(GDBRegisterState, 1);
-    s->base_reg = last_reg;
+    s->base_reg = cpu->gdb_num_regs;
     s->num_regs = num_regs;
     s->get_reg = get_reg;
     s->set_reg = set_reg;
     s->xml = xml;
 
     /* Add to end of list.  */
-    last_reg += num_regs;
+    cpu->gdb_num_regs += num_regs;
     *p = s;
     if (g_pos) {
         if (g_pos != s->base_reg) {
             fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n"
                     "Expected %d got %d\n", xml, g_pos, s->base_reg);
-        } else {
-            num_g_regs = last_reg;
         }
     }
 }
-#endif
 
 #ifndef CONFIG_USER_ONLY
 static const int xlat_gdb_type[] = {
@@ -2071,10 +753,8 @@ static CPUState *find_cpu(uint32_t thread_id)
 
 static int gdb_handle_packet(GDBState *s, const char *line_buf)
 {
-#ifdef TARGET_XTENSA
-    CPUArchState *env;
-#endif
     CPUState *cpu;
+    CPUClass *cc;
     const char *p;
     uint32_t thread;
     int ch, reg_size, type, res;
@@ -2221,11 +901,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'g':
         cpu_synchronize_state(s->g_cpu);
-#ifdef TARGET_XTENSA
-        env = s->g_cpu->env_ptr;
-#endif
         len = 0;
-        for (addr = 0; addr < num_g_regs; addr++) {
+        for (addr = 0; addr < s->g_cpu->gdb_num_regs; addr++) {
             reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
             len += reg_size;
         }
@@ -2234,13 +911,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'G':
         cpu_synchronize_state(s->g_cpu);
-#ifdef TARGET_XTENSA
-        env = s->g_cpu->env_ptr;
-#endif
         registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
-        for (addr = 0; addr < num_g_regs && len > 0; addr++) {
+        for (addr = 0; addr < s->g_cpu->gdb_num_regs && len > 0; addr++) {
             reg_size = gdb_write_register(s->g_cpu, registers, addr);
             len -= reg_size;
             registers += reg_size;
@@ -2443,20 +1117,25 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 #endif /* !CONFIG_USER_ONLY */
         if (strncmp(p, "Supported", 9) == 0) {
             snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
-#ifdef GDB_CORE_XML
-            pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
-#endif
+            cc = CPU_GET_CLASS(first_cpu);
+            if (cc->gdb_core_xml_file != NULL) {
+                pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
+            }
             put_packet(s, buf);
             break;
         }
-#ifdef GDB_CORE_XML
         if (strncmp(p, "Xfer:features:read:", 19) == 0) {
             const char *xml;
             target_ulong total_len;
 
-            gdb_has_xml = 1;
+            cc = CPU_GET_CLASS(first_cpu);
+            if (cc->gdb_core_xml_file == NULL) {
+                goto unknown_command;
+            }
+
+            gdb_has_xml = true;
             p += 19;
-            xml = get_feature_xml(p, &p);
+            xml = get_feature_xml(p, &p, cc);
             if (!xml) {
                 snprintf(buf, sizeof(buf), "E00");
                 put_packet(s, buf);
@@ -2488,7 +1167,6 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
             put_packet_binary(s, buf, len + 1);
             break;
         }
-#endif
         /* Unrecognised 'q' command.  */
         goto unknown_command;
 
@@ -2863,7 +1541,7 @@ static void gdb_accept(void)
     s->c_cpu = first_cpu;
     s->g_cpu = first_cpu;
     s->fd = fd;
-    gdb_has_xml = 0;
+    gdb_has_xml = false;
 
     gdbserver_state = s;
 
@@ -2949,7 +1627,7 @@ static void gdb_chr_event(void *opaque, int event)
     switch (event) {
     case CHR_EVENT_OPENED:
         vm_stop(RUN_STATE_PAUSED);
-        gdb_has_xml = 0;
+        gdb_has_xml = false;
         break;
     default:
         break;
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 7ea1ad7f9c..a608a26c30 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -39,6 +39,43 @@ static inline int cpu_index(CPUState *cpu)
 #endif
 }
 
+/* The GDB remote protocol transfers values in target byte order.  This means
+ * we can use the raw memory access routines to access the value buffer.
+ * Conveniently, these also handle the case where the buffer is mis-aligned.
+ */
+
+static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
+{
+    stb_p(mem_buf, val);
+    return 1;
+}
+
+static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
+{
+    stw_p(mem_buf, val);
+    return 2;
+}
+
+static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
+{
+    stl_p(mem_buf, val);
+    return 4;
+}
+
+static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
+{
+    stq_p(mem_buf, val);
+    return 8;
+}
+
+#if TARGET_LONG_BITS == 64
+#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
+#define ldtul_p(addr) ldq_p(addr)
+#else
+#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val)
+#define ldtul_p(addr) ldl_p(addr)
+#endif
+
 #endif
 
 #ifdef CONFIG_USER_ONLY
@@ -47,6 +84,14 @@ int gdbserver_start(int);
 int gdbserver_start(const char *port);
 #endif
 
+/**
+ * gdb_has_xml:
+ * This is an ugly hack to cope with both new and old gdb.
+ * If gdb sends qXfer:features:read then assume we're talking to a newish
+ * gdb that understands target descriptions.
+ */
+extern bool gdb_has_xml;
+
 /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
 extern const char *const xml_builtin[][2];
 
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index daf1835c1a..0d6e95c0b6 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -80,7 +80,11 @@ struct TranslationBlock;
  * @synchronize_from_tb: Callback for synchronizing state from a TCG
  * #TranslationBlock.
  * @get_phys_page_debug: Callback for obtaining a physical address.
+ * @gdb_read_register: Callback for letting GDB read a register.
+ * @gdb_write_register: Callback for letting GDB write a register.
  * @vmsd: State description for migration.
+ * @gdb_num_core_regs: Number of core registers accessible to GDB.
+ * @gdb_core_xml_file: File name for core registers GDB XML description.
  *
  * Represents a CPU family or model.
  */
@@ -108,8 +112,9 @@ typedef struct CPUClass {
     void (*set_pc)(CPUState *cpu, vaddr value);
     void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
     hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
+    int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
+    int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
 
-    const struct VMStateDescription *vmsd;
     int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
                             int cpuid, void *opaque);
     int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
@@ -118,6 +123,10 @@ typedef struct CPUClass {
                             int cpuid, void *opaque);
     int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
                                 void *opaque);
+
+    const struct VMStateDescription *vmsd;
+    int gdb_num_core_regs;
+    const char *gdb_core_xml_file;
 } CPUClass;
 
 struct KVMState;
@@ -142,6 +151,7 @@ struct kvm_run;
  * @env_ptr: Pointer to subclass-specific CPUArchState field.
  * @current_tb: Currently executing TB.
  * @gdb_regs: Additional GDB registers.
+ * @gdb_num_regs: Number of total registers accessible to GDB.
  * @next_cpu: Next CPU sharing TB cache.
  * @kvm_fd: vCPU file descriptor for KVM.
  *
@@ -177,6 +187,7 @@ struct CPUState {
     void *env_ptr; /* CPUArchState */
     struct TranslationBlock *current_tb;
     struct GDBRegisterState *gdb_regs;
+    int gdb_num_regs;
     CPUState *next_cpu;
 
     int kvm_fd;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index f8ac448e0b..de74411f41 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -174,7 +174,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
 int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
                           target_ulong len, int type);
 void kvm_remove_all_breakpoints(CPUState *cpu);
-int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap);
+int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap);
 #ifndef _WIN32
 int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset);
 #endif
diff --git a/kvm-all.c b/kvm-all.c
index 4fb4ccbeca..716860f617 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1883,9 +1883,8 @@ static void kvm_invoke_set_guest_debug(void *data)
                                    &dbg_data->dbg);
 }
 
-int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
+int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
 {
-    CPUState *cpu = ENV_GET_CPU(env);
     struct kvm_set_guest_debug_data data;
 
     data.dbg.control = reinject_trap;
@@ -1935,9 +1934,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
     }
 
     for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
-        CPUArchState *env = cpu->env_ptr;
-
-        err = kvm_update_guest_debug(env, 0);
+        err = kvm_update_guest_debug(cpu, 0);
         if (err) {
             return err;
         }
@@ -1977,9 +1974,7 @@ int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
     }
 
     for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
-        CPUArchState *env = cpu->env_ptr;
-
-        err = kvm_update_guest_debug(env, 0);
+        err = kvm_update_guest_debug(cpu, 0);
         if (err) {
             return err;
         }
@@ -2007,15 +2002,13 @@ void kvm_remove_all_breakpoints(CPUState *cpu)
     kvm_arch_remove_all_hw_breakpoints();
 
     for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
-        CPUArchState *env = cpu->env_ptr;
-
-        kvm_update_guest_debug(env, 0);
+        kvm_update_guest_debug(cpu, 0);
     }
 }
 
 #else /* !KVM_CAP_SET_GUEST_DEBUG */
 
-int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
+int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
 {
     return -EINVAL;
 }
diff --git a/kvm-stub.c b/kvm-stub.c
index 7b2233ae82..771360b3ca 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,7 +78,7 @@ void kvm_setup_guest_memory(void *start, size_t size)
 {
 }
 
-int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
+int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
 {
     return -ENOSYS;
 }
diff --git a/linux-user/main.c b/linux-user/main.c
index 5dc09471e4..5309117034 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3637,7 +3637,7 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
     cpu = ENV_GET_CPU(env);
-    cpu_reset(ENV_GET_CPU(env));
+    cpu_reset(cpu);
 
     thread_cpu = cpu;
 
diff --git a/qom/cpu.c b/qom/cpu.c
index 5c45ab5333..dbc9fb6489 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -157,6 +157,17 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
 }
 
 
+static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
+{
+    return 0;
+}
+
+static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
+{
+    return 0;
+}
+
+
 void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
@@ -226,6 +237,14 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
     }
 }
 
+static void cpu_common_initfn(Object *obj)
+{
+    CPUState *cpu = CPU(obj);
+    CPUClass *cc = CPU_GET_CLASS(obj);
+
+    cpu->gdb_num_regs = cc->gdb_num_core_regs;
+}
+
 static int64_t cpu_common_get_arch_id(CPUState *cpu)
 {
     return cpu->cpu_index;
@@ -245,6 +264,8 @@ static void cpu_class_init(ObjectClass *klass, void *data)
     k->write_elf32_note = cpu_common_write_elf32_note;
     k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
     k->write_elf64_note = cpu_common_write_elf64_note;
+    k->gdb_read_register = cpu_common_gdb_read_register;
+    k->gdb_write_register = cpu_common_gdb_write_register;
     dc->realize = cpu_common_realizefn;
     dc->no_user = 1;
 }
@@ -253,6 +274,7 @@ static const TypeInfo cpu_type_info = {
     .name = TYPE_CPU,
     .parent = TYPE_DEVICE,
     .instance_size = sizeof(CPUState),
+    .instance_init = cpu_common_initfn,
     .abstract = true,
     .class_size = sizeof(CPUClass),
     .class_init = cpu_class_init,
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 9b701b4714..f306cbada3 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -7,6 +7,7 @@ stub-obj-y += fdset-add-fd.o
 stub-obj-y += fdset-find-fd.o
 stub-obj-y += fdset-get-fd.o
 stub-obj-y += fdset-remove-fd.o
+stub-obj-y += gdbstub.o
 stub-obj-y += get-fd.o
 stub-obj-y += get-vm-name.o
 stub-obj-y += iothread-lock.o
diff --git a/stubs/gdbstub.c b/stubs/gdbstub.c
new file mode 100644
index 0000000000..c1dbfe7fb7
--- /dev/null
+++ b/stubs/gdbstub.c
@@ -0,0 +1,5 @@
+#include "qemu-common.h"
+
+const char *const xml_builtin[][2] = {
+  { NULL, NULL }
+};
diff --git a/target-alpha/Makefile.objs b/target-alpha/Makefile.objs
index 590304cc61..b96c5da98d 100644
--- a/target-alpha/Makefile.objs
+++ b/target-alpha/Makefile.objs
@@ -1,3 +1,4 @@
 obj-$(CONFIG_SOFTMMU) += machine.o
 obj-y += translate.o helper.o cpu.o
 obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
+obj-y += gdbstub.o
diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h
index b2eeba36f3..2ebc9bcacb 100644
--- a/target-alpha/cpu-qom.h
+++ b/target-alpha/cpu-qom.h
@@ -82,5 +82,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
 void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
                           int flags);
 hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index c8c8c2c861..64c70bc1e9 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -271,11 +271,14 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = alpha_cpu_do_interrupt;
     cc->dump_state = alpha_cpu_dump_state;
     cc->set_pc = alpha_cpu_set_pc;
+    cc->gdb_read_register = alpha_cpu_gdb_read_register;
+    cc->gdb_write_register = alpha_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->do_unassigned_access = alpha_cpu_unassigned_access;
     cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
     dc->vmsd = &vmstate_alpha_cpu;
 #endif
+    cc->gdb_num_core_regs = 67;
 }
 
 static const TypeInfo alpha_cpu_type_info = {
diff --git a/target-alpha/gdbstub.c b/target-alpha/gdbstub.c
new file mode 100644
index 0000000000..980f140e72
--- /dev/null
+++ b/target-alpha/gdbstub.c
@@ -0,0 +1,93 @@
+/*
+ * Alpha gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+    CPUAlphaState *env = &cpu->env;
+    uint64_t val;
+    CPU_DoubleU d;
+
+    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;
+    }
+    return gdb_get_regl(mem_buf, val);
+}
+
+int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    AlphaCPU *cpu = ALPHA_CPU(cs);
+    CPUAlphaState *env = &cpu->env;
+    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;
+    }
+    return 8;
+}
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index 4a6e52e528..2d9f77fa9b 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -4,3 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-y += translate.o op_helper.o helper.o cpu.o
 obj-y += neon_helper.o iwmmxt_helper.o
+obj-y += gdbstub.o
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 02162c9aba..cf3658714e 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -149,4 +149,7 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
 
 hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 
+int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
 #endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index d3906a4829..87d35c6bf2 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -824,10 +824,14 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = arm_cpu_do_interrupt;
     cc->dump_state = arm_cpu_dump_state;
     cc->set_pc = arm_cpu_set_pc;
+    cc->gdb_read_register = arm_cpu_gdb_read_register;
+    cc->gdb_write_register = arm_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_arm_cpu;
 #endif
+    cc->gdb_num_core_regs = 26;
+    cc->gdb_core_xml_file = "arm-core.xml";
 }
 
 static void cpu_register(const ARMCPUInfo *info)
diff --git a/target-arm/gdbstub.c b/target-arm/gdbstub.c
new file mode 100644
index 0000000000..1c3439654f
--- /dev/null
+++ b/target-arm/gdbstub.c
@@ -0,0 +1,102 @@
+/*
+ * ARM gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+/* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
+   whatever the target description contains.  Due to a historical mishap
+   the FPA registers appear in between core integer regs and the CPSR.
+   We hack round this by giving the FPA regs zero size when talking to a
+   newer gdb.  */
+
+int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    if (n < 16) {
+        /* Core integer register.  */
+        return gdb_get_reg32(mem_buf, env->regs[n]);
+    }
+    if (n < 24) {
+        /* FPA registers.  */
+        if (gdb_has_xml) {
+            return 0;
+        }
+        memset(mem_buf, 0, 12);
+        return 12;
+    }
+    switch (n) {
+    case 24:
+        /* FPA status register.  */
+        if (gdb_has_xml) {
+            return 0;
+        }
+        return gdb_get_reg32(mem_buf, 0);
+    case 25:
+        /* CPSR */
+        return gdb_get_reg32(mem_buf, cpsr_read(env));
+    }
+    /* Unknown register.  */
+    return 0;
+}
+
+int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    uint32_t tmp;
+
+    tmp = ldl_p(mem_buf);
+
+    /* Mask out low bit of PC to workaround gdb bugs.  This will probably
+       cause problems if we ever implement the Jazelle DBX extensions.  */
+    if (n == 15) {
+        tmp &= ~1;
+    }
+
+    if (n < 16) {
+        /* Core integer register.  */
+        env->regs[n] = tmp;
+        return 4;
+    }
+    if (n < 24) { /* 16-23 */
+        /* FPA registers (ignored).  */
+        if (gdb_has_xml) {
+            return 0;
+        }
+        return 12;
+    }
+    switch (n) {
+    case 24:
+        /* FPA status register (ignored).  */
+        if (gdb_has_xml) {
+            return 0;
+        }
+        return 4;
+    case 25:
+        /* CPSR */
+        cpsr_write(env, tmp, 0xffffffff);
+        return 4;
+    }
+    /* Unknown register.  */
+    return 0;
+}
diff --git a/target-cris/Makefile.objs b/target-cris/Makefile.objs
index afb87bcc80..7779227fc4 100644
--- a/target-cris/Makefile.objs
+++ b/target-cris/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += mmu.o machine.o
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
index d7baf0746a..75593667d6 100644
--- a/target-cris/cpu-qom.h
+++ b/target-cris/cpu-qom.h
@@ -81,4 +81,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
 
 hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 
+int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
 #endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index ba095e75a5..45f2d6bacf 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -175,6 +175,7 @@ static void crisv8_cpu_class_init(ObjectClass *oc, void *data)
 
     ccc->vr = 8;
     cc->do_interrupt = crisv10_cpu_do_interrupt;
+    cc->gdb_read_register = crisv10_cpu_gdb_read_register;
 }
 
 static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
@@ -184,6 +185,7 @@ static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
 
     ccc->vr = 9;
     cc->do_interrupt = crisv10_cpu_do_interrupt;
+    cc->gdb_read_register = crisv10_cpu_gdb_read_register;
 }
 
 static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
@@ -193,6 +195,7 @@ static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
 
     ccc->vr = 10;
     cc->do_interrupt = crisv10_cpu_do_interrupt;
+    cc->gdb_read_register = crisv10_cpu_gdb_read_register;
 }
 
 static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
@@ -202,6 +205,7 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
 
     ccc->vr = 11;
     cc->do_interrupt = crisv10_cpu_do_interrupt;
+    cc->gdb_read_register = crisv10_cpu_gdb_read_register;
 }
 
 static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
@@ -255,9 +259,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = cris_cpu_do_interrupt;
     cc->dump_state = cris_cpu_dump_state;
     cc->set_pc = cris_cpu_set_pc;
+    cc->gdb_read_register = cris_cpu_gdb_read_register;
+    cc->gdb_write_register = cris_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
 #endif
+
+    cc->gdb_num_core_regs = 49;
 }
 
 static const TypeInfo cris_cpu_type_info = {
diff --git a/target-cris/gdbstub.c b/target-cris/gdbstub.c
new file mode 100644
index 0000000000..5db3683ab6
--- /dev/null
+++ b/target-cris/gdbstub.c
@@ -0,0 +1,130 @@
+/*
+ * CRIS gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+
+    if (n < 15) {
+        return gdb_get_reg32(mem_buf, env->regs[n]);
+    }
+
+    if (n == 15) {
+        return gdb_get_reg32(mem_buf, env->pc);
+    }
+
+    if (n < 32) {
+        switch (n) {
+        case 16:
+            return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
+        case 17:
+            return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
+        case 20:
+        case 21:
+            return gdb_get_reg16(mem_buf, env->pregs[n - 16]);
+        default:
+            if (n >= 23) {
+                return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
+            }
+            break;
+        }
+    }
+    return 0;
+}
+
+int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+    uint8_t srs;
+
+    srs = env->pregs[PR_SRS];
+    if (n < 16) {
+        return gdb_get_reg32(mem_buf, env->regs[n]);
+    }
+
+    if (n >= 21 && n < 32) {
+        return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
+    }
+    if (n >= 33 && n < 49) {
+        return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]);
+    }
+    switch (n) {
+    case 16:
+        return gdb_get_reg8(mem_buf, env->pregs[0]);
+    case 17:
+        return gdb_get_reg8(mem_buf, env->pregs[1]);
+    case 18:
+        return gdb_get_reg32(mem_buf, env->pregs[2]);
+    case 19:
+        return gdb_get_reg8(mem_buf, srs);
+    case 20:
+        return gdb_get_reg16(mem_buf, env->pregs[4]);
+    case 32:
+        return gdb_get_reg32(mem_buf, env->pc);
+    }
+
+    return 0;
+}
+
+int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    CRISCPU *cpu = CRIS_CPU(cs);
+    CPUCRISState *env = &cpu->env;
+    uint32_t tmp;
+
+    if (n > 49) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 16) {
+        env->regs[n] = tmp;
+    }
+
+    if (n >= 21 && n < 32) {
+        env->pregs[n - 16] = tmp;
+    }
+
+    /* FIXME: Should support function regs be writable?  */
+    switch (n) {
+    case 16:
+        return 1;
+    case 17:
+        return 1;
+    case 18:
+        env->pregs[PR_PID] = tmp;
+        break;
+    case 19:
+        return 1;
+    case 20:
+        return 2;
+    case 32:
+        env->pc = tmp;
+        break;
+    }
+
+    return 4;
+}
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index c1d4f059da..3b629d4d39 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -1,6 +1,7 @@
 obj-y += translate.o helper.o cpu.o
 obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
 obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
 obj-$(CONFIG_KVM) += kvm.o hyperv.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index d928562c53..60d2b5d772 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -106,4 +106,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
 
 hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 
+int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
 #endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index cd350cb8e4..2b59b7d7ef 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2538,6 +2538,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
     cc->dump_state = x86_cpu_dump_state;
     cc->set_pc = x86_cpu_set_pc;
     cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
+    cc->gdb_read_register = x86_cpu_gdb_read_register;
+    cc->gdb_write_register = x86_cpu_gdb_write_register;
     cc->get_arch_id = x86_cpu_get_arch_id;
     cc->get_paging_enabled = x86_cpu_get_paging_enabled;
 #ifndef CONFIG_USER_ONLY
@@ -2549,6 +2551,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
     cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
     cc->vmsd = &vmstate_x86_cpu;
 #endif
+    cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25;
 }
 
 static const TypeInfo x86_cpu_type_info = {
diff --git a/target-i386/gdbstub.c b/target-i386/gdbstub.c
new file mode 100644
index 0000000000..15bebeff89
--- /dev/null
+++ b/target-i386/gdbstub.c
@@ -0,0 +1,231 @@
+/*
+ * x86 gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+#ifdef TARGET_X86_64
+static const int gpr_map[16] = {
+    R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
+    8, 9, 10, 11, 12, 13, 14, 15
+};
+#else
+#define gpr_map gpr_map32
+#endif
+static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+#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)
+
+int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
+    if (n < CPU_NB_REGS) {
+        if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+            return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]);
+        } else if (n < CPU_NB_REGS32) {
+            return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
+        }
+    } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
+#ifdef USE_X86LDOUBLE
+        /* 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 >= 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 {
+        switch (n) {
+        case IDX_IP_REG:
+            if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+                return gdb_get_reg64(mem_buf, env->eip);
+            } else {
+                return gdb_get_reg32(mem_buf, env->eip);
+            }
+        case IDX_FLAGS_REG:
+            return gdb_get_reg32(mem_buf, env->eflags);
+
+        case IDX_SEG_REGS:
+            return gdb_get_reg32(mem_buf, env->segs[R_CS].selector);
+        case IDX_SEG_REGS + 1:
+            return gdb_get_reg32(mem_buf, env->segs[R_SS].selector);
+        case IDX_SEG_REGS + 2:
+            return gdb_get_reg32(mem_buf, env->segs[R_DS].selector);
+        case IDX_SEG_REGS + 3:
+            return gdb_get_reg32(mem_buf, env->segs[R_ES].selector);
+        case IDX_SEG_REGS + 4:
+            return gdb_get_reg32(mem_buf, env->segs[R_FS].selector);
+        case IDX_SEG_REGS + 5:
+            return gdb_get_reg32(mem_buf, env->segs[R_GS].selector);
+
+        case IDX_FP_REGS + 8:
+            return gdb_get_reg32(mem_buf, env->fpuc);
+        case IDX_FP_REGS + 9:
+            return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) |
+                                          (env->fpstt & 0x7) << 11);
+        case IDX_FP_REGS + 10:
+            return gdb_get_reg32(mem_buf, 0); /* ftag */
+        case IDX_FP_REGS + 11:
+            return gdb_get_reg32(mem_buf, 0); /* fiseg */
+        case IDX_FP_REGS + 12:
+            return gdb_get_reg32(mem_buf, 0); /* fioff */
+        case IDX_FP_REGS + 13:
+            return gdb_get_reg32(mem_buf, 0); /* foseg */
+        case IDX_FP_REGS + 14:
+            return gdb_get_reg32(mem_buf, 0); /* fooff */
+        case IDX_FP_REGS + 15:
+            return gdb_get_reg32(mem_buf, 0); /* fop */
+
+        case IDX_MXCSR_REG:
+            return gdb_get_reg32(mem_buf, env->mxcsr);
+        }
+    }
+    return 0;
+}
+
+static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf)
+{
+    CPUX86State *env = &cpu->env;
+    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;
+}
+
+int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+    uint32_t tmp;
+
+    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
+        /* FIXME: byteswap float values - after fixing fpregs layout. */
+        memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
+#endif
+        return 10;
+    } 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 {
+        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 x86_cpu_gdb_load_seg(cpu, R_CS, mem_buf);
+        case IDX_SEG_REGS + 1:
+            return x86_cpu_gdb_load_seg(cpu, R_SS, mem_buf);
+        case IDX_SEG_REGS + 2:
+            return x86_cpu_gdb_load_seg(cpu, R_DS, mem_buf);
+        case IDX_SEG_REGS + 3:
+            return x86_cpu_gdb_load_seg(cpu, R_ES, mem_buf);
+        case IDX_SEG_REGS + 4:
+            return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf);
+        case IDX_SEG_REGS + 5:
+            return x86_cpu_gdb_load_seg(cpu, 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.  */
+    return 0;
+}
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 3c9d10a762..376fc70ae3 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1618,7 +1618,7 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu)
      */
     if (reinject_trap ||
         (!kvm_has_robust_singlestep() && cs->singlestep_enabled)) {
-        ret = kvm_update_guest_debug(env, reinject_trap);
+        ret = kvm_update_guest_debug(cs, reinject_trap);
     }
     return ret;
 }
diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs
index ca20f21443..40236876c8 100644
--- a/target-lm32/Makefile.objs
+++ b/target-lm32/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index 9e2732919d..723f6049c3 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -79,5 +79,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
 void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                          int flags);
 hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index ce55e4807d..962d553de0 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -87,10 +87,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = lm32_cpu_do_interrupt;
     cc->dump_state = lm32_cpu_dump_state;
     cc->set_pc = lm32_cpu_set_pc;
+    cc->gdb_read_register = lm32_cpu_gdb_read_register;
+    cc->gdb_write_register = lm32_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
     cc->vmsd = &vmstate_lm32_cpu;
 #endif
+    cc->gdb_num_core_regs = 32 + 7;
 }
 
 static const TypeInfo lm32_cpu_type_info = {
diff --git a/target-lm32/gdbstub.c b/target-lm32/gdbstub.c
new file mode 100644
index 0000000000..4979a98d74
--- /dev/null
+++ b/target-lm32/gdbstub.c
@@ -0,0 +1,92 @@
+/*
+ * LM32 gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "hw/lm32/lm32_pic.h"
+
+int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    LM32CPU *cpu = LM32_CPU(cs);
+    CPULM32State *env = &cpu->env;
+
+    if (n < 32) {
+        return gdb_get_reg32(mem_buf, env->regs[n]);
+    } else {
+        switch (n) {
+        case 32:
+            return gdb_get_reg32(mem_buf, env->pc);
+        /* FIXME: put in right exception ID */
+        case 33:
+            return gdb_get_reg32(mem_buf, 0);
+        case 34:
+            return gdb_get_reg32(mem_buf, env->eba);
+        case 35:
+            return gdb_get_reg32(mem_buf, env->deba);
+        case 36:
+            return gdb_get_reg32(mem_buf, env->ie);
+        case 37:
+            return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state));
+        case 38:
+            return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state));
+        }
+    }
+    return 0;
+}
+
+int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    LM32CPU *cpu = LM32_CPU(cs);
+    CPUClass *cc = CPU_GET_CLASS(cs);
+    CPULM32State *env = &cpu->env;
+    uint32_t tmp;
+
+    if (n > cc->gdb_num_core_regs) {
+        return 0;
+    }
+
+    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;
+}
diff --git a/target-m68k/Makefile.objs b/target-m68k/Makefile.objs
index 2e2b85044d..02cf616a78 100644
--- a/target-m68k/Makefile.objs
+++ b/target-m68k/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y += m68k-semi.o
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h
index 7115707e91..7f388eda68 100644
--- a/target-m68k/cpu-qom.h
+++ b/target-m68k/cpu-qom.h
@@ -74,5 +74,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
 void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                          int flags);
 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index 988f476257..c0bcb0dbce 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -190,10 +190,14 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
     cc->do_interrupt = m68k_cpu_do_interrupt;
     cc->dump_state = m68k_cpu_dump_state;
     cc->set_pc = m68k_cpu_set_pc;
+    cc->gdb_read_register = m68k_cpu_gdb_read_register;
+    cc->gdb_write_register = m68k_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_m68k_cpu;
+    cc->gdb_num_core_regs = 18;
+    cc->gdb_core_xml_file = "cf-core.xml";
 }
 
 static void register_cpu_type(const M68kCPUInfo *info)
diff --git a/target-m68k/gdbstub.c b/target-m68k/gdbstub.c
new file mode 100644
index 0000000000..ae8179c016
--- /dev/null
+++ b/target-m68k/gdbstub.c
@@ -0,0 +1,75 @@
+/*
+ * m68k gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
+    if (n < 8) {
+        /* D0-D7 */
+        return gdb_get_reg32(mem_buf, env->dregs[n]);
+    } else if (n < 16) {
+        /* A0-A7 */
+        return gdb_get_reg32(mem_buf, env->aregs[n - 8]);
+    } else {
+        switch (n) {
+        case 16:
+            return gdb_get_reg32(mem_buf, env->sr);
+        case 17:
+            return gdb_get_reg32(mem_buf, env->pc);
+        }
+    }
+    /* FP registers not included here because they vary between
+       ColdFire and m68k.  Use XML bits for these.  */
+    return 0;
+}
+
+int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+    uint32_t tmp;
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 8) {
+        /* D0-D7 */
+        env->dregs[n] = tmp;
+    } else if (n < 16) {
+        /* A0-A7 */
+        env->aregs[n - 8] = tmp;
+    } else {
+        switch (n) {
+        case 16:
+            env->sr = tmp;
+            break;
+        case 17:
+            env->pc = tmp;
+            break;
+        default:
+            return 0;
+        }
+    }
+    return 4;
+}
diff --git a/target-microblaze/Makefile.objs b/target-microblaze/Makefile.objs
index 985330eac5..f3d7b44c89 100644
--- a/target-microblaze/Makefile.objs
+++ b/target-microblaze/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += mmu.o
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
index 1318a36676..35a12b42a5 100644
--- a/target-microblaze/cpu-qom.h
+++ b/target-microblaze/cpu-qom.h
@@ -75,5 +75,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
 void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                        int flags);
 hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 9f10c8c778..c75d1bd642 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -141,12 +141,15 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = mb_cpu_do_interrupt;
     cc->dump_state = mb_cpu_dump_state;
     cc->set_pc = mb_cpu_set_pc;
+    cc->gdb_read_register = mb_cpu_gdb_read_register;
+    cc->gdb_write_register = mb_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->do_unassigned_access = mb_cpu_unassigned_access;
     cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_mb_cpu;
     dc->props = mb_properties;
+    cc->gdb_num_core_regs = 32 + 5;
 }
 
 static const TypeInfo mb_cpu_type_info = {
diff --git a/target-microblaze/gdbstub.c b/target-microblaze/gdbstub.c
new file mode 100644
index 0000000000..a70e2ee3cb
--- /dev/null
+++ b/target-microblaze/gdbstub.c
@@ -0,0 +1,56 @@
+/*
+ * MicroBlaze gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUMBState *env = &cpu->env;
+
+    if (n < 32) {
+        return gdb_get_reg32(mem_buf, env->regs[n]);
+    } else {
+        return gdb_get_reg32(mem_buf, env->sregs[n - 32]);
+    }
+    return 0;
+}
+
+int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+    CPUClass *cc = CPU_GET_CLASS(cs);
+    CPUMBState *env = &cpu->env;
+    uint32_t tmp;
+
+    if (n > cc->gdb_num_core_regs) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+        env->regs[n] = tmp;
+    } else {
+        env->sregs[n - 32] = tmp;
+    }
+    return 4;
+}
diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs
index 119c816518..0277d56e82 100644
--- a/target-mips/Makefile.objs
+++ b/target-mips/Makefile.objs
@@ -1,2 +1,3 @@
 obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h
index 7c8e616392..8877f813f7 100644
--- a/target-mips/cpu-qom.h
+++ b/target-mips/cpu-qom.h
@@ -78,5 +78,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
 void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                          int flags);
 hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 4834c86d02..f81f9e9409 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -100,10 +100,14 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
     cc->dump_state = mips_cpu_dump_state;
     cc->set_pc = mips_cpu_set_pc;
     cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
+    cc->gdb_read_register = mips_cpu_gdb_read_register;
+    cc->gdb_write_register = mips_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->do_unassigned_access = mips_cpu_unassigned_access;
     cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
 #endif
+
+    cc->gdb_num_core_regs = 73;
 }
 
 static const TypeInfo mips_cpu_type_info = {
diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c
new file mode 100644
index 0000000000..5b72d58a44
--- /dev/null
+++ b/target-mips/gdbstub.c
@@ -0,0 +1,155 @@
+/*
+ * MIPS gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
+
+    if (n < 32) {
+        return gdb_get_regl(mem_buf, env->active_tc.gpr[n]);
+    }
+    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+        if (n >= 38 && n < 70) {
+            if (env->CP0_Status & (1 << CP0St_FR)) {
+                return gdb_get_regl(mem_buf,
+                    env->active_fpu.fpr[n - 38].d);
+            } else {
+                return gdb_get_regl(mem_buf,
+                    env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
+            }
+        }
+        switch (n) {
+        case 70:
+            return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31);
+        case 71:
+            return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0);
+        }
+    }
+    switch (n) {
+    case 32:
+        return gdb_get_regl(mem_buf, (int32_t)env->CP0_Status);
+    case 33:
+        return gdb_get_regl(mem_buf, env->active_tc.LO[0]);
+    case 34:
+        return gdb_get_regl(mem_buf, env->active_tc.HI[0]);
+    case 35:
+        return gdb_get_regl(mem_buf, env->CP0_BadVAddr);
+    case 36:
+        return gdb_get_regl(mem_buf, (int32_t)env->CP0_Cause);
+    case 37:
+        return gdb_get_regl(mem_buf, env->active_tc.PC |
+                                     !!(env->hflags & MIPS_HFLAG_M16));
+    case 72:
+        return gdb_get_regl(mem_buf, 0); /* fp */
+    case 89:
+        return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid);
+    }
+    if (n >= 73 && n <= 88) {
+        /* 16 embedded regs.  */
+        return gdb_get_regl(mem_buf, 0);
+    }
+
+    return 0;
+}
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+static unsigned int ieee_rm[] = {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down
+};
+#define RESTORE_ROUNDING_MODE \
+    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \
+                            &env->active_fpu.fp_status)
+
+int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    MIPSCPU *cpu = MIPS_CPU(cs);
+    CPUMIPSState *env = &cpu->env;
+    target_ulong tmp;
+
+    tmp = ldtul_p(mem_buf);
+
+    if (n < 32) {
+        env->active_tc.gpr[n] = tmp;
+        return sizeof(target_ulong);
+    }
+    if (env->CP0_Config1 & (1 << CP0C1_FP)
+            && n >= 38 && n < 73) {
+        if (n < 70) {
+            if (env->CP0_Status & (1 << CP0St_FR)) {
+                env->active_fpu.fpr[n - 38].d = tmp;
+            } else {
+                env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
+            }
+        }
+        switch (n) {
+        case 70:
+            env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
+            /* set rounding mode */
+            RESTORE_ROUNDING_MODE;
+            break;
+        case 71:
+            env->active_fpu.fcr0 = tmp;
+            break;
+        }
+        return sizeof(target_ulong);
+    }
+    switch (n) {
+    case 32:
+        env->CP0_Status = tmp;
+        break;
+    case 33:
+        env->active_tc.LO[0] = tmp;
+        break;
+    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 & ~(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) {
+            return 0;
+        }
+        /* Other registers are readonly.  Ignore writes.  */
+        break;
+    }
+
+    return sizeof(target_ulong);
+}
diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
index 44dc5399df..397d01650e 100644
--- a/target-openrisc/Makefile.objs
+++ b/target-openrisc/Makefile.objs
@@ -2,3 +2,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o
 obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
 obj-y += exception_helper.o fpu_helper.o int_helper.o \
          interrupt_helper.o mmu_helper.o sys_helper.o
+obj-y += gdbstub.o
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index 7718820ecc..aa269fb7a6 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -155,10 +155,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = openrisc_cpu_do_interrupt;
     cc->dump_state = openrisc_cpu_dump_state;
     cc->set_pc = openrisc_cpu_set_pc;
+    cc->gdb_read_register = openrisc_cpu_gdb_read_register;
+    cc->gdb_write_register = openrisc_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
     dc->vmsd = &vmstate_openrisc_cpu;
 #endif
+    cc->gdb_num_core_regs = 32 + 3;
 }
 
 static void cpu_register(const OpenRISCCPUInfo *info)
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 3ddb7674c7..8fd0bc0bf0 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -350,6 +350,8 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
 void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
                              fprintf_function cpu_fprintf, int flags);
 hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void openrisc_translate_init(void);
 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
                                   target_ulong address,
diff --git a/target-openrisc/gdbstub.c b/target-openrisc/gdbstub.c
new file mode 100644
index 0000000000..18bcc46167
--- /dev/null
+++ b/target-openrisc/gdbstub.c
@@ -0,0 +1,83 @@
+/*
+ * OpenRISC gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+    CPUOpenRISCState *env = &cpu->env;
+
+    if (n < 32) {
+        return gdb_get_reg32(mem_buf, env->gpr[n]);
+    } else {
+        switch (n) {
+        case 32:    /* PPC */
+            return gdb_get_reg32(mem_buf, env->ppc);
+
+        case 33:    /* NPC */
+            return gdb_get_reg32(mem_buf, env->npc);
+
+        case 34:    /* SR */
+            return gdb_get_reg32(mem_buf, env->sr);
+
+        default:
+            break;
+        }
+    }
+    return 0;
+}
+
+int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+    CPUClass *cc = CPU_GET_CLASS(cs);
+    CPUOpenRISCState *env = &cpu->env;
+    uint32_t tmp;
+
+    if (n > cc->gdb_num_core_regs) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+        env->gpr[n] = tmp;
+    } else {
+        switch (n) {
+        case 32: /* PPC */
+            env->ppc = tmp;
+            break;
+
+        case 33: /* NPC */
+            env->npc = tmp;
+            break;
+
+        case 34: /* SR */
+            env->sr = tmp;
+            break;
+
+        default:
+            break;
+        }
+    }
+    return 4;
+}
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 6e78cb3624..f72e3993f7 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -13,3 +13,4 @@ obj-y += timebase_helper.o
 obj-y += misc_helper.o
 obj-y += mem_helper.o
 obj-$(CONFIG_USER_ONLY) += user_only_helper.o
+obj-y += gdbstub.o
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 3341c5151d..fc0d737880 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -106,5 +106,7 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
 void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
                              fprintf_function cpu_fprintf, int flags);
 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c
new file mode 100644
index 0000000000..1c910902ea
--- /dev/null
+++ b/target-ppc/gdbstub.c
@@ -0,0 +1,131 @@
+/*
+ * PowerPC gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+/* Old gdb always expects FP registers.  Newer (xml-aware) gdb only
+ * expects whatever the target description contains.  Due to a
+ * historical mishap the FP registers appear in between core integer
+ * regs and PC, MSR, CR, and so forth.  We hack round this by giving the
+ * FP regs zero size when talking to a newer gdb.
+ */
+
+int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
+    if (n < 32) {
+        /* gprs */
+        return gdb_get_regl(mem_buf, env->gpr[n]);
+    } else if (n < 64) {
+        /* fprs */
+        if (gdb_has_xml) {
+            return 0;
+        }
+        stfq_p(mem_buf, env->fpr[n-32]);
+        return 8;
+    } else {
+        switch (n) {
+        case 64:
+            return gdb_get_regl(mem_buf, env->nip);
+        case 65:
+            return gdb_get_regl(mem_buf, env->msr);
+        case 66:
+            {
+                uint32_t cr = 0;
+                int i;
+                for (i = 0; i < 8; i++) {
+                    cr |= env->crf[i] << (32 - ((i + 1) * 4));
+                }
+                return gdb_get_reg32(mem_buf, cr);
+            }
+        case 67:
+            return gdb_get_regl(mem_buf, env->lr);
+        case 68:
+            return gdb_get_regl(mem_buf, env->ctr);
+        case 69:
+            return gdb_get_regl(mem_buf, env->xer);
+        case 70:
+            {
+                if (gdb_has_xml) {
+                    return 0;
+                }
+                return gdb_get_reg32(mem_buf, env->fpscr);
+            }
+        }
+    }
+    return 0;
+}
+
+int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
+    if (n < 32) {
+        /* gprs */
+        env->gpr[n] = ldtul_p(mem_buf);
+        return sizeof(target_ulong);
+    } else if (n < 64) {
+        /* fprs */
+        if (gdb_has_xml) {
+            return 0;
+        }
+        env->fpr[n-32] = ldfq_p(mem_buf);
+        return 8;
+    } else {
+        switch (n) {
+        case 64:
+            env->nip = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 65:
+            ppc_store_msr(env, ldtul_p(mem_buf));
+            return sizeof(target_ulong);
+        case 66:
+            {
+                uint32_t cr = ldl_p(mem_buf);
+                int i;
+                for (i = 0; i < 8; i++) {
+                    env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
+                }
+                return 4;
+            }
+        case 67:
+            env->lr = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 68:
+            env->ctr = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 69:
+            env->xer = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 70:
+            /* fpscr */
+            if (gdb_has_xml) {
+                return 0;
+            }
+            store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
+            return sizeof(target_ulong);
+        }
+    }
+    return 0;
+}
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 0b0844f467..8215946e39 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8458,9 +8458,18 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = ppc_cpu_dump_state;
     cc->dump_statistics = ppc_cpu_dump_statistics;
     cc->set_pc = ppc_cpu_set_pc;
+    cc->gdb_read_register = ppc_cpu_gdb_read_register;
+    cc->gdb_write_register = ppc_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
 #endif
+
+    cc->gdb_num_core_regs = 71;
+#if defined(TARGET_PPC64)
+    cc->gdb_core_xml_file = "power64-core.xml";
+#else
+    cc->gdb_core_xml_file = "power-core.xml";
+#endif
 }
 
 static const TypeInfo ppc_cpu_type_info = {
diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs
index 4e634173a4..ab938e7ad8 100644
--- a/target-s390x/Makefile.objs
+++ b/target-s390x/Makefile.objs
@@ -1,4 +1,5 @@
 obj-y += translate.o helper.o cpu.o interrupt.o
 obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += ioinst.o
 obj-$(CONFIG_KVM) += kvm.o
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index a4fe8fb5fc..0d63b1cf20 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -75,5 +75,7 @@ void s390_cpu_do_interrupt(CPUState *cpu);
 void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                          int flags);
 hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index cb89d1a46b..1d16da3787 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -173,10 +173,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
     cc->do_interrupt = s390_cpu_do_interrupt;
     cc->dump_state = s390_cpu_dump_state;
     cc->set_pc = s390_cpu_set_pc;
+    cc->gdb_read_register = s390_cpu_gdb_read_register;
+    cc->gdb_write_register = s390_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_s390_cpu;
+    cc->gdb_num_core_regs = S390_NUM_REGS;
 }
 
 static const TypeInfo s390_cpu_type_info = {
diff --git a/target-s390x/gdbstub.c b/target-s390x/gdbstub.c
new file mode 100644
index 0000000000..a129742e2f
--- /dev/null
+++ b/target-s390x/gdbstub.c
@@ -0,0 +1,88 @@
+/*
+ * s390x gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "qemu/bitops.h"
+
+int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    uint64_t val;
+    int cc_op;
+
+    switch (n) {
+    case S390_PSWM_REGNUM:
+        cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
+        val = deposit64(env->psw.mask, 44, 2, cc_op);
+        return gdb_get_regl(mem_buf, val);
+    case S390_PSWA_REGNUM:
+        return gdb_get_regl(mem_buf, env->psw.addr);
+    case S390_R0_REGNUM ... S390_R15_REGNUM:
+        return gdb_get_regl(mem_buf, env->regs[n-S390_R0_REGNUM]);
+    case S390_A0_REGNUM ... S390_A15_REGNUM:
+        return gdb_get_reg32(mem_buf, env->aregs[n-S390_A0_REGNUM]);
+    case S390_FPC_REGNUM:
+        return gdb_get_reg32(mem_buf, env->fpc);
+    case S390_F0_REGNUM ... S390_F15_REGNUM:
+        return gdb_get_reg64(mem_buf, env->fregs[n-S390_F0_REGNUM].ll);
+    }
+
+    return 0;
+}
+
+int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    target_ulong tmpl;
+    uint32_t tmp32;
+    int r = 8;
+    tmpl = ldtul_p(mem_buf);
+    tmp32 = ldl_p(mem_buf);
+
+    switch (n) {
+    case S390_PSWM_REGNUM:
+        env->psw.mask = tmpl;
+        env->cc_op = extract64(tmpl, 44, 2);
+        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:
+        env->fregs[n-S390_F0_REGNUM].ll = tmpl;
+        break;
+    default:
+        return 0;
+    }
+    return r;
+}
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 60e94f8ee8..85f01125de 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -345,12 +345,10 @@ void *kvm_arch_ram_alloc(ram_addr_t size)
 
 int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
     static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
 
-    if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
-        cpu_memory_rw_debug(env, bp->pc, (uint8_t *)diag_501, 4, 1)) {
+    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
+        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) {
         return -EINVAL;
     }
     return 0;
@@ -358,16 +356,14 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 
 int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
     uint8_t t[4];
     static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
 
-    if (cpu_memory_rw_debug(env, bp->pc, t, 4, 0)) {
+    if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) {
         return -EINVAL;
     } else if (memcmp(t, diag_501, 4)) {
         return -EINVAL;
-    } else if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+    } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
         return -EINVAL;
     }
 
diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs
index cb448a840f..a285358adf 100644
--- a/target-sh4/Makefile.objs
+++ b/target-sh4/Makefile.objs
@@ -1 +1,2 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h
index 7c9160bab8..c04e78631b 100644
--- a/target-sh4/cpu-qom.h
+++ b/target-sh4/cpu-qom.h
@@ -87,5 +87,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
 void superh_cpu_dump_state(CPUState *cpu, FILE *f,
                            fprintf_function cpu_fprintf, int flags);
 hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index 51a77576fb..bda3c5112c 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -286,10 +286,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
     cc->dump_state = superh_cpu_dump_state;
     cc->set_pc = superh_cpu_set_pc;
     cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
+    cc->gdb_read_register = superh_cpu_gdb_read_register;
+    cc->gdb_write_register = superh_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
 #endif
     dc->vmsd = &vmstate_sh_cpu;
+    cc->gdb_num_core_regs = 59;
 }
 
 static const TypeInfo superh_cpu_type_info = {
diff --git a/target-sh4/gdbstub.c b/target-sh4/gdbstub.c
new file mode 100644
index 0000000000..df4fa2af76
--- /dev/null
+++ b/target-sh4/gdbstub.c
@@ -0,0 +1,146 @@
+/*
+ * SuperH gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
+/* FIXME: We should use XML for this.  */
+
+int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
+
+    switch (n) {
+    case 0 ... 7:
+        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+            return gdb_get_regl(mem_buf, env->gregs[n + 16]);
+        } else {
+            return gdb_get_regl(mem_buf, env->gregs[n]);
+        }
+    case 8 ... 15:
+        return gdb_get_regl(mem_buf, env->gregs[n]);
+    case 16:
+        return gdb_get_regl(mem_buf, env->pc);
+    case 17:
+        return gdb_get_regl(mem_buf, env->pr);
+    case 18:
+        return gdb_get_regl(mem_buf, env->gbr);
+    case 19:
+        return gdb_get_regl(mem_buf, env->vbr);
+    case 20:
+        return gdb_get_regl(mem_buf, env->mach);
+    case 21:
+        return gdb_get_regl(mem_buf, env->macl);
+    case 22:
+        return gdb_get_regl(mem_buf, env->sr);
+    case 23:
+        return gdb_get_regl(mem_buf, env->fpul);
+    case 24:
+        return gdb_get_regl(mem_buf, env->fpscr);
+    case 25 ... 40:
+        if (env->fpscr & FPSCR_FR) {
+            stfl_p(mem_buf, env->fregs[n - 9]);
+        } else {
+            stfl_p(mem_buf, env->fregs[n - 25]);
+        }
+        return 4;
+    case 41:
+        return gdb_get_regl(mem_buf, env->ssr);
+    case 42:
+        return gdb_get_regl(mem_buf, env->spc);
+    case 43 ... 50:
+        return gdb_get_regl(mem_buf, env->gregs[n - 43]);
+    case 51 ... 58:
+        return gdb_get_regl(mem_buf, env->gregs[n - (51 - 16)]);
+    }
+
+    return 0;
+}
+
+int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    SuperHCPU *cpu = SUPERH_CPU(cs);
+    CPUSH4State *env = &cpu->env;
+
+    switch (n) {
+    case 0 ... 7:
+        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+            env->gregs[n + 16] = ldl_p(mem_buf);
+        } else {
+            env->gregs[n] = ldl_p(mem_buf);
+        }
+        break;
+    case 8 ... 15:
+        env->gregs[n] = ldl_p(mem_buf);
+        break;
+    case 16:
+        env->pc = ldl_p(mem_buf);
+        break;
+    case 17:
+        env->pr = ldl_p(mem_buf);
+        break;
+    case 18:
+        env->gbr = ldl_p(mem_buf);
+        break;
+    case 19:
+        env->vbr = ldl_p(mem_buf);
+        break;
+    case 20:
+        env->mach = ldl_p(mem_buf);
+        break;
+    case 21:
+        env->macl = ldl_p(mem_buf);
+        break;
+    case 22:
+        env->sr = ldl_p(mem_buf);
+        break;
+    case 23:
+        env->fpul = ldl_p(mem_buf);
+        break;
+    case 24:
+        env->fpscr = ldl_p(mem_buf);
+        break;
+    case 25 ... 40:
+        if (env->fpscr & FPSCR_FR) {
+            env->fregs[n - 9] = ldfl_p(mem_buf);
+        } else {
+            env->fregs[n - 25] = ldfl_p(mem_buf);
+        }
+        break;
+    case 41:
+        env->ssr = ldl_p(mem_buf);
+        break;
+    case 42:
+        env->spc = ldl_p(mem_buf);
+        break;
+    case 43 ... 50:
+        env->gregs[n - 43] = ldl_p(mem_buf);
+        break;
+    case 51 ... 58:
+        env->gregs[n - (51 - 16)] = ldl_p(mem_buf);
+        break;
+    default:
+        return 0;
+    }
+
+    return 4;
+}
diff --git a/target-sparc/Makefile.objs b/target-sparc/Makefile.objs
index 9fc42ea9b0..1cd81cccc3 100644
--- a/target-sparc/Makefile.objs
+++ b/target-sparc/Makefile.objs
@@ -4,3 +4,4 @@ obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
 obj-$(TARGET_SPARC) += int32_helper.o
 obj-$(TARGET_SPARC64) += int64_helper.o
 obj-$(TARGET_SPARC64) += vis_helper.o
+obj-y += gdbstub.o
diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h
index 39d975b5fc..8e3e0de277 100644
--- a/target-sparc/cpu-qom.h
+++ b/target-sparc/cpu-qom.h
@@ -79,5 +79,7 @@ void sparc_cpu_do_interrupt(CPUState *cpu);
 void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
                           fprintf_function cpu_fprintf, int flags);
 hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index d1d03396ef..c7b4a90663 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -787,10 +787,18 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
 #endif
     cc->set_pc = sparc_cpu_set_pc;
     cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
+    cc->gdb_read_register = sparc_cpu_gdb_read_register;
+    cc->gdb_write_register = sparc_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->do_unassigned_access = sparc_cpu_unassigned_access;
     cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
 #endif
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+    cc->gdb_num_core_regs = 86;
+#else
+    cc->gdb_num_core_regs = 72;
+#endif
 }
 
 static const TypeInfo sparc_cpu_type_info = {
diff --git a/target-sparc/gdbstub.c b/target-sparc/gdbstub.c
new file mode 100644
index 0000000000..3de3242b29
--- /dev/null
+++ b/target-sparc/gdbstub.c
@@ -0,0 +1,208 @@
+/*
+ * SPARC gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+#ifdef TARGET_ABI32
+#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val)
+#else
+#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
+#endif
+
+int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
+
+    if (n < 8) {
+        /* g0..g7 */
+        return gdb_get_rega(mem_buf, env->gregs[n]);
+    }
+    if (n < 32) {
+        /* register window */
+        return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
+    }
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+    if (n < 64) {
+        /* fprs */
+        if (n & 1) {
+            return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
+        } else {
+            return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
+        }
+    }
+    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+    switch (n) {
+    case 64:
+        return gdb_get_rega(mem_buf, env->y);
+    case 65:
+        return gdb_get_rega(mem_buf, cpu_get_psr(env));
+    case 66:
+        return gdb_get_rega(mem_buf, env->wim);
+    case 67:
+        return gdb_get_rega(mem_buf, env->tbr);
+    case 68:
+        return gdb_get_rega(mem_buf, env->pc);
+    case 69:
+        return gdb_get_rega(mem_buf, env->npc);
+    case 70:
+        return gdb_get_rega(mem_buf, env->fsr);
+    case 71:
+        return gdb_get_rega(mem_buf, 0); /* csr */
+    default:
+        return gdb_get_rega(mem_buf, 0);
+    }
+#else
+    if (n < 64) {
+        /* f0-f31 */
+        if (n & 1) {
+            return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
+        } else {
+            return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
+        }
+    }
+    if (n < 80) {
+        /* f32-f62 (double width, even numbers only) */
+        return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll);
+    }
+    switch (n) {
+    case 80:
+        return gdb_get_regl(mem_buf, env->pc);
+    case 81:
+        return gdb_get_regl(mem_buf, env->npc);
+    case 82:
+        return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) |
+                                     ((env->asi & 0xff) << 24) |
+                                     ((env->pstate & 0xfff) << 8) |
+                                     cpu_get_cwp64(env));
+    case 83:
+        return gdb_get_regl(mem_buf, env->fsr);
+    case 84:
+        return gdb_get_regl(mem_buf, env->fprs);
+    case 85:
+        return gdb_get_regl(mem_buf, env->y);
+    }
+#endif
+    return 0;
+}
+
+int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    SPARCCPU *cpu = SPARC_CPU(cs);
+    CPUSPARCState *env = &cpu->env;
+#if defined(TARGET_ABI32)
+    abi_ulong tmp;
+
+    tmp = ldl_p(mem_buf);
+#else
+    target_ulong tmp;
+
+    tmp = ldtul_p(mem_buf);
+#endif
+
+    if (n < 8) {
+        /* g0..g7 */
+        env->gregs[n] = tmp;
+    } else if (n < 32) {
+        /* register window */
+        env->regwptr[n - 8] = tmp;
+    }
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+    else if (n < 64) {
+        /* fprs */
+        /* f0-f31 */
+        if (n & 1) {
+            env->fpr[(n - 32) / 2].l.lower = tmp;
+        } else {
+            env->fpr[(n - 32) / 2].l.upper = tmp;
+        }
+    } else {
+        /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+        switch (n) {
+        case 64:
+            env->y = 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;
+        case 69:
+            env->npc = tmp;
+            break;
+        case 70:
+            env->fsr = tmp;
+            break;
+        default:
+            return 0;
+        }
+    }
+    return 4;
+#else
+    else if (n < 64) {
+        /* f0-f31 */
+        tmp = ldl_p(mem_buf);
+        if (n & 1) {
+            env->fpr[(n - 32) / 2].l.lower = tmp;
+        } else {
+            env->fpr[(n - 32) / 2].l.upper = tmp;
+        }
+        return 4;
+    } else if (n < 80) {
+        /* f32-f62 (double width, even numbers only) */
+        env->fpr[(n - 32) / 2].ll = tmp;
+    } else {
+        switch (n) {
+        case 80:
+            env->pc = tmp;
+            break;
+        case 81:
+            env->npc = tmp;
+            break;
+        case 82:
+            cpu_put_ccr(env, tmp >> 32);
+            env->asi = (tmp >> 24) & 0xff;
+            env->pstate = (tmp >> 8) & 0xfff;
+            cpu_put_cwp64(env, tmp & 0xff);
+            break;
+        case 83:
+            env->fsr = tmp;
+            break;
+        case 84:
+            env->fprs = tmp;
+            break;
+        case 85:
+            env->y = tmp;
+            break;
+        default:
+            return 0;
+        }
+    }
+    return 8;
+#endif
+}
diff --git a/target-xtensa/Makefile.objs b/target-xtensa/Makefile.objs
index 644b7f99bb..5c150a870f 100644
--- a/target-xtensa/Makefile.objs
+++ b/target-xtensa/Makefile.objs
@@ -3,3 +3,4 @@ obj-y += core-dc232b.o
 obj-y += core-dc233c.o
 obj-y += core-fsf.o
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
index b9896f2647..c6cc2d91f4 100644
--- a/target-xtensa/cpu-qom.h
+++ b/target-xtensa/cpu-qom.h
@@ -45,6 +45,7 @@
  * XtensaCPUClass:
  * @parent_realize: The parent class' realize handler.
  * @parent_reset: The parent class' reset handler.
+ * @config: The CPU core configuration.
  *
  * An Xtensa CPU model.
  */
@@ -55,6 +56,8 @@ typedef struct XtensaCPUClass {
 
     DeviceRealize parent_realize;
     void (*parent_reset)(CPUState *cpu);
+
+    const XtensaConfig *config;
 } XtensaCPUClass;
 
 /**
@@ -84,5 +87,7 @@ void xtensa_cpu_do_interrupt(CPUState *cpu);
 void xtensa_cpu_dump_state(CPUState *cpu, FILE *f,
                            fprintf_function cpu_fprintf, int flags);
 hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 #endif
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index d2bcfc69a2..e966aa0a79 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -64,10 +64,32 @@ static void xtensa_cpu_reset(CPUState *s)
     reset_mmu(env);
 }
 
+static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    char *typename;
+
+    if (cpu_model == NULL) {
+        return NULL;
+    }
+
+    typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model);
+    oc = object_class_by_name(typename);
+    g_free(typename);
+    if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) ||
+        object_class_is_abstract(oc)) {
+        return NULL;
+    }
+    return oc;
+}
+
 static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
 {
+    CPUState *cs = CPU(dev);
     XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
 
+    cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs;
+
     xcc->parent_realize(dev, errp);
 }
 
@@ -75,10 +97,12 @@ static void xtensa_cpu_initfn(Object *obj)
 {
     CPUState *cs = CPU(obj);
     XtensaCPU *cpu = XTENSA_CPU(obj);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj);
     CPUXtensaState *env = &cpu->env;
     static bool tcg_inited;
 
     cs->env_ptr = env;
+    env->config = xcc->config;
     cpu_exec_init(env);
 
     if (tcg_enabled() && !tcg_inited) {
@@ -105,9 +129,12 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
     xcc->parent_reset = cc->reset;
     cc->reset = xtensa_cpu_reset;
 
+    cc->class_by_name = xtensa_cpu_class_by_name;
     cc->do_interrupt = xtensa_cpu_do_interrupt;
     cc->dump_state = xtensa_cpu_dump_state;
     cc->set_pc = xtensa_cpu_set_pc;
+    cc->gdb_read_register = xtensa_cpu_gdb_read_register;
+    cc->gdb_write_register = xtensa_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
     cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
 #endif
@@ -119,7 +146,7 @@ static const TypeInfo xtensa_cpu_type_info = {
     .parent = TYPE_CPU,
     .instance_size = sizeof(XtensaCPU),
     .instance_init = xtensa_cpu_initfn,
-    .abstract = false,
+    .abstract = true,
     .class_size = sizeof(XtensaCPUClass),
     .class_init = xtensa_cpu_class_init,
 };
diff --git a/target-xtensa/gdbstub.c b/target-xtensa/gdbstub.c
new file mode 100644
index 0000000000..9e13b20c46
--- /dev/null
+++ b/target-xtensa/gdbstub.c
@@ -0,0 +1,109 @@
+/*
+ * Xtensa gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        return gdb_get_reg32(mem_buf, env->pc);
+
+    case 1: /*ar*/
+        xtensa_sync_phys_from_window(env);
+        return gdb_get_reg32(mem_buf, env->phys_regs[(reg->targno & 0xff)
+                                                     % env->config->nareg]);
+
+    case 2: /*SR*/
+        return gdb_get_reg32(mem_buf, env->sregs[reg->targno & 0xff]);
+
+    case 3: /*UR*/
+        return gdb_get_reg32(mem_buf, env->uregs[reg->targno & 0xff]);
+
+    case 4: /*f*/
+        return gdb_get_reg32(mem_buf, float32_val(env->fregs[reg->targno
+                                                             & 0x0f]));
+
+    case 8: /*a*/
+        return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]);
+
+    default:
+        qemu_log("%s from reg %d of unsupported type %d\n",
+                 __func__, n, reg->type);
+        return 0;
+    }
+}
+
+int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    XtensaCPU *cpu = XTENSA_CPU(cs);
+    CPUXtensaState *env = &cpu->env;
+    uint32_t tmp;
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        env->pc = tmp;
+        break;
+
+    case 1: /*ar*/
+        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
+        xtensa_sync_window_from_phys(env);
+        break;
+
+    case 2: /*SR*/
+        env->sregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 3: /*UR*/
+        env->uregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 4: /*f*/
+        env->fregs[reg->targno & 0x0f] = make_float32(tmp);
+        break;
+
+    case 8: /*a*/
+        env->regs[reg->targno & 0x0f] = tmp;
+        break;
+
+    default:
+        qemu_log("%s to reg %d of unsupported type %d\n",
+                 __func__, n, reg->type);
+        return 0;
+    }
+
+    return 4;
+}
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index de6cc3b7c5..a0f9993b2d 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -35,10 +35,35 @@
 
 static struct XtensaConfigList *xtensa_cores;
 
+static void xtensa_core_class_init(ObjectClass *oc, void *data)
+{
+    CPUClass *cc = CPU_CLASS(oc);
+    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
+    const XtensaConfig *config = data;
+
+    xcc->config = config;
+
+    /* Use num_core_regs to see only non-privileged registers in an unmodified
+     * gdb. Use num_regs to see all registers. gdb modification is required
+     * for that: reset bit 0 in the 'flags' field of the registers definitions
+     * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
+     */
+    cc->gdb_num_core_regs = config->gdb_regmap.num_regs;
+}
+
 void xtensa_register_core(XtensaConfigList *node)
 {
+    TypeInfo type = {
+        .parent = TYPE_XTENSA_CPU,
+        .class_init = xtensa_core_class_init,
+        .class_data = (void *)node->config,
+    };
+
     node->next = xtensa_cores;
     xtensa_cores = node;
+    type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name);
+    type_register(&type);
+    g_free((gpointer)type.name);
 }
 
 static uint32_t check_hw_breakpoints(CPUXtensaState *env)
@@ -72,24 +97,17 @@ void xtensa_breakpoint_handler(CPUXtensaState *env)
 
 XtensaCPU *cpu_xtensa_init(const char *cpu_model)
 {
+    ObjectClass *oc;
     XtensaCPU *cpu;
     CPUXtensaState *env;
-    const XtensaConfig *config = NULL;
-    XtensaConfigList *core = xtensa_cores;
-
-    for (; core; core = core->next)
-        if (strcmp(core->config->name, cpu_model) == 0) {
-            config = core->config;
-            break;
-        }
 
-    if (config == NULL) {
+    oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model);
+    if (oc == NULL) {
         return NULL;
     }
 
-    cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
+    cpu = XTENSA_CPU(object_new(object_class_get_name(oc)));
     env = &cpu->env;
-    env->config = config;
 
     xtensa_irq_init(env);