]> git.proxmox.com Git - qemu.git/commitdiff
Merge remote-tracking branch 'afaerber/tags/qom-cpu-for-anthony' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Fri, 26 Jul 2013 22:53:19 +0000 (17:53 -0500)
committerAnthony Liguori <aliguori@us.ibm.com>
Fri, 26 Jul 2013 22:53:19 +0000 (17:53 -0500)
QOM CPUState refactorings

* Fix cpu_memory_rw_debug() breakage in s390x KVM
* Replace final CPUArchState in sysemu/kvm.h
* Introduce model subclasses for XtensaCPU
* Introduce CPUClass::gdb_num[_core]_regs
* Introduce CPUClass::gdb_core_xml_file
* Introduce CPUClass::gdb_{read,write}_register()
* Propagate CPUState further in gdbstub

# gpg: Signature made Fri 26 Jul 2013 05:04:28 PM CDT using RSA key ID 3E7E013F
# gpg: Can't check signature: public key not found

# By Andreas Färber (23) and others
# Via Andreas Färber
* afaerber/tags/qom-cpu-for-anthony: (25 commits)
  cpu: Introduce CPUClass::gdb_core_xml_file for GDB_CORE_XML
  target-cris: Factor out CPUClass::gdb_read_register() hook for v10
  cpu: Introduce CPUClass::gdb_{read,write}_register()
  gdbstub: Replace GET_REG*() macros with gdb_get_reg*() functions
  target-xtensa: Move cpu_gdb_{read,write}_register()
  target-lm32: Move cpu_gdb_{read,write}_register()
  target-s390x: Move cpu_gdb_{read,write}_register()
  target-alpha: Move cpu_gdb_{read,write}_register()
  target-cris: Move cpu_gdb_{read,write}_register()
  target-microblaze: Move cpu_gdb_{read,write}_register()
  target-sh4: Move cpu_gdb_{read,write}_register()
  target-openrisc: Move cpu_gdb_{read,write}_register()
  target-mips: Move cpu_gdb_{read,write}_register()
  target-m68k: Move cpu_gdb_{read,write}_register()
  target-arm: Move cpu_gdb_{read,write}_register()
  target-sparc: Move cpu_gdb_{read,write}_register()
  target-ppc: Move cpu_gdb_{read,write}_register()
  target-i386: Move cpu_gdb_{read,write}_register()
  cpu: Introduce CPUState::gdb_num_regs and CPUClass::gdb_num_core_regs
  gdbstub: Drop dead code in cpu_gdb_{read,write}_register()
  ...

70 files changed:
exec.c
gdbstub.c
include/exec/gdbstub.h
include/qom/cpu.h
include/sysemu/kvm.h
kvm-all.c
kvm-stub.c
linux-user/main.c
qom/cpu.c
stubs/Makefile.objs
stubs/gdbstub.c [new file with mode: 0644]
target-alpha/Makefile.objs
target-alpha/cpu-qom.h
target-alpha/cpu.c
target-alpha/gdbstub.c [new file with mode: 0644]
target-arm/Makefile.objs
target-arm/cpu-qom.h
target-arm/cpu.c
target-arm/gdbstub.c [new file with mode: 0644]
target-cris/Makefile.objs
target-cris/cpu-qom.h
target-cris/cpu.c
target-cris/gdbstub.c [new file with mode: 0644]
target-i386/Makefile.objs
target-i386/cpu-qom.h
target-i386/cpu.c
target-i386/gdbstub.c [new file with mode: 0644]
target-i386/kvm.c
target-lm32/Makefile.objs
target-lm32/cpu-qom.h
target-lm32/cpu.c
target-lm32/gdbstub.c [new file with mode: 0644]
target-m68k/Makefile.objs
target-m68k/cpu-qom.h
target-m68k/cpu.c
target-m68k/gdbstub.c [new file with mode: 0644]
target-microblaze/Makefile.objs
target-microblaze/cpu-qom.h
target-microblaze/cpu.c
target-microblaze/gdbstub.c [new file with mode: 0644]
target-mips/Makefile.objs
target-mips/cpu-qom.h
target-mips/cpu.c
target-mips/gdbstub.c [new file with mode: 0644]
target-openrisc/Makefile.objs
target-openrisc/cpu.c
target-openrisc/cpu.h
target-openrisc/gdbstub.c [new file with mode: 0644]
target-ppc/Makefile.objs
target-ppc/cpu-qom.h
target-ppc/gdbstub.c [new file with mode: 0644]
target-ppc/translate_init.c
target-s390x/Makefile.objs
target-s390x/cpu-qom.h
target-s390x/cpu.c
target-s390x/gdbstub.c [new file with mode: 0644]
target-s390x/kvm.c
target-sh4/Makefile.objs
target-sh4/cpu-qom.h
target-sh4/cpu.c
target-sh4/gdbstub.c [new file with mode: 0644]
target-sparc/Makefile.objs
target-sparc/cpu-qom.h
target-sparc/cpu.c
target-sparc/gdbstub.c [new file with mode: 0644]
target-xtensa/Makefile.objs
target-xtensa/cpu-qom.h
target-xtensa/cpu.c
target-xtensa/gdbstub.c [new file with mode: 0644]
target-xtensa/helper.c

