[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH RFC qom-cpu 41/41] cpu: Introduce CPUClass::gdb_{read,
From: |
Andreas Färber |
Subject: |
[Qemu-ppc] [PATCH RFC qom-cpu 41/41] cpu: Introduce CPUClass::gdb_{read, write}_register() |
Date: |
Sat, 29 Jun 2013 22:01:57 +0200 |
Replace GET_REG*() macros by gdb_get_reg*() inline functions for
clarity and drop breaks after return.
Allows to move target-specific code to new target-*/gdbstub.c files.
Signed-off-by: Andreas Färber <address@hidden>
---
gdbstub.c | 1274 +--------------------------------------
include/exec/gdbstub.h | 39 ++
include/qom/cpu.h | 4 +
qom/cpu.c | 13 +
target-alpha/Makefile.objs | 1 +
target-alpha/cpu-qom.h | 2 +
target-alpha/cpu.c | 2 +
target-alpha/gdbstub.c | 93 +++
target-arm/Makefile.objs | 1 +
target-arm/cpu-qom.h | 3 +
target-arm/cpu.c | 2 +
target-arm/gdbstub.c | 102 ++++
target-cris/Makefile.objs | 1 +
target-cris/cpu-qom.h | 4 +
target-cris/cpu.c | 6 +
target-cris/gdbstub.c | 130 ++++
target-i386/Makefile.objs | 1 +
target-i386/cpu-qom.h | 3 +
target-i386/cpu.c | 2 +
target-i386/gdbstub.c | 231 +++++++
target-lm32/Makefile.objs | 1 +
target-lm32/cpu-qom.h | 2 +
target-lm32/cpu.c | 2 +
target-lm32/gdbstub.c | 92 +++
target-m68k/Makefile.objs | 1 +
target-m68k/cpu-qom.h | 2 +
target-m68k/cpu.c | 2 +
target-m68k/gdbstub.c | 75 +++
target-microblaze/Makefile.objs | 1 +
target-microblaze/cpu-qom.h | 2 +
target-microblaze/cpu.c | 2 +
target-microblaze/gdbstub.c | 56 ++
target-mips/Makefile.objs | 1 +
target-mips/cpu-qom.h | 2 +
target-mips/cpu.c | 2 +
target-mips/gdbstub.c | 154 +++++
target-openrisc/Makefile.objs | 1 +
target-openrisc/cpu.c | 2 +
target-openrisc/cpu.h | 2 +
target-openrisc/gdbstub.c | 86 +++
target-ppc/Makefile.objs | 1 +
target-ppc/cpu-qom.h | 2 +
target-ppc/gdbstub.c | 131 ++++
target-ppc/translate_init.c | 2 +
target-s390x/Makefile.objs | 1 +
target-s390x/cpu-qom.h | 2 +
target-s390x/cpu.c | 2 +
target-s390x/gdbstub.c | 88 +++
target-sh4/Makefile.objs | 1 +
target-sh4/cpu-qom.h | 2 +
target-sh4/cpu.c | 2 +
target-sh4/gdbstub.c | 146 +++++
target-sparc/Makefile.objs | 1 +
target-sparc/cpu-qom.h | 2 +
target-sparc/cpu.c | 2 +
target-sparc/gdbstub.c | 208 +++++++
target-xtensa/Makefile.objs | 1 +
target-xtensa/cpu-qom.h | 2 +
target-xtensa/cpu.c | 2 +
target-xtensa/gdbstub.c | 111 ++++
60 files changed, 1844 insertions(+), 1267 deletions(-)
create mode 100644 target-alpha/gdbstub.c
create mode 100644 target-arm/gdbstub.c
create mode 100644 target-cris/gdbstub.c
create mode 100644 target-i386/gdbstub.c
create mode 100644 target-lm32/gdbstub.c
create mode 100644 target-m68k/gdbstub.c
create mode 100644 target-microblaze/gdbstub.c
create mode 100644 target-mips/gdbstub.c
create mode 100644 target-openrisc/gdbstub.c
create mode 100644 target-ppc/gdbstub.c
create mode 100644 target-s390x/gdbstub.c
create mode 100644 target-sh4/gdbstub.c
create mode 100644 target-sparc/gdbstub.c
create mode 100644 target-xtensa/gdbstub.c
diff --git a/gdbstub.c b/gdbstub.c
index 1a827c2..a9a0770 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -40,7 +40,6 @@
#include "cpu.h"
#include "qemu/sockets.h"
#include "sysemu/kvm.h"
-#include "qemu/bitops.h"
static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
uint8_t *buf, int len, bool is_write)
@@ -319,7 +318,7 @@ 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,1281 +488,22 @@ 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 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)
+#if defined(TARGET_PPC)
-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. */
#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)
-
-#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 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 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)
-
-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)
-
-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)
-{
- CPUClass *cc = CPU_GET_CLASS(openrisc_env_get_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;
-}
-#elif defined (TARGET_SH4)
-
-/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
-/* FIXME: We should use XML for this. */
-
-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)
-
-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)
-{
- CPUClass *cc = CPU_GET_CLASS(mb_env_get_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;
-}
-#elif defined (TARGET_CRIS)
-
-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)
-
-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)
-
-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"
-
-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)
-{
- CPUClass *cc = CPU_GET_CLASS(lm32_env_get_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;
-}
-#elif defined(TARGET_XTENSA)
-
-static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
-{
- XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
- const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
-
- if (n < 0 || n >= xcc->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) % xcc->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)
-{
- XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
- uint32_t tmp;
- const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
-
- if (n < 0 || n >= xcc->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) % xcc->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
-
-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
#ifdef GDB_CORE_XML
@@ -1839,7 +579,7 @@ static int gdb_read_register(CPUState *cpu, uint8_t
*mem_buf, int reg)
GDBRegisterState *r;
if (reg < cc->gdb_num_core_regs) {
- return cpu_gdb_read_register(env, mem_buf, reg);
+ return cc->gdb_read_register(cpu, mem_buf, reg);
}
for (r = cpu->gdb_regs; r; r = r->next) {
@@ -1857,7 +597,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t
*mem_buf, int reg)
GDBRegisterState *r;
if (reg < cc->gdb_num_core_regs) {
- return cpu_gdb_write_register(env, mem_buf, reg);
+ return cc->gdb_write_register(cpu, mem_buf, reg);
}
for (r = cpu->gdb_regs; r; r = r->next) {
@@ -2398,7 +1138,7 @@ static int gdb_handle_packet(GDBState *s, const char
*line_buf)
const char *xml;
target_ulong total_len;
- gdb_has_xml = 1;
+ gdb_has_xml = true;
p += 19;
xml = get_feature_xml(p, &p);
if (!xml) {
@@ -2807,7 +1547,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;
@@ -2893,7 +1633,7 @@ static void gdb_chr_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_OPENED:
vm_stop(RUN_STATE_PAUSED);
- gdb_has_xml = 0;
+ gdb_has_xml = false;
break;
default:
break;
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 1bd00ae..4d580f0 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -39,6 +39,43 @@ static inline int cpu_index(CPUState *cpu)
#endif
}
+/* The GDB remote protocol transfers values in target byte order. This means
+ * we can use the raw memory access routines to access the value buffer.
+ * Conveniently, these also handle the case where the buffer is mis-aligned.
+ */
+
+static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
+{
+ stb_p(mem_buf, val);
+ return 1;
+}
+
+static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
+{
+ stw_p(mem_buf, val);
+ return 2;
+}
+
+static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
+{
+ stl_p(mem_buf, val);
+ return 4;
+}
+
+static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
+{
+ stq_p(mem_buf, val);
+ return 8;
+}
+
+#if TARGET_LONG_BITS == 64
+#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
+#define ldtul_p(addr) ldq_p(addr)
+#else
+#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val)
+#define ldtul_p(addr) ldl_p(addr)
+#endif
+
#endif
#ifdef CONFIG_USER_ONLY
@@ -47,6 +84,8 @@ int gdbserver_start(int);
int gdbserver_start(const char *port);
#endif
+extern bool gdb_has_xml;
+
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2];
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index f89c49e..a422815 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -62,6 +62,8 @@ typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr
addr,
* @get_paging_enabled: Callback for inquiring whether paging is enabled.
* @get_memory_mapping: Callback for obtaining the memory mappings.
* @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.
*
* Represents a CPU family or model.
@@ -90,6 +92,8 @@ typedef struct CPUClass {
void (*set_pc)(CPUState *cpu, uint64_t value);
void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
hwaddr (*get_phys_page_debug)(CPUState *cpu, uint64_t 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,
diff --git a/qom/cpu.c b/qom/cpu.c
index 2839ddf..dbc9fb6 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -157,6 +157,17 @@ static int
cpu_common_write_elf64_note(WriteCoreDumpFunction f,
}
+static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
+{
+ return 0;
+}
+
+static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
+{
+ return 0;
+}
+
+
void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags)
{
@@ -253,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;
}
diff --git a/target-alpha/Makefile.objs b/target-alpha/Makefile.objs
index 590304c..b96c5da 100644
--- a/target-alpha/Makefile.objs
+++ b/target-alpha/Makefile.objs
@@ -1,3 +1,4 @@
obj-$(CONFIG_SOFTMMU) += machine.o
obj-y += translate.o helper.o cpu.o
obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
+obj-y += gdbstub.o
diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h
index 50cccca..8922207 100644
--- a/target-alpha/cpu-qom.h
+++ b/target-alpha/cpu-qom.h
@@ -82,5 +82,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags);
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c
index 028cec1..14dadae 100644
--- a/target-alpha/cpu.c
+++ b/target-alpha/cpu.c
@@ -271,6 +271,8 @@ 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;
diff --git a/target-alpha/gdbstub.c b/target-alpha/gdbstub.c
new file mode 100644
index 0000000..980f140
--- /dev/null
+++ b/target-alpha/gdbstub.c
@@ -0,0 +1,93 @@
+/*
+ * Alpha gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ AlphaCPU *cpu = ALPHA_CPU(cs);
+ CPUAlphaState *env = &cpu->env;
+ uint64_t val;
+ CPU_DoubleU d;
+
+ switch (n) {
+ case 0 ... 30:
+ val = env->ir[n];
+ break;
+ case 32 ... 62:
+ d.d = env->fir[n - 32];
+ val = d.ll;
+ break;
+ case 63:
+ val = cpu_alpha_load_fpcr(env);
+ break;
+ case 64:
+ val = env->pc;
+ break;
+ case 66:
+ val = env->unique;
+ break;
+ case 31:
+ case 65:
+ /* 31 really is the zero register; 65 is unassigned in the
+ gdb protocol, but is still required to occupy 8 bytes. */
+ val = 0;
+ break;
+ default:
+ return 0;
+ }
+ return gdb_get_regl(mem_buf, val);
+}
+
+int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ AlphaCPU *cpu = ALPHA_CPU(cs);
+ CPUAlphaState *env = &cpu->env;
+ target_ulong tmp = ldtul_p(mem_buf);
+ CPU_DoubleU d;
+
+ switch (n) {
+ case 0 ... 30:
+ env->ir[n] = tmp;
+ break;
+ case 32 ... 62:
+ d.ll = tmp;
+ env->fir[n - 32] = d.d;
+ break;
+ case 63:
+ cpu_alpha_store_fpcr(env, tmp);
+ break;
+ case 64:
+ env->pc = tmp;
+ break;
+ case 66:
+ env->unique = tmp;
+ break;
+ case 31:
+ case 65:
+ /* 31 really is the zero register; 65 is unassigned in the
+ gdb protocol, but is still required to occupy 8 bytes. */
+ break;
+ default:
+ return 0;
+ }
+ return 8;
+}
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index 4a6e52e..2d9f77f 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -4,3 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o
+obj-y += gdbstub.o
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index c6d54c2..f542531 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -149,4 +149,7 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf,
hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
#endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index e04bcc3..44290fa 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -819,6 +819,8 @@ 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;
diff --git a/target-arm/gdbstub.c b/target-arm/gdbstub.c
new file mode 100644
index 0000000..1c34396
--- /dev/null
+++ b/target-arm/gdbstub.c
@@ -0,0 +1,102 @@
+/*
+ * ARM gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
+ whatever the target description contains. Due to a historical mishap
+ the FPA registers appear in between core integer regs and the CPSR.
+ We hack round this by giving the FPA regs zero size when talking to a
+ newer gdb. */
+
+int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ if (n < 16) {
+ /* Core integer register. */
+ return gdb_get_reg32(mem_buf, env->regs[n]);
+ }
+ if (n < 24) {
+ /* FPA registers. */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ memset(mem_buf, 0, 12);
+ return 12;
+ }
+ switch (n) {
+ case 24:
+ /* FPA status register. */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ return gdb_get_reg32(mem_buf, 0);
+ case 25:
+ /* CPSR */
+ return gdb_get_reg32(mem_buf, cpsr_read(env));
+ }
+ /* Unknown register. */
+ return 0;
+}
+
+int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint32_t tmp;
+
+ tmp = ldl_p(mem_buf);
+
+ /* Mask out low bit of PC to workaround gdb bugs. This will probably
+ cause problems if we ever implement the Jazelle DBX extensions. */
+ if (n == 15) {
+ tmp &= ~1;
+ }
+
+ if (n < 16) {
+ /* Core integer register. */
+ env->regs[n] = tmp;
+ return 4;
+ }
+ if (n < 24) { /* 16-23 */
+ /* FPA registers (ignored). */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ return 12;
+ }
+ switch (n) {
+ case 24:
+ /* FPA status register (ignored). */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ return 4;
+ case 25:
+ /* CPSR */
+ cpsr_write(env, tmp, 0xffffffff);
+ return 4;
+ }
+ /* Unknown register. */
+ return 0;
+}
diff --git a/target-cris/Makefile.objs b/target-cris/Makefile.objs
index afb87bc..7779227 100644
--- a/target-cris/Makefile.objs
+++ b/target-cris/Makefile.objs
@@ -1,2 +1,3 @@
obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += mmu.o machine.o
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
index cd19070..b81a708 100644
--- a/target-cris/cpu-qom.h
+++ b/target-cris/cpu-qom.h
@@ -81,4 +81,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf,
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
#endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 426a321..dd67f14 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -175,6 +175,7 @@ static void crisv8_cpu_class_init(ObjectClass *oc, void
*data)
ccc->vr = 8;
cc->do_interrupt = crisv10_cpu_do_interrupt;
+ cc->gdb_read_register = crisv10_cpu_gdb_read_register;
}
static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
@@ -184,6 +185,7 @@ static void crisv9_cpu_class_init(ObjectClass *oc, void
*data)
ccc->vr = 9;
cc->do_interrupt = crisv10_cpu_do_interrupt;
+ cc->gdb_read_register = crisv10_cpu_gdb_read_register;
}
static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
@@ -193,6 +195,7 @@ static void crisv10_cpu_class_init(ObjectClass *oc, void
*data)
ccc->vr = 10;
cc->do_interrupt = crisv10_cpu_do_interrupt;
+ cc->gdb_read_register = crisv10_cpu_gdb_read_register;
}
static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
@@ -202,6 +205,7 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void
*data)
ccc->vr = 11;
cc->do_interrupt = crisv10_cpu_do_interrupt;
+ cc->gdb_read_register = crisv10_cpu_gdb_read_register;
}
static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
@@ -255,6 +259,8 @@ 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
diff --git a/target-cris/gdbstub.c b/target-cris/gdbstub.c
new file mode 100644
index 0000000..55ec994
--- /dev/null
+++ b/target-cris/gdbstub.c
@@ -0,0 +1,130 @@
+/*
+ * CRIS gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ CRISCPU *cpu = CRIS_CPU(cs);
+ CPUCRISState *env = &cpu->env;
+
+ if (n < 15) {
+ return gdb_get_reg32(mem_buf, env->regs[n]);
+ }
+
+ if (n == 15) {
+ return gdb_get_reg32(mem_buf, env->pc);
+ }
+
+ if (n < 32) {
+ switch (n) {
+ case 16:
+ 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]);
+ break;
+ default:
+ if (n >= 23) {
+ return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ CRISCPU *cpu = CRIS_CPU(cs);
+ CPUCRISState *env = &cpu->env;
+ uint8_t srs;
+
+ srs = env->pregs[PR_SRS];
+ if (n < 16) {
+ return gdb_get_reg32(mem_buf, env->regs[n]);
+ }
+
+ if (n >= 21 && n < 32) {
+ return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
+ }
+ if (n >= 33 && n < 49) {
+ return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]);
+ }
+ switch (n) {
+ case 16:
+ return gdb_get_reg8(mem_buf, env->pregs[0]);
+ case 17:
+ return gdb_get_reg8(mem_buf, env->pregs[1]);
+ case 18:
+ return gdb_get_reg32(mem_buf, env->pregs[2]);
+ case 19:
+ return gdb_get_reg8(mem_buf, srs);
+ case 20:
+ return gdb_get_reg16(mem_buf, env->pregs[4]);
+ case 32:
+ return gdb_get_reg32(mem_buf, env->pc);
+ }
+
+ return 0;
+}
+
+int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ CRISCPU *cpu = CRIS_CPU(cs);
+ CPUCRISState *env = &cpu->env;
+ uint32_t tmp;
+
+ if (n > 49) {
+ return 0;
+ }
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 16) {
+ env->regs[n] = tmp;
+ }
+
+ if (n >= 21 && n < 32) {
+ env->pregs[n - 16] = tmp;
+ }
+
+ /* FIXME: Should support function regs be writable? */
+ switch (n) {
+ case 16:
+ return 1;
+ case 17:
+ return 1;
+ case 18:
+ env->pregs[PR_PID] = tmp;
+ break;
+ case 19:
+ return 1;
+ case 20:
+ return 2;
+ case 32:
+ env->pc = tmp;
+ break;
+ }
+
+ return 4;
+}
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index c1d4f05..3b629d4d 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -1,6 +1,7 @@
obj-y += translate.o helper.o cpu.o
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
+obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index b762d06..59f04b2 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -106,4 +106,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf,
hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
#endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 7c6f1d3..549b058 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2538,6 +2538,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc,
void *data)
cc->dump_state = x86_cpu_dump_state;
cc->set_pc = x86_cpu_set_pc;
cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
+ cc->gdb_read_register = x86_cpu_gdb_read_register;
+ cc->gdb_write_register = x86_cpu_gdb_write_register;
cc->get_arch_id = x86_cpu_get_arch_id;
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
#ifndef CONFIG_USER_ONLY
diff --git a/target-i386/gdbstub.c b/target-i386/gdbstub.c
new file mode 100644
index 0000000..a76cf6d
--- /dev/null
+++ b/target-i386/gdbstub.c
@@ -0,0 +1,231 @@
+/*
+ * x86 gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+#ifdef TARGET_X86_64
+static const int gpr_map[16] = {
+ R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
+ 8, 9, 10, 11, 12, 13, 14, 15
+};
+#else
+#define gpr_map gpr_map32
+#endif
+static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+#define IDX_IP_REG CPU_NB_REGS
+#define IDX_FLAGS_REG (IDX_IP_REG + 1)
+#define IDX_SEG_REGS (IDX_FLAGS_REG + 1)
+#define IDX_FP_REGS (IDX_SEG_REGS + 6)
+#define IDX_XMM_REGS (IDX_FP_REGS + 16)
+#define IDX_MXCSR_REG (IDX_XMM_REGS + CPU_NB_REGS)
+
+int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ if (n < CPU_NB_REGS) {
+ if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+ return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]);
+ } else if (n < CPU_NB_REGS32) {
+ return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
+ }
+ } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
+#ifdef USE_X86LDOUBLE
+ /* FIXME: byteswap float values - after fixing fpregs layout. */
+ memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
+#else
+ memset(mem_buf, 0, 10);
+#endif
+ return 10;
+ } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
+ n -= IDX_XMM_REGS;
+ if (n < CPU_NB_REGS32 ||
+ (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
+ stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
+ stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1));
+ return 16;
+ }
+ } else {
+ switch (n) {
+ case IDX_IP_REG:
+ if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+ return gdb_get_reg64(mem_buf, env->eip);
+ } else {
+ return gdb_get_reg32(mem_buf, env->eip);
+ }
+ case IDX_FLAGS_REG:
+ return gdb_get_reg32(mem_buf, env->eflags);
+
+ case IDX_SEG_REGS:
+ return gdb_get_reg32(mem_buf, env->segs[R_CS].selector);
+ case IDX_SEG_REGS + 1:
+ return gdb_get_reg32(mem_buf, env->segs[R_SS].selector);
+ case IDX_SEG_REGS + 2:
+ return gdb_get_reg32(mem_buf, env->segs[R_DS].selector);
+ case IDX_SEG_REGS + 3:
+ return gdb_get_reg32(mem_buf, env->segs[R_ES].selector);
+ case IDX_SEG_REGS + 4:
+ return gdb_get_reg32(mem_buf, env->segs[R_FS].selector);
+ case IDX_SEG_REGS + 5:
+ return gdb_get_reg32(mem_buf, env->segs[R_GS].selector);
+
+ case IDX_FP_REGS + 8:
+ return gdb_get_reg32(mem_buf, env->fpuc);
+ case IDX_FP_REGS + 9:
+ return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) |
+ (env->fpstt & 0x7) << 11);
+ case IDX_FP_REGS + 10:
+ return gdb_get_reg32(mem_buf, 0); /* ftag */
+ case IDX_FP_REGS + 11:
+ return gdb_get_reg32(mem_buf, 0); /* fiseg */
+ case IDX_FP_REGS + 12:
+ return gdb_get_reg32(mem_buf, 0); /* fioff */
+ case IDX_FP_REGS + 13:
+ return gdb_get_reg32(mem_buf, 0); /* foseg */
+ case IDX_FP_REGS + 14:
+ return gdb_get_reg32(mem_buf, 0); /* fooff */
+ case IDX_FP_REGS + 15:
+ return gdb_get_reg32(mem_buf, 0); /* fop */
+
+ case IDX_MXCSR_REG:
+ return gdb_get_reg32(mem_buf, env->mxcsr);
+ }
+ }
+ return 0;
+}
+
+static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf)
+{
+ CPUX86State *env = &cpu->env;
+ uint16_t selector = ldl_p(mem_buf);
+
+ if (selector != env->segs[sreg].selector) {
+#if defined(CONFIG_USER_ONLY)
+ cpu_x86_load_seg(env, sreg, selector);
+#else
+ unsigned int limit, flags;
+ target_ulong base;
+
+ if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+ base = selector << 4;
+ limit = 0xffff;
+ flags = 0;
+ } else {
+ if (!cpu_x86_get_descr_debug(env, selector, &base, &limit,
+ &flags)) {
+ return 4;
+ }
+ }
+ cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags);
+#endif
+ }
+ return 4;
+}
+
+int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ uint32_t tmp;
+
+ if (n < CPU_NB_REGS) {
+ if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+ env->regs[gpr_map[n]] = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ } else if (n < CPU_NB_REGS32) {
+ n = gpr_map32[n];
+ env->regs[n] &= ~0xffffffffUL;
+ env->regs[n] |= (uint32_t)ldl_p(mem_buf);
+ return 4;
+ }
+ } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
+#ifdef USE_X86LDOUBLE
+ /* FIXME: byteswap float values - after fixing fpregs layout. */
+ memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
+#endif
+ return 10;
+ } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
+ n -= IDX_XMM_REGS;
+ if (n < CPU_NB_REGS32 ||
+ (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
+ env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf);
+ env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8);
+ return 16;
+ }
+ } else {
+ switch (n) {
+ case IDX_IP_REG:
+ if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
+ env->eip = ldq_p(mem_buf);
+ return 8;
+ } else {
+ env->eip &= ~0xffffffffUL;
+ env->eip |= (uint32_t)ldl_p(mem_buf);
+ return 4;
+ }
+ case IDX_FLAGS_REG:
+ env->eflags = ldl_p(mem_buf);
+ return 4;
+
+ case IDX_SEG_REGS:
+ return x86_cpu_gdb_load_seg(cpu, R_CS, mem_buf);
+ case IDX_SEG_REGS + 1:
+ return x86_cpu_gdb_load_seg(cpu, R_SS, mem_buf);
+ case IDX_SEG_REGS + 2:
+ return x86_cpu_gdb_load_seg(cpu, R_DS, mem_buf);
+ case IDX_SEG_REGS + 3:
+ return x86_cpu_gdb_load_seg(cpu, R_ES, mem_buf);
+ case IDX_SEG_REGS + 4:
+ return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf);
+ case IDX_SEG_REGS + 5:
+ return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf);
+
+ case IDX_FP_REGS + 8:
+ env->fpuc = ldl_p(mem_buf);
+ return 4;
+ case IDX_FP_REGS + 9:
+ tmp = ldl_p(mem_buf);
+ env->fpstt = (tmp >> 11) & 7;
+ env->fpus = tmp & ~0x3800;
+ return 4;
+ case IDX_FP_REGS + 10: /* ftag */
+ return 4;
+ case IDX_FP_REGS + 11: /* fiseg */
+ return 4;
+ case IDX_FP_REGS + 12: /* fioff */
+ return 4;
+ case IDX_FP_REGS + 13: /* foseg */
+ return 4;
+ case IDX_FP_REGS + 14: /* fooff */
+ return 4;
+ case IDX_FP_REGS + 15: /* fop */
+ return 4;
+
+ case IDX_MXCSR_REG:
+ env->mxcsr = ldl_p(mem_buf);
+ return 4;
+ }
+ }
+ /* Unrecognised register. */
+ return 0;
+}
diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs
index ca20f21..4023687 100644
--- a/target-lm32/Makefile.objs
+++ b/target-lm32/Makefile.objs
@@ -1,2 +1,3 @@
obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h
index 5c4810f..b568cf9 100644
--- a/target-lm32/cpu-qom.h
+++ b/target-lm32/cpu-qom.h
@@ -79,5 +79,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index ec5f0e0..ea13dc6 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -87,6 +87,8 @@ 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;
diff --git a/target-lm32/gdbstub.c b/target-lm32/gdbstub.c
new file mode 100644
index 0000000..4979a98
--- /dev/null
+++ b/target-lm32/gdbstub.c
@@ -0,0 +1,92 @@
+/*
+ * LM32 gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "hw/lm32/lm32_pic.h"
+
+int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ LM32CPU *cpu = LM32_CPU(cs);
+ CPULM32State *env = &cpu->env;
+
+ if (n < 32) {
+ return gdb_get_reg32(mem_buf, env->regs[n]);
+ } else {
+ switch (n) {
+ case 32:
+ return gdb_get_reg32(mem_buf, env->pc);
+ /* FIXME: put in right exception ID */
+ case 33:
+ return gdb_get_reg32(mem_buf, 0);
+ case 34:
+ return gdb_get_reg32(mem_buf, env->eba);
+ case 35:
+ return gdb_get_reg32(mem_buf, env->deba);
+ case 36:
+ return gdb_get_reg32(mem_buf, env->ie);
+ case 37:
+ return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state));
+ case 38:
+ return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state));
+ }
+ }
+ return 0;
+}
+
+int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ LM32CPU *cpu = LM32_CPU(cs);
+ CPUClass *cc = CPU_GET_CLASS(cs);
+ CPULM32State *env = &cpu->env;
+ uint32_t tmp;
+
+ if (n > cc->gdb_num_core_regs) {
+ return 0;
+ }
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 32) {
+ env->regs[n] = tmp;
+ } else {
+ switch (n) {
+ case 32:
+ env->pc = tmp;
+ break;
+ case 34:
+ env->eba = tmp;
+ break;
+ case 35:
+ env->deba = tmp;
+ break;
+ case 36:
+ env->ie = tmp;
+ break;
+ case 37:
+ lm32_pic_set_im(env->pic_state, tmp);
+ break;
+ case 38:
+ lm32_pic_set_ip(env->pic_state, tmp);
+ break;
+ }
+ }
+ return 4;
+}
diff --git a/target-m68k/Makefile.objs b/target-m68k/Makefile.objs
index 2e2b850..02cf616 100644
--- a/target-m68k/Makefile.objs
+++ b/target-m68k/Makefile.objs
@@ -1,2 +1,3 @@
obj-y += m68k-semi.o
obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h
index 9ec8c35..0afd23f 100644
--- a/target-m68k/cpu-qom.h
+++ b/target-m68k/cpu-qom.h
@@ -74,5 +74,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c
index 35c203c..b59a4fd 100644
--- a/target-m68k/cpu.c
+++ b/target-m68k/cpu.c
@@ -190,6 +190,8 @@ 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
diff --git a/target-m68k/gdbstub.c b/target-m68k/gdbstub.c
new file mode 100644
index 0000000..ae8179c
--- /dev/null
+++ b/target-m68k/gdbstub.c
@@ -0,0 +1,75 @@
+/*
+ * m68k gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+
+ if (n < 8) {
+ /* D0-D7 */
+ return gdb_get_reg32(mem_buf, env->dregs[n]);
+ } else if (n < 16) {
+ /* A0-A7 */
+ return gdb_get_reg32(mem_buf, env->aregs[n - 8]);
+ } else {
+ switch (n) {
+ case 16:
+ return gdb_get_reg32(mem_buf, env->sr);
+ case 17:
+ return gdb_get_reg32(mem_buf, env->pc);
+ }
+ }
+ /* FP registers not included here because they vary between
+ ColdFire and m68k. Use XML bits for these. */
+ return 0;
+}
+
+int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+ uint32_t tmp;
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 8) {
+ /* D0-D7 */
+ env->dregs[n] = tmp;
+ } else if (n < 16) {
+ /* A0-A7 */
+ env->aregs[n - 8] = tmp;
+ } else {
+ switch (n) {
+ case 16:
+ env->sr = tmp;
+ break;
+ case 17:
+ env->pc = tmp;
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 4;
+}
diff --git a/target-microblaze/Makefile.objs b/target-microblaze/Makefile.objs
index 985330e..f3d7b44 100644
--- a/target-microblaze/Makefile.objs
+++ b/target-microblaze/Makefile.objs
@@ -1,2 +1,3 @@
obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += mmu.o
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
index be05858..1ee576a 100644
--- a/target-microblaze/cpu-qom.h
+++ b/target-microblaze/cpu-qom.h
@@ -75,5 +75,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index f2e538a..72bd4dc 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -141,6 +141,8 @@ 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;
diff --git a/target-microblaze/gdbstub.c b/target-microblaze/gdbstub.c
new file mode 100644
index 0000000..a70e2ee
--- /dev/null
+++ b/target-microblaze/gdbstub.c
@@ -0,0 +1,56 @@
+/*
+ * MicroBlaze gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+ CPUMBState *env = &cpu->env;
+
+ if (n < 32) {
+ return gdb_get_reg32(mem_buf, env->regs[n]);
+ } else {
+ return gdb_get_reg32(mem_buf, env->sregs[n - 32]);
+ }
+ return 0;
+}
+
+int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+ CPUClass *cc = CPU_GET_CLASS(cs);
+ CPUMBState *env = &cpu->env;
+ uint32_t tmp;
+
+ if (n > cc->gdb_num_core_regs) {
+ return 0;
+ }
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 32) {
+ env->regs[n] = tmp;
+ } else {
+ env->sregs[n - 32] = tmp;
+ }
+ return 4;
+}
diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs
index 119c816..0277d56 100644
--- a/target-mips/Makefile.objs
+++ b/target-mips/Makefile.objs
@@ -1,2 +1,3 @@
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
+obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h
index 291b061..25ca9f9 100644
--- a/target-mips/cpu-qom.h
+++ b/target-mips/cpu-qom.h
@@ -78,5 +78,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 17d49b8..ca66d41 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -100,6 +100,8 @@ 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;
diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c
new file mode 100644
index 0000000..6b2bba9
--- /dev/null
+++ b/target-mips/gdbstub.c
@@ -0,0 +1,154 @@
+/*
+ * MIPS gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ if (n < 32) {
+ return gdb_get_regl(mem_buf, env->active_tc.gpr[n]);
+ }
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ if (n >= 38 && n < 70) {
+ if (env->CP0_Status & (1 << CP0St_FR)) {
+ return gdb_get_regl(mem_buf, env->active_fpu.fpr[n - 38].d);
+ } else {
+ return gdb_get_regl(mem_buf,
+ env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
+ }
+ }
+ switch (n) {
+ case 70:
+ return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31);
+ case 71:
+ return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0);
+ }
+ }
+ switch (n) {
+ case 32:
+ return gdb_get_regl(mem_buf, (int32_t)env->CP0_Status);
+ case 33:
+ return gdb_get_regl(mem_buf, env->active_tc.LO[0]);
+ case 34:
+ return gdb_get_regl(mem_buf, env->active_tc.HI[0]);
+ case 35:
+ return gdb_get_regl(mem_buf, env->CP0_BadVAddr);
+ case 36:
+ return gdb_get_regl(mem_buf, (int32_t)env->CP0_Cause);
+ case 37:
+ return gdb_get_regl(mem_buf, env->active_tc.PC |
+ !!(env->hflags & MIPS_HFLAG_M16));
+ case 72:
+ return gdb_get_regl(mem_buf, 0); /* fp */
+ case 89:
+ return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid);
+ }
+ if (n >= 73 && n <= 88) {
+ /* 16 embedded regs. */
+ return gdb_get_regl(mem_buf, 0);
+ }
+
+ return 0;
+}
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+static unsigned int ieee_rm[] = {
+ float_round_nearest_even,
+ float_round_to_zero,
+ float_round_up,
+ float_round_down
+};
+#define RESTORE_ROUNDING_MODE \
+ set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \
+ &env->active_fpu.fp_status)
+
+int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+ target_ulong tmp;
+
+ tmp = ldtul_p(mem_buf);
+
+ if (n < 32) {
+ env->active_tc.gpr[n] = tmp;
+ return sizeof(target_ulong);
+ }
+ if (env->CP0_Config1 & (1 << CP0C1_FP)
+ && n >= 38 && n < 73) {
+ if (n < 70) {
+ if (env->CP0_Status & (1 << CP0St_FR)) {
+ env->active_fpu.fpr[n - 38].d = tmp;
+ } else {
+ env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
+ }
+ }
+ switch (n) {
+ case 70:
+ env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
+ /* set rounding mode */
+ RESTORE_ROUNDING_MODE;
+ break;
+ case 71:
+ env->active_fpu.fcr0 = tmp;
+ break;
+ }
+ return sizeof(target_ulong);
+ }
+ switch (n) {
+ case 32:
+ env->CP0_Status = tmp;
+ break;
+ case 33:
+ env->active_tc.LO[0] = tmp;
+ break;
+ case 34:
+ env->active_tc.HI[0] = tmp;
+ break;
+ case 35:
+ env->CP0_BadVAddr = tmp;
+ break;
+ case 36:
+ env->CP0_Cause = tmp;
+ break;
+ case 37:
+ env->active_tc.PC = tmp & ~(target_ulong)1;
+ if (tmp & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ } else {
+ env->hflags &= ~(MIPS_HFLAG_M16);
+ }
+ break;
+ case 72: /* fp, ignored */
+ break;
+ default:
+ if (n > 89) {
+ return 0;
+ }
+ /* Other registers are readonly. Ignore writes. */
+ break;
+ }
+
+ return sizeof(target_ulong);
+}
diff --git a/target-openrisc/Makefile.objs b/target-openrisc/Makefile.objs
index 44dc539..397d016 100644
--- a/target-openrisc/Makefile.objs
+++ b/target-openrisc/Makefile.objs
@@ -2,3 +2,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o
obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
obj-y += exception_helper.o fpu_helper.o int_helper.o \
interrupt_helper.o mmu_helper.o sys_helper.o
+obj-y += gdbstub.o
diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c
index a2cd4be..7b620d9 100644
--- a/target-openrisc/cpu.c
+++ b/target-openrisc/cpu.c
@@ -152,6 +152,8 @@ 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;
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 5747655..bcd15ca 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -350,6 +350,8 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void openrisc_translate_init(void);
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
target_ulong address,
diff --git a/target-openrisc/gdbstub.c b/target-openrisc/gdbstub.c
new file mode 100644
index 0000000..78874df
--- /dev/null
+++ b/target-openrisc/gdbstub.c
@@ -0,0 +1,86 @@
+/*
+ * 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);
+ break;
+
+ case 33: /* NPC */
+ return gdb_get_reg32(mem_buf, env->npc);
+ break;
+
+ case 34: /* SR */
+ return gdb_get_reg32(mem_buf, env->sr);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ CPUClass *cc = CPU_GET_CLASS(cs);
+ CPUOpenRISCState *env = &cpu->env;
+ uint32_t tmp;
+
+ if (n > cc->gdb_num_core_regs) {
+ return 0;
+ }
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 32) {
+ env->gpr[n] = tmp;
+ } else {
+ switch (n) {
+ case 32: /* PPC */
+ env->ppc = tmp;
+ break;
+
+ case 33: /* NPC */
+ env->npc = tmp;
+ break;
+
+ case 34: /* SR */
+ env->sr = tmp;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 4;
+}
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 2c43c34..8274e8a 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -12,3 +12,4 @@ obj-y += timebase_helper.o
obj-y += misc_helper.o
obj-y += mem_helper.o
obj-$(CONFIG_USER_ONLY) += user_only_helper.o
+obj-y += gdbstub.o
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 7216cc4..658e962 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -106,5 +106,7 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf,
void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c
new file mode 100644
index 0000000..1c91090
--- /dev/null
+++ b/target-ppc/gdbstub.c
@@ -0,0 +1,131 @@
+/*
+ * PowerPC gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
+ * expects whatever the target description contains. Due to a
+ * historical mishap the FP registers appear in between core integer
+ * regs and PC, MSR, CR, and so forth. We hack round this by giving the
+ * FP regs zero size when talking to a newer gdb.
+ */
+
+int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ if (n < 32) {
+ /* gprs */
+ return gdb_get_regl(mem_buf, env->gpr[n]);
+ } else if (n < 64) {
+ /* fprs */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ stfq_p(mem_buf, env->fpr[n-32]);
+ return 8;
+ } else {
+ switch (n) {
+ case 64:
+ return gdb_get_regl(mem_buf, env->nip);
+ case 65:
+ return gdb_get_regl(mem_buf, env->msr);
+ case 66:
+ {
+ uint32_t cr = 0;
+ int i;
+ for (i = 0; i < 8; i++) {
+ cr |= env->crf[i] << (32 - ((i + 1) * 4));
+ }
+ return gdb_get_reg32(mem_buf, cr);
+ }
+ case 67:
+ return gdb_get_regl(mem_buf, env->lr);
+ case 68:
+ return gdb_get_regl(mem_buf, env->ctr);
+ case 69:
+ return gdb_get_regl(mem_buf, env->xer);
+ case 70:
+ {
+ if (gdb_has_xml) {
+ return 0;
+ }
+ return gdb_get_reg32(mem_buf, env->fpscr);
+ }
+ }
+ }
+ return 0;
+}
+
+int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ if (n < 32) {
+ /* gprs */
+ env->gpr[n] = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ } else if (n < 64) {
+ /* fprs */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ env->fpr[n-32] = ldfq_p(mem_buf);
+ return 8;
+ } else {
+ switch (n) {
+ case 64:
+ env->nip = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ case 65:
+ ppc_store_msr(env, ldtul_p(mem_buf));
+ return sizeof(target_ulong);
+ case 66:
+ {
+ uint32_t cr = ldl_p(mem_buf);
+ int i;
+ for (i = 0; i < 8; i++) {
+ env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
+ }
+ return 4;
+ }
+ case 67:
+ env->lr = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ case 68:
+ env->ctr = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ case 69:
+ env->xer = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ case 70:
+ /* fpscr */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
+ return sizeof(target_ulong);
+ }
+ }
+ return 0;
+}
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e1d9d02..1b7d96b 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8313,6 +8313,8 @@ 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;
cc->gdb_num_core_regs = 71;
}
diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs
index 4e63417..ab938e7 100644
--- a/target-s390x/Makefile.objs
+++ b/target-s390x/Makefile.objs
@@ -1,4 +1,5 @@
obj-y += translate.o helper.o cpu.o interrupt.o
obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
+obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += ioinst.o
obj-$(CONFIG_KVM) += kvm.o
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index cac55cc..5cec1ed 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -75,5 +75,7 @@ void s390_cpu_do_interrupt(CPUState *cpu);
void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index ae62143..3b15b36 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -173,6 +173,8 @@ 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
diff --git a/target-s390x/gdbstub.c b/target-s390x/gdbstub.c
new file mode 100644
index 0000000..a129742
--- /dev/null
+++ b/target-s390x/gdbstub.c
@@ -0,0 +1,88 @@
+/*
+ * s390x gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "qemu/bitops.h"
+
+int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+ uint64_t val;
+ int cc_op;
+
+ switch (n) {
+ case S390_PSWM_REGNUM:
+ cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
+ val = deposit64(env->psw.mask, 44, 2, cc_op);
+ return gdb_get_regl(mem_buf, val);
+ case S390_PSWA_REGNUM:
+ return gdb_get_regl(mem_buf, env->psw.addr);
+ case S390_R0_REGNUM ... S390_R15_REGNUM:
+ return gdb_get_regl(mem_buf, env->regs[n-S390_R0_REGNUM]);
+ case S390_A0_REGNUM ... S390_A15_REGNUM:
+ return gdb_get_reg32(mem_buf, env->aregs[n-S390_A0_REGNUM]);
+ case S390_FPC_REGNUM:
+ return gdb_get_reg32(mem_buf, env->fpc);
+ case S390_F0_REGNUM ... S390_F15_REGNUM:
+ return gdb_get_reg64(mem_buf, env->fregs[n-S390_F0_REGNUM].ll);
+ }
+
+ return 0;
+}
+
+int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+ target_ulong tmpl;
+ uint32_t tmp32;
+ int r = 8;
+ tmpl = ldtul_p(mem_buf);
+ tmp32 = ldl_p(mem_buf);
+
+ switch (n) {
+ case S390_PSWM_REGNUM:
+ env->psw.mask = tmpl;
+ env->cc_op = extract64(tmpl, 44, 2);
+ break;
+ case S390_PSWA_REGNUM:
+ env->psw.addr = tmpl;
+ break;
+ case S390_R0_REGNUM ... S390_R15_REGNUM:
+ env->regs[n-S390_R0_REGNUM] = tmpl;
+ break;
+ case S390_A0_REGNUM ... S390_A15_REGNUM:
+ env->aregs[n-S390_A0_REGNUM] = tmp32;
+ r = 4;
+ break;
+ case S390_FPC_REGNUM:
+ env->fpc = tmp32;
+ r = 4;
+ break;
+ case S390_F0_REGNUM ... S390_F15_REGNUM:
+ env->fregs[n-S390_F0_REGNUM].ll = tmpl;
+ break;
+ default:
+ return 0;
+ }
+ return r;
+}
diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs
index cb448a8..a285358 100644
--- a/target-sh4/Makefile.objs
+++ b/target-sh4/Makefile.objs
@@ -1 +1,2 @@
obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h
index 6f50a0a..209069a 100644
--- a/target-sh4/cpu-qom.h
+++ b/target-sh4/cpu-qom.h
@@ -87,5 +87,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
void superh_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index 7f5c47a..2fe12a6 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -286,6 +286,8 @@ 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
diff --git a/target-sh4/gdbstub.c b/target-sh4/gdbstub.c
new file mode 100644
index 0000000..df4fa2a
--- /dev/null
+++ b/target-sh4/gdbstub.c
@@ -0,0 +1,146 @@
+/*
+ * SuperH gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
+/* FIXME: We should use XML for this. */
+
+int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ SuperHCPU *cpu = SUPERH_CPU(cs);
+ CPUSH4State *env = &cpu->env;
+
+ switch (n) {
+ case 0 ... 7:
+ if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+ return gdb_get_regl(mem_buf, env->gregs[n + 16]);
+ } else {
+ return gdb_get_regl(mem_buf, env->gregs[n]);
+ }
+ case 8 ... 15:
+ return gdb_get_regl(mem_buf, env->gregs[n]);
+ case 16:
+ return gdb_get_regl(mem_buf, env->pc);
+ case 17:
+ return gdb_get_regl(mem_buf, env->pr);
+ case 18:
+ return gdb_get_regl(mem_buf, env->gbr);
+ case 19:
+ return gdb_get_regl(mem_buf, env->vbr);
+ case 20:
+ return gdb_get_regl(mem_buf, env->mach);
+ case 21:
+ return gdb_get_regl(mem_buf, env->macl);
+ case 22:
+ return gdb_get_regl(mem_buf, env->sr);
+ case 23:
+ return gdb_get_regl(mem_buf, env->fpul);
+ case 24:
+ return gdb_get_regl(mem_buf, env->fpscr);
+ case 25 ... 40:
+ if (env->fpscr & FPSCR_FR) {
+ stfl_p(mem_buf, env->fregs[n - 9]);
+ } else {
+ stfl_p(mem_buf, env->fregs[n - 25]);
+ }
+ return 4;
+ case 41:
+ return gdb_get_regl(mem_buf, env->ssr);
+ case 42:
+ return gdb_get_regl(mem_buf, env->spc);
+ case 43 ... 50:
+ return gdb_get_regl(mem_buf, env->gregs[n - 43]);
+ case 51 ... 58:
+ return gdb_get_regl(mem_buf, env->gregs[n - (51 - 16)]);
+ }
+
+ return 0;
+}
+
+int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ SuperHCPU *cpu = SUPERH_CPU(cs);
+ CPUSH4State *env = &cpu->env;
+
+ switch (n) {
+ case 0 ... 7:
+ if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+ env->gregs[n + 16] = ldl_p(mem_buf);
+ } else {
+ env->gregs[n] = ldl_p(mem_buf);
+ }
+ break;
+ case 8 ... 15:
+ env->gregs[n] = ldl_p(mem_buf);
+ break;
+ case 16:
+ env->pc = ldl_p(mem_buf);
+ break;
+ case 17:
+ env->pr = ldl_p(mem_buf);
+ break;
+ case 18:
+ env->gbr = ldl_p(mem_buf);
+ break;
+ case 19:
+ env->vbr = ldl_p(mem_buf);
+ break;
+ case 20:
+ env->mach = ldl_p(mem_buf);
+ break;
+ case 21:
+ env->macl = ldl_p(mem_buf);
+ break;
+ case 22:
+ env->sr = ldl_p(mem_buf);
+ break;
+ case 23:
+ env->fpul = ldl_p(mem_buf);
+ break;
+ case 24:
+ env->fpscr = ldl_p(mem_buf);
+ break;
+ case 25 ... 40:
+ if (env->fpscr & FPSCR_FR) {
+ env->fregs[n - 9] = ldfl_p(mem_buf);
+ } else {
+ env->fregs[n - 25] = ldfl_p(mem_buf);
+ }
+ break;
+ case 41:
+ env->ssr = ldl_p(mem_buf);
+ break;
+ case 42:
+ env->spc = ldl_p(mem_buf);
+ break;
+ case 43 ... 50:
+ env->gregs[n - 43] = ldl_p(mem_buf);
+ break;
+ case 51 ... 58:
+ env->gregs[n - (51 - 16)] = ldl_p(mem_buf);
+ break;
+ default:
+ return 0;
+ }
+
+ return 4;
+}
diff --git a/target-sparc/Makefile.objs b/target-sparc/Makefile.objs
index 9fc42ea..1cd81cc 100644
--- a/target-sparc/Makefile.objs
+++ b/target-sparc/Makefile.objs
@@ -4,3 +4,4 @@ obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o
ldst_helper.o
obj-$(TARGET_SPARC) += int32_helper.o
obj-$(TARGET_SPARC64) += int64_helper.o
obj-$(TARGET_SPARC64) += vis_helper.o
+obj-y += gdbstub.o
diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h
index 1b39274..3f9e84c 100644
--- a/target-sparc/cpu-qom.h
+++ b/target-sparc/cpu-qom.h
@@ -79,5 +79,7 @@ void sparc_cpu_do_interrupt(CPUState *cpu);
void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, uint64_t addr);
+int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index b35f2d1..855f097 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -787,6 +787,8 @@ 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;
diff --git a/target-sparc/gdbstub.c b/target-sparc/gdbstub.c
new file mode 100644
index 0000000..25fb2a3
--- /dev/null
+++ b/target-sparc/gdbstub.c
@@ -0,0 +1,208 @@
+/*
+ * SPARC gdb server stub
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2013 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+#ifdef TARGET_ABI32
+#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val)
+#else
+#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
+#endif
+
+int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
+
+ if (n < 8) {
+ /* g0..g7 */
+ return gdb_get_rega(mem_buf, env->gregs[n]);
+ }
+ if (n < 32) {
+ /* register window */
+ return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
+ }
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+ if (n < 64) {
+ /* fprs */
+ if (n & 1) {
+ return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
+ } else {
+ return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
+ }
+ }
+ /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+ switch (n) {
+ case 64:
+ return gdb_get_rega(mem_buf, env->y);
+ case 65:
+ return gdb_get_rega(mem_buf, cpu_get_psr(env));
+ case 66:
+ return gdb_get_rega(mem_buf, env->wim);
+ case 67:
+ return gdb_get_rega(mem_buf, env->tbr);
+ case 68:
+ return gdb_get_rega(mem_buf, env->pc);
+ case 69:
+ return gdb_get_rega(mem_buf, env->npc);
+ case 70:
+ return gdb_get_rega(mem_buf, env->fsr);
+ case 71:
+ return gdb_get_rega(mem_buf, 0); /* csr */
+ default:
+ return gdb_get_rega(mem_buf, 0);
+ }
+#else
+ if (n < 64) {
+ /* f0-f31 */
+ if (n & 1) {
+ return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
+ } else {
+ return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
+ }
+ }
+ if (n < 80) {
+ /* f32-f62 (double width, even numbers only) */
+ return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll);
+ }
+ switch (n) {
+ case 80:
+ return gdb_get_regl(mem_buf, env->pc);
+ case 81:
+ return gdb_get_regl(mem_buf, env->npc);
+ case 82:
+ return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) |
+ ((env->asi & 0xff) << 24) |
+ ((env->pstate & 0xfff) << 8) |
+ cpu_get_cwp64(env));
+ case 83:
+ return gdb_get_regl(mem_buf, env->fsr);
+ case 84:
+ return gdb_get_regl(mem_buf, env->fprs);
+ case 85:
+ return gdb_get_regl(mem_buf, env->y);
+ }
+#endif
+ return 0;
+}
+
+int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
+#if defined(TARGET_ABI32)
+ abi_ulong tmp;
+
+ tmp = ldl_p(mem_buf);
+#else
+ target_ulong tmp;
+
+ tmp = ldtul_p(mem_buf);
+#endif
+
+ if (n < 8) {
+ /* g0..g7 */
+ env->gregs[n] = tmp;
+ } else if (n < 32) {
+ /* register window */
+ env->regwptr[n - 8] = tmp;
+ }
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+ else if (n < 64) {
+ /* fprs */
+ /* f0-f31 */
+ if (n & 1) {
+ env->fpr[(n - 32) / 2].l.lower = tmp;
+ } else {
+ env->fpr[(n - 32) / 2].l.upper = tmp;
+ }
+ } else {
+ /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+ switch (n) {
+ case 64:
+ env->y = tmp;
+ break;
+ case 65:
+ cpu_put_psr(env, tmp);
+ break;
+ case 66:
+ env->wim = tmp;
+ break;
+ case 67:
+ env->tbr = tmp;
+ break;
+ case 68:
+ env->pc = tmp;
+ break;
+ case 69:
+ env->npc = tmp;
+ break;
+ case 70:
+ env->fsr = tmp;
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 4;
+#else
+ else if (n < 64) {
+ /* f0-f31 */
+ tmp = ldl_p(mem_buf);
+ if (n & 1) {
+ env->fpr[(n - 32) / 2].l.lower = tmp;
+ } else {
+ env->fpr[(n - 32) / 2].l.upper = tmp;
+ }
+ return 4;
+ } else if (n < 80) {
+ /* f32-f62 (double width, even numbers only) */
+ env->fpr[(n - 32) / 2].ll = tmp;
+ } else {
+ switch (n) {
+ case 80:
+ env->pc = tmp;
+ break;
+ case 81:
+ env->npc = tmp;
+ break;
+ case 82:
+ cpu_put_ccr(env, tmp >> 32);
+ env->asi = (tmp >> 24) & 0xff;
+ env->pstate = (tmp >> 8) & 0xfff;
+ cpu_put_cwp64(env, tmp & 0xff);
+ break;
+ case 83:
+ env->fsr = tmp;
+ break;
+ case 84:
+ env->fprs = tmp;
+ break;
+ case 85:
+ env->y = tmp;
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 8;
+#endif
+}
diff --git a/target-xtensa/Makefile.objs b/target-xtensa/Makefile.objs
index 644b7f9..5c150a8 100644
--- a/target-xtensa/Makefile.objs
+++ b/target-xtensa/Makefile.objs
@@ -3,3 +3,4 @@ obj-y += core-dc232b.o
obj-y += core-dc233c.o
obj-y += core-fsf.o
obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
index 878eb15..9a2da25 100644
--- a/target-xtensa/cpu-qom.h
+++ b/target-xtensa/cpu-qom.h
@@ -87,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, uint64_t addr);
+int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index eaafacf..0743ce2 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -131,6 +131,8 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void
*data)
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
diff --git a/target-xtensa/gdbstub.c b/target-xtensa/gdbstub.c
new file mode 100644
index 0000000..b8cef35
--- /dev/null
+++ b/target-xtensa/gdbstub.c
@@ -0,0 +1,111 @@
+/*
+ * 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);
+ XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cs);
+ CPUXtensaState *env = &cpu->env;
+ const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
+
+ if (n < 0 || n >= xcc->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)
+ % xcc->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);
+ XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cs);
+ CPUXtensaState *env = &cpu->env;
+ uint32_t tmp;
+ const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
+
+ if (n < 0 || n >= xcc->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) % xcc->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;
+}
--
1.8.1.4
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-ppc] [PATCH RFC qom-cpu 41/41] cpu: Introduce CPUClass::gdb_{read, write}_register(),
Andreas Färber <=