diff options
Diffstat (limited to 'target/ppc/gdbstub.c')
-rw-r--r-- | target/ppc/gdbstub.c | 504 |
1 files changed, 416 insertions, 88 deletions
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 19565b584d..3b28d4e21c 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -7,7 +7,7 @@ * 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. + * version 2.1 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 @@ -18,9 +18,10 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" -#include "qemu-common.h" #include "cpu.h" #include "exec/gdbstub.h" +#include "gdbstub/helpers.h" +#include "internal.h" static int ppc_gdb_register_len_apple(int n) { @@ -33,14 +34,14 @@ static int ppc_gdb_register_len_apple(int n) return 8; case 64 ... 95: return 16; - case 64+32: /* nip */ - case 65+32: /* msr */ - case 67+32: /* lr */ - case 68+32: /* ctr */ - case 70+32: /* fpscr */ + case 64 + 32: /* nip */ + case 65 + 32: /* msr */ + case 67 + 32: /* lr */ + case 68 + 32: /* ctr */ + case 70 + 32: /* fpscr */ return 8; - case 66+32: /* cr */ - case 69+32: /* xer */ + case 66 + 32: /* cr */ + case 69 + 32: /* xer */ return 4; default: return 0; @@ -53,12 +54,6 @@ static int ppc_gdb_register_len(int n) case 0 ... 31: /* gprs */ return sizeof(target_ulong); - case 32 ... 63: - /* fprs */ - if (gdb_has_xml) { - return 0; - } - return 8; case 66: /* cr */ case 69: @@ -73,48 +68,48 @@ static int ppc_gdb_register_len(int n) case 68: /* ctr */ return sizeof(target_ulong); - case 70: - /* fpscr */ - if (gdb_has_xml) { - return 0; - } - return sizeof(target_ulong); default: return 0; } } -/* We need to present the registers to gdb in the "current" memory ordering. - For user-only mode we get this for free; TARGET_WORDS_BIGENDIAN is set to - the proper ordering for the binary, and cannot be changed. - For system mode, TARGET_WORDS_BIGENDIAN is always set, and we must check - the current mode of the chip to see if we're running in little-endian. */ +/* + * We need to present the registers to gdb in the "current" memory + * ordering. For user-only mode we get this for free; + * TARGET_BIG_ENDIAN is set to the proper ordering for the + * binary, and cannot be changed. For system mode, + * TARGET_BIG_ENDIAN is always set, and we must check the current + * mode of the chip to see if we're running in little-endian. + */ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len) { #ifndef CONFIG_USER_ONLY - if (!msr_le) { + if (!FIELD_EX64(env->msr, MSR, LE)) { /* do nothing */ } else if (len == 4) { bswap32s((uint32_t *)mem_buf); } else if (len == 8) { bswap64s((uint64_t *)mem_buf); + } else if (len == 16) { + bswap128s((Int128 *)mem_buf); } else { g_assert_not_reached(); } #endif } -/* Old gdb always expects FP registers. Newer (xml-aware) gdb only +/* + * 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. + * 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) +int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + CPUPPCState *env = cpu_env(cs); + uint8_t *mem_buf; int r = ppc_gdb_register_len(n); if (!r) { @@ -123,50 +118,41 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) if (n < 32) { /* gprs */ - gdb_get_regl(mem_buf, env->gpr[n]); - } else if (n < 64) { - /* fprs */ - stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32)); + gdb_get_regl(buf, env->gpr[n]); } else { switch (n) { case 64: - gdb_get_regl(mem_buf, env->nip); + gdb_get_regl(buf, env->nip); break; case 65: - gdb_get_regl(mem_buf, env->msr); + gdb_get_regl(buf, env->msr); break; case 66: { - 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); + uint32_t cr = ppc_get_cr(env); + gdb_get_reg32(buf, cr); break; } case 67: - gdb_get_regl(mem_buf, env->lr); + gdb_get_regl(buf, env->lr); break; case 68: - gdb_get_regl(mem_buf, env->ctr); + gdb_get_regl(buf, env->ctr); break; case 69: - gdb_get_reg32(mem_buf, env->xer); - break; - case 70: - gdb_get_reg32(mem_buf, env->fpscr); + gdb_get_reg32(buf, cpu_read_xer(env)); break; } } + mem_buf = buf->data + buf->len - r; ppc_maybe_bswap_register(env, mem_buf, r); return r; } -int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n) +int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + CPUPPCState *env = cpu_env(cs); + uint8_t *mem_buf; int r = ppc_gdb_register_len_apple(n); if (!r) { @@ -175,54 +161,50 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n) if (n < 32) { /* gprs */ - gdb_get_reg64(mem_buf, env->gpr[n]); + gdb_get_reg64(buf, env->gpr[n]); } else if (n < 64) { /* fprs */ - stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32)); + gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32)); } else if (n < 96) { /* Altivec */ - stq_p(mem_buf, n - 64); - stq_p(mem_buf + 8, 0); + gdb_get_reg64(buf, n - 64); + gdb_get_reg64(buf, 0); } else { switch (n) { case 64 + 32: - gdb_get_reg64(mem_buf, env->nip); + gdb_get_reg64(buf, env->nip); break; case 65 + 32: - gdb_get_reg64(mem_buf, env->msr); + gdb_get_reg64(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); + uint32_t cr = ppc_get_cr(env); + gdb_get_reg32(buf, cr); break; } case 67 + 32: - gdb_get_reg64(mem_buf, env->lr); + gdb_get_reg64(buf, env->lr); break; case 68 + 32: - gdb_get_reg64(mem_buf, env->ctr); + gdb_get_reg64(buf, env->ctr); break; case 69 + 32: - gdb_get_reg32(mem_buf, env->xer); + gdb_get_reg32(buf, cpu_read_xer(env)); break; case 70 + 32: - gdb_get_reg64(mem_buf, env->fpscr); + gdb_get_reg64(buf, env->fpscr); break; } } + mem_buf = buf->data + buf->len - r; ppc_maybe_bswap_register(env, mem_buf, r); return r; } int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + CPUPPCState *env = cpu_env(cs); int r = ppc_gdb_register_len(n); if (!r) { @@ -234,7 +216,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->gpr[n] = ldtul_p(mem_buf); } else if (n < 64) { /* fprs */ - *cpu_fpr_ptr(env, n - 32) = ldfq_p(mem_buf); + *cpu_fpr_ptr(env, n - 32) = ldq_p(mem_buf); } else { switch (n) { case 64: @@ -246,10 +228,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) 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; - } + ppc_set_cr(env, cr); break; } case 67: @@ -259,11 +238,11 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->ctr = ldtul_p(mem_buf); break; case 69: - env->xer = ldl_p(mem_buf); + cpu_write_xer(env, ldl_p(mem_buf)); break; case 70: /* fpscr */ - store_fpscr(env, ldtul_p(mem_buf), 0xffffffff); + ppc_store_fpscr(env, ldtul_p(mem_buf)); break; } } @@ -271,8 +250,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) } int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; + CPUPPCState *env = cpu_env(cs); int r = ppc_gdb_register_len_apple(n); if (!r) { @@ -284,7 +262,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n) env->gpr[n] = ldq_p(mem_buf); } else if (n < 64) { /* fprs */ - *cpu_fpr_ptr(env, n - 32) = ldfq_p(mem_buf); + *cpu_fpr_ptr(env, n - 32) = ldq_p(mem_buf); } else { switch (n) { case 64 + 32: @@ -296,10 +274,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n) 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; - } + ppc_set_cr(env, cr); break; } case 67 + 32: @@ -309,13 +284,366 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n) env->ctr = ldq_p(mem_buf); break; case 69 + 32: - env->xer = ldl_p(mem_buf); + cpu_write_xer(env, ldl_p(mem_buf)); break; case 70 + 32: /* fpscr */ - store_fpscr(env, ldq_p(mem_buf), 0xffffffff); + ppc_store_fpscr(env, ldq_p(mem_buf)); break; } } return r; } + +#ifndef CONFIG_USER_ONLY +static void gdb_gen_spr_feature(CPUState *cs) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + GDBFeatureBuilder builder; + unsigned int num_regs = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (!spr->name) { + continue; + } + + /* + * GDB identifies registers based on the order they are + * presented in the XML. These ids will not match QEMU's + * representation (which follows the PowerISA). + * + * Store the position of the current register description so + * we can make the correspondence later. + */ + spr->gdb_id = num_regs; + num_regs++; + } + + if (pcc->gdb_spr.xml) { + return; + } + + gdb_feature_builder_init(&builder, &pcc->gdb_spr, + "org.qemu.power.spr", "power-spr.xml", + cs->gdb_num_regs); + + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (!spr->name) { + continue; + } + + gdb_feature_builder_append_reg(&builder, g_ascii_strdown(spr->name, -1), + TARGET_LONG_BITS, spr->gdb_id, + "int", "spr"); + } + + gdb_feature_builder_end(&builder); +} +#endif + +#if !defined(CONFIG_USER_ONLY) +static int gdb_find_spr_idx(CPUPPCState *env, int n) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (spr->name && spr->gdb_id == n) { + return i; + } + } + return -1; +} + +static int gdb_get_spr_reg(CPUState *cs, GByteArray *buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + int reg; + int len; + + reg = gdb_find_spr_idx(env, n); + if (reg < 0) { + return 0; + } + + len = TARGET_LONG_SIZE; + + /* Handle those SPRs that are not part of the env->spr[] array */ + target_ulong val; + switch (reg) { +#if defined(TARGET_PPC64) + case SPR_CFAR: + val = env->cfar; + break; +#endif + case SPR_HDEC: + val = cpu_ppc_load_hdecr(env); + break; + case SPR_TBL: + val = cpu_ppc_load_tbl(env); + break; + case SPR_TBU: + val = cpu_ppc_load_tbu(env); + break; + case SPR_DECR: + val = cpu_ppc_load_decr(env); + break; + default: + val = env->spr[reg]; + } + gdb_get_regl(buf, val); + + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len); + return len; +} + +static int gdb_set_spr_reg(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + int reg; + int len; + + reg = gdb_find_spr_idx(env, n); + if (reg < 0) { + return 0; + } + + len = TARGET_LONG_SIZE; + ppc_maybe_bswap_register(env, mem_buf, len); + + /* Handle those SPRs that are not part of the env->spr[] array */ + target_ulong val = ldn_p(mem_buf, len); + switch (reg) { +#if defined(TARGET_PPC64) + case SPR_CFAR: + env->cfar = val; + break; +#endif + default: + env->spr[reg] = val; + } + + return len; +} +#endif + +static int gdb_get_float_reg(CPUState *cs, GByteArray *buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + uint8_t *mem_buf; + if (n < 32) { + gdb_get_reg64(buf, *cpu_fpr_ptr(env, n)); + mem_buf = gdb_get_reg_ptr(buf, 8); + ppc_maybe_bswap_register(env, mem_buf, 8); + return 8; + } + if (n == 32) { + gdb_get_reg32(buf, env->fpscr); + mem_buf = gdb_get_reg_ptr(buf, 4); + ppc_maybe_bswap_register(env, mem_buf, 4); + return 4; + } + return 0; +} + +static int gdb_set_float_reg(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { + ppc_maybe_bswap_register(env, mem_buf, 8); + *cpu_fpr_ptr(env, n) = ldq_p(mem_buf); + return 8; + } + if (n == 32) { + ppc_maybe_bswap_register(env, mem_buf, 4); + ppc_store_fpscr(env, ldl_p(mem_buf)); + return 4; + } + return 0; +} + +static int gdb_get_avr_reg(CPUState *cs, GByteArray *buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + uint8_t *mem_buf; + + if (n < 32) { + ppc_avr_t *avr = cpu_avr_ptr(env, n); + gdb_get_reg128(buf, avr->VsrD(0), avr->VsrD(1)); + mem_buf = gdb_get_reg_ptr(buf, 16); + ppc_maybe_bswap_register(env, mem_buf, 16); + return 16; + } + if (n == 32) { + gdb_get_reg32(buf, ppc_get_vscr(env)); + mem_buf = gdb_get_reg_ptr(buf, 4); + ppc_maybe_bswap_register(env, mem_buf, 4); + return 4; + } + if (n == 33) { + gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]); + mem_buf = gdb_get_reg_ptr(buf, 4); + ppc_maybe_bswap_register(env, mem_buf, 4); + return 4; + } + return 0; +} + +static int gdb_set_avr_reg(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { + ppc_avr_t *avr = cpu_avr_ptr(env, n); + ppc_maybe_bswap_register(env, mem_buf, 16); + avr->VsrD(0) = ldq_p(mem_buf); + avr->VsrD(1) = ldq_p(mem_buf + 8); + return 16; + } + if (n == 32) { + ppc_maybe_bswap_register(env, mem_buf, 4); + ppc_store_vscr(env, ldl_p(mem_buf)); + return 4; + } + if (n == 33) { + ppc_maybe_bswap_register(env, mem_buf, 4); + env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf); + return 4; + } + return 0; +} + +static int gdb_get_spe_reg(CPUState *cs, GByteArray *buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { +#if defined(TARGET_PPC64) + gdb_get_reg32(buf, env->gpr[n] >> 32); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4); +#else + gdb_get_reg32(buf, env->gprh[n]); +#endif + return 4; + } + if (n == 32) { + gdb_get_reg64(buf, env->spe_acc); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8); + return 8; + } + if (n == 33) { + gdb_get_reg32(buf, env->spe_fscr); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4); + return 4; + } + return 0; +} + +static int gdb_set_spe_reg(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { +#if defined(TARGET_PPC64) + target_ulong lo = (uint32_t)env->gpr[n]; + target_ulong hi; + + ppc_maybe_bswap_register(env, mem_buf, 4); + + hi = (target_ulong)ldl_p(mem_buf) << 32; + env->gpr[n] = lo | hi; +#else + env->gprh[n] = ldl_p(mem_buf); +#endif + return 4; + } + if (n == 32) { + ppc_maybe_bswap_register(env, mem_buf, 8); + env->spe_acc = ldq_p(mem_buf); + return 8; + } + if (n == 33) { + ppc_maybe_bswap_register(env, mem_buf, 4); + env->spe_fscr = ldl_p(mem_buf); + return 4; + } + return 0; +} + +static int gdb_get_vsx_reg(CPUState *cs, GByteArray *buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { + gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n)); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8); + return 8; + } + return 0; +} + +static int gdb_set_vsx_reg(CPUState *cs, uint8_t *mem_buf, int n) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + if (n < 32) { + ppc_maybe_bswap_register(env, mem_buf, 8); + *cpu_vsrl_ptr(env, n) = ldq_p(mem_buf); + return 8; + } + return 0; +} + +const gchar *ppc_gdb_arch_name(CPUState *cs) +{ +#if defined(TARGET_PPC64) + return "powerpc:common64"; +#else + return "powerpc:common"; +#endif +} + +void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *pcc) +{ + if (pcc->insns_flags & PPC_FLOAT) { + gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg, + gdb_find_static_feature("power-fpu.xml"), 0); + } + if (pcc->insns_flags & PPC_ALTIVEC) { + gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg, + gdb_find_static_feature("power-altivec.xml"), + 0); + } + if (pcc->insns_flags & PPC_SPE) { + gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg, + gdb_find_static_feature("power-spe.xml"), 0); + } + if (pcc->insns_flags2 & PPC2_VSX) { + gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg, + gdb_find_static_feature("power-vsx.xml"), 0); + } +#ifndef CONFIG_USER_ONLY + gdb_gen_spr_feature(cs); + gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg, + &pcc->gdb_spr, 0); +#endif +} |