aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/gdbstub.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2014-06-23 15:23:08 +0200
committerAlexander Graf <agraf@suse.de>2014-06-27 13:48:22 +0200
commitb3cad3abf6df07db165091343b912c2a5de63c26 (patch)
treed010a10efa2e67806871326459b79fd4206ad98d /target-ppc/gdbstub.c
parent294d1292893867894992e810a01cfcfa451f1885 (diff)
PPC: Add support for Apple gdb in gdbstub
The Apple gdbstub protocol is different from the normal gdbstub protocol used on PowerPC. Add support for the different variant, so that we can use Apple's gdb to debug guest code. Keep in mind that the switch is a compile time option. We can't detect during runtime whether a gdb connecting to us is an upstream gdb or an Apple gdb. Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc/gdbstub.c')
-rw-r--r--target-ppc/gdbstub.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c
index 381a3c7e31..694d303e19 100644
--- a/target-ppc/gdbstub.c
+++ b/target-ppc/gdbstub.c
@@ -21,6 +21,31 @@
#include "qemu-common.h"
#include "exec/gdbstub.h"
+static int ppc_gdb_register_len_apple(int n)
+{
+ switch (n) {
+ case 0 ... 31:
+ /* gprs */
+ return 8;
+ case 32 ... 63:
+ /* fprs */
+ return 8;
+ case 64 ... 95:
+ return 16;
+ case 64+32: /* nip */
+ case 65+32: /* msr */
+ case 67+32: /* lr */
+ case 68+32: /* ctr */
+ case 69+32: /* xer */
+ case 70+32: /* fpscr */
+ return 8;
+ case 66+32: /* cr */
+ return 4;
+ default:
+ return 0;
+ }
+}
+
static int ppc_gdb_register_len(int n)
{
switch (n) {
@@ -132,6 +157,65 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return r;
}
+int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ int r = ppc_gdb_register_len_apple(n);
+
+ if (!r) {
+ return r;
+ }
+
+ if (n < 32) {
+ /* gprs */
+ gdb_get_reg64(mem_buf, env->gpr[n]);
+ } else if (n < 64) {
+ /* fprs */
+ stfq_p(mem_buf, env->fpr[n-32]);
+ } else if (n < 96) {
+ /* Altivec */
+ stq_p(mem_buf, n - 64);
+ stq_p(mem_buf + 8, 0);
+ } else {
+ switch (n) {
+ case 64 + 32:
+ gdb_get_reg64(mem_buf, env->nip);
+ break;
+ case 65 + 32:
+ gdb_get_reg64(mem_buf, env->msr);
+ break;
+ case 66 + 32:
+ {
+ uint32_t cr = 0;
+ int i;
+ for (i = 0; i < 8; i++) {
+ cr |= env->crf[i] << (32 - ((i + 1) * 4));
+ }
+ gdb_get_reg32(mem_buf, cr);
+ break;
+ }
+ case 67 + 32:
+ gdb_get_reg64(mem_buf, env->lr);
+ break;
+ case 68 + 32:
+ gdb_get_reg64(mem_buf, env->ctr);
+ break;
+ case 69 + 32:
+ gdb_get_reg64(mem_buf, env->xer);
+ break;
+ case 70 + 32:
+ gdb_get_reg64(mem_buf, env->fpscr);
+ break;
+ }
+ }
+ if (msr_le) {
+ /* If cpu is in LE mode, convert memory contents to LE. */
+ ppc_gdb_swap_register(mem_buf, n, r);
+ }
+ return r;
+}
+
int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -185,3 +269,56 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
}
return r;
}
+int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ int r = ppc_gdb_register_len_apple(n);
+
+ if (!r) {
+ return r;
+ }
+ if (msr_le) {
+ /* If cpu is in LE mode, convert memory contents to LE. */
+ ppc_gdb_swap_register(mem_buf, n, r);
+ }
+ if (n < 32) {
+ /* gprs */
+ env->gpr[n] = ldq_p(mem_buf);
+ } else if (n < 64) {
+ /* fprs */
+ env->fpr[n-32] = ldfq_p(mem_buf);
+ } else {
+ switch (n) {
+ case 64 + 32:
+ env->nip = ldq_p(mem_buf);
+ break;
+ case 65 + 32:
+ ppc_store_msr(env, ldq_p(mem_buf));
+ break;
+ case 66 + 32:
+ {
+ uint32_t cr = ldl_p(mem_buf);
+ int i;
+ for (i = 0; i < 8; i++) {
+ env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
+ }
+ break;
+ }
+ case 67 + 32:
+ env->lr = ldq_p(mem_buf);
+ break;
+ case 68 + 32:
+ env->ctr = ldq_p(mem_buf);
+ break;
+ case 69 + 32:
+ env->xer = ldq_p(mem_buf);
+ break;
+ case 70 + 32:
+ /* fpscr */
+ store_fpscr(env, ldq_p(mem_buf), 0xffffffff);
+ break;
+ }
+ }
+ return r;
+}