Am 04.04.2014 22:23, schrieb Thomas Falcon:
This patch allows registers to be properly read from and written to
when using the gdbstub to debug a ppc guest running in little
endian mode. It accomplishes this goal by byte swapping the values of
any registers if the MSR:LE value is set.
Signed-off-by: Thomas Falcon <tlfal...@linux.vnet.ibm.com>
---
Differences for v7:
Inlined the register_read() and register_write() wrapper functions
---
target-ppc/cpu-qom.h | 1 +
target-ppc/gdbstub.c | 125 +++++++++++++++++++++++++++++++++++++--------------
2 files changed, 92 insertions(+), 34 deletions(-)
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 47dc8e6..aab4977 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -111,6 +111,7 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf,
int flags);
void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
+void ppc_cpu_gdb_swap_register(uint8_t *buf, int reg, int len);
This is only ever used in gdbstub.c. Can we please keep it static there
to avoid a full ppc*-softmmu rebuild?
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c
index 1c91090..594dd08 100644
--- a/target-ppc/gdbstub.c
+++ b/target-ppc/gdbstub.c
@@ -21,6 +21,58 @@
#include "qemu-common.h"
#include "exec/gdbstub.h"
+static int ppc_cpu_gdb_register_len(int n)
Nitpick: Since these two functions do not operate on the CPU, you could
just use ppc_gdb_* rather than ppc_cpu_gdb_*.
+{
+ switch (n) {
+ case 0 ... 31:
+ /* gprs */
+ return sizeof(target_ulong);
+ case 32 ... 63:
+ /* fprs */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ return 8;
+ case 66:
+ /* cr */
+ return 4;
+ case 64:
+ /* nip */
+ case 65:
+ /* msr */
+ case 67:
+ /* lr */
+ case 68:
+ /* ctr */
+ case 69:
+ /* xer */
+ return sizeof(target_ulong);
+ case 70:
+ /* fpscr */
+ if (gdb_has_xml) {
+ return 0;
+ }
+ return sizeof(target_ulong);
+ default:
+ return 0;
+ }
+}
+
+
+/* The following functions are used to ensure the correct
+ * transfer of registers between a little endian ppc target
+ * and a big endian host by checking the LE bit in the Machine State Register
+ */
+
+void ppc_cpu_gdb_swap_register(uint8_t *mem_buf, int n, int len)
+{
+ if (len == 4) {
+ bswap32s((uint32_t *)mem_buf);
+ } else {
+ bswap64s((uint64_t *)mem_buf);
+ }
This logic assumes that len can only be either 4 or 8. Please use an
explicit len == 8 comparison and g_assert_not_reached() on unhandled len
values.
+}
+
/* 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
@@ -32,23 +84,26 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t
*mem_buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ int r = ppc_cpu_gdb_register_len(n);
+
+ if (!r) {
+ return r;
+ }
if (n < 32) {
/* gprs */
- return gdb_get_regl(mem_buf, env->gpr[n]);
+ gdb_get_regl(mem_buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- if (gdb_has_xml) {
- return 0;
- }
I stumbled over dropping this not being related to Little Endian or
being mentioned in the commit message. Maybe mention that this is
replaced by ..._register_len() and returning early?