diff --git a/exec.c b/exec.c
index 3ba9525bd345c0bccefc16f30d715d9d9c51a4b0..c4f2894ea12b40a356ea37ddbdf116ce491e8735 100644 (file)
--- 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);
         }
     }
index 35ca7c2c1e7d134cf18dab7af4d4ec78f242483e..1af25a6fe6332f89cdbe57b1a2b24e3f2961ff95 100644 (file)
--- 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;
index 7ea1ad7f9c23634e13436732459c89097cbc4ee8..a608a26c30e29fa57409cfe4bd6856c4f4a5145a 100644 (file)
@@ -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];
 
index daf1835c1a03f2d62ca474c1cf5c1188431cc3a5..0d6e95c0b6bc5672739759b5ea95e7f8b8a64843 100644 (file)
@@ -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;
index f8ac448e0bb27609f3daeaf40df89cbfcb4fa6d9..de74411f4123cf0d75bc2a11b99f7c3a2e9517e2 100644 (file)
@@ -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
index 4fb4ccbeca4f8196c6feb0528234e4f97e19c8b5..716860f6174552bc470e9a8a74dba72494bc0ce4 100644 (file)
--- 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;
 }
index 7b2233ae8229b6580166b829277621c40798c0e3..771360b3ca10d1eae5b551a0f192228643fd11b4 100644 (file)
@@ -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;
 }
index 5dc09471e4fe2b6669826cc6a08ba52ae7f09fc2..5309117034aba8de7007edbd6b2fd960bb868c38 100644 (file)
@@ -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;
 
index 5c45ab533338d411a2bd3d2bcc88a0c5f5200b8c..dbc9fb64891555fbcdd06c8231e8c112866dd2c0 100644 (file)
--- 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,
index 9b701b47140011769ef9b69b5b26c616b2309dc5..f306cbada3753632147aa94b7aad0df6626c60ff 100644 (file)
@@ -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 (file)
index 0000000..c1dbfe7
--- /dev/null
@@ -0,0 +1,5 @@
+#include "qemu-common.h"
+
+const char *const xml_builtin[][2] = {
+  { NULL, NULL }
+};
index 590304cc61b1e9dd5efff3bc155f4e6322477a92..b96c5da98d0872748001fd1b7379bfd4f8c78deb 100644 (file)
@@ -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
index b2eeba36f3c170a95b12d371a1290b493235e44f..2ebc9bcacbf9c27604532e4c9d95ecd083797034 100644 (file)
@@ -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
index c8c8c2c86158d37c0edf7ce0abc6c106ed1f348a..64c70bc1e9a883e40ee9ebeb75744031a118ed0b 100644 (file)
@@ -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 (file)
index 0000000..980f140
--- /dev/null
@@ -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;
+}
index 4a6e52e5282924cde87520124e998b638814c326..2d9f77fa9b425796f948ade7aec25d333e513cae 100644 (file)
@@ -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
index 02162c9aba57b6b3a3621e1988cc6d857e9e6213..cf3658714e361230ad63f0865f46c528b99ef8b3 100644 (file)
@@ -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
index d3906a4829a00d67f8b13618a7dd1e4b80b26064..87d35c6bf25cd035b5e49f218c4d0f8388ee8ddd 100644 (file)
@@ -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 (file)
index 0000000..1c34396
--- /dev/null
@@ -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;
+}
index afb87bcc80146f6e2d6976cb7de3202de8f30660..7779227fc4f1fd63c43d634fda60d1f8400273a3 100644 (file)
@@ -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
index d7baf0746ab1891ca8a61820cca1d3e525cecb71..75593667d629aa75bfe58ee9e3b6efe6436e5d72 100644 (file)
@@ -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
index ba095e75a5e4d629fa07636ab59776c4c13ccc6c..45f2d6bacf7c73cedf0b841cfd24dddb7c426aba 100644 (file)
@@ -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 (file)
index 0000000..5db3683
--- /dev/null
@@ -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;
+}
index c1d4f059da8cf7d3c87d4b23ca2365f43ba6c70b..3b629d4d39f47d73d8e5f9fb0afca7806b38e209 100644 (file)
@@ -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
index d928562c5333c95f2ca4b709f5cd4c9578594358..60d2b5d77274c6e177c8032f1767cc6e2203ae07 100644 (file)
@@ -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
index cd350cb8e44693367e06abf97e9f56d11aaa29fd..2b59b7d7ef381e0fe1fe3523ab7c382974433098 100644 (file)
@@ -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 (file)
index 0000000..15bebef
--- /dev/null
@@ -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;
+}
index 3c9d10a76249b56ad1e39a3631cb4cdbd5df27ef..376fc70ae39141b2302693ed04b837bb9544ab97 100644 (file)
@@ -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;
 }
index ca20f21443b4f0aa7d1db362b265a13d74d3c2c5..40236876c8d83df7bb30efdaec1dfb405e938a8c 100644 (file)
@@ -1,2 +1,3 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += machine.o
index 9e2732919d54bf9040e134d82b0178f12b6fcb10..723f6049c3a43be80935de7d6481fd073389ac5e 100644 (file)
@@ -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
index ce55e4807d8e846374f1bef9a43374e1df0cdc49..962d553de0ade5337a655a24313a09f65608f1f4 100644 (file)
@@ -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 (file)
index 0000000..4979a98
--- /dev/null
@@ -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;
+}
index 2e2b85044d9c6cfdb988fc150f3648830a8e71a4..02cf616a788db2f3e88e96e04928048250375f80 100644 (file)
@@ -1,2 +1,3 @@
 obj-y += m68k-semi.o
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
index 7115707e91564c2a87e6f680aa881aea9a29f309..7f388eda6808496ef50eb840e00ca93b30adeb31 100644 (file)
@@ -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
index 988f4762573e72ec75d00d53d1ccce6cd48186dc..c0bcb0dbce06020db0f5d21ff6e6d6d31ddee083 100644 (file)
@@ -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 (file)
index 0000000..ae8179c
--- /dev/null
@@ -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;
+}
index 985330eac5bbd2f1b355325a166c0ea1e03552c3..f3d7b44c890e5c27fb0b7078af936ec515a988f5 100644 (file)
@@ -1,2 +1,3 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += mmu.o
index 1318a36676a8c4b440f463ead33001646ad91161..35a12b42a584a61325d2a2bed4b368c97f985707 100644 (file)
@@ -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
index 9f10c8c778d2eab3db8f4451c6bad440d94f1663..c75d1bd64268d1de6ad68d64f9281ffdf3a329e0 100644 (file)
@@ -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 (file)
index 0000000..a70e2ee
--- /dev/null
@@ -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;
+}
index 119c816518efc7e4f8b7ef6b2e19ce84fd44e8c9..0277d56e8252fedae448da4d8b806e43c0ab87bb 100644 (file)
@@ -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
index 7c8e6163920ddcd963d222ebb1d2982b9f916383..8877f813f7b5c25cdcd596554e5552efdb0f3e63 100644 (file)
@@ -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
index 4834c86d021048afc343c6cb1ef3a321eb15ca60..f81f9e9409462d4e5c722a738a49997ff71e3fc7 100644 (file)
@@ -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 (file)
index 0000000..5b72d58
--- /dev/null
@@ -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);
+}
index 44dc5399dfd8363618a1459eb9eb669123b90235..397d01650e838f61a74ff86ce40aaa1feaee2e27 100644 (file)
@@ -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
index 7718820eccb09d95ebe8e7778b8370603f667ee9..aa269fb7a6b01a0502c0fd3791abb157f95a9e21 100644 (file)
@@ -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)
index 3ddb7674c7a1d05c237d1d55d7296757fea61c6f..8fd0bc0bf01096c68be599f3a551e0806fcd52fb 100644 (file)
@@ -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 (file)
index 0000000..18bcc46
--- /dev/null
@@ -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;
+}
index 6e78cb3624392165910ed6e49ecdf6cef71cd691..f72e3993f7f118fc85ced5b1fb32d252d33300b8 100644 (file)
@@ -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
index 3341c5151db900fc27767eeaf8c23d8d5b9033e3..fc0d73788071da5e143c252d22fb26f488469725 100644 (file)
@@ -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 (file)
index 0000000..1c91090
--- /dev/null
@@ -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;
+}
index 0b0844f467508c8f4f737f03b380d85add594843..8215946e397a2a3a28b65611605ffd681ba84b11 100644 (file)
@@ -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 = {
index 4e634173a4f2be12c8962cf5029936ccce5ff37b..ab938e7ad874f53965d59c99834711205f828e9d 100644 (file)
@@ -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
index a4fe8fb5fc183b5d78dfe73a31ba26d7fb589ef1..0d63b1cf20d7d60505122bfd5afae962c906fc0a 100644 (file)
@@ -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
index cb89d1a46b3fdd53f5a01d17ea840eeaccbd112a..1d16da3787d2c04931d545231c033604972cfa30 100644 (file)
@@ -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 (file)
index 0000000..a129742
--- /dev/null
@@ -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;
+}
index 60e94f8ee8f6ceeb567a7fcf7ad6b9923515a308..85f01125de443f0510f6d3950a560c30ef180045 100644 (file)
@@ -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;
     }
 
index cb448a840fc28d9f91c576285d78d38593d806d3..a285358adf972309b4921397a74e1751671f93b1 100644 (file)
@@ -1 +1,2 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
index 7c9160bab8303d3b12d193eaf9b9e3adb0b6fd0e..c04e78631b3048121bc6c274233e11f7357b0320 100644 (file)
@@ -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
index 51a77576fbfc08b7c02850bebd076bf531cb303e..bda3c5112c9c0d8b0ef7c4a8ff611498e46fcd6c 100644 (file)
@@ -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 (file)
index 0000000..df4fa2a
--- /dev/null
@@ -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;
+}
index 9fc42ea9b023a2c1676282854157a039c934e882..1cd81cccc33d026479c7aeac0d788e82c16714f7 100644 (file)
@@ -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
index 39d975b5fce59677e5afb94dac52f1349ab7f237..8e3e0de27707570484a0c045cc58978d46b4fde5 100644 (file)
@@ -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
index d1d03396efdd91b200fdb5ff3074473915d8b6ec..c7b4a90663713d0a8d83fbfb1f6681983c61a7bb 100644 (file)
@@ -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 (file)
index 0000000..3de3242
--- /dev/null
@@ -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
+}
index 644b7f99bbce47a80dab5a86060cee77a559e508..5c150a870fe94d9817239183835aabda84909231 100644 (file)
@@ -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
index b9896f2647098f47139a3164b471f83dd903bbec..c6cc2d91f46fd3d96eb890f13374e8bd6434ae5e 100644 (file)
@@ -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
index d2bcfc69a239cb931cfa5d449545b1b072105264..e966aa0a793a70b22d1a42f03c12cfd88d516ab2 100644 (file)
@@ -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 (file)
index 0000000..9e13b20
--- /dev/null
@@ -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;
+}
index de6cc3b7c57fa83eae173cc52640dc6400c8613e..a0f9993b2d1aeb09993d3def5d2bb9da0bae5f62 100644 (file)
 
 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);