aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver/linux-ppc-low.c
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2009-07-31 15:30:03 +0000
committerUlrich Weigand <uweigand@de.ibm.com>2009-07-31 15:30:03 +0000
commit0b9ff2c0a421194cbef8937954cdbbd624d066b0 (patch)
tree839990eafb263251c33cdf35a47562cc0523e99f /gdb/gdbserver/linux-ppc-low.c
parent85e747d2499c43ff4003d348304f3d8f573d5cad (diff)
downloadgdb-0b9ff2c0a421194cbef8937954cdbbd624d066b0.zip
gdb-0b9ff2c0a421194cbef8937954cdbbd624d066b0.tar.gz
gdb-0b9ff2c0a421194cbef8937954cdbbd624d066b0.tar.bz2
* linux-ppc-low.c (INSTR_SC, NR_spu_run): Define.
(parse_spufs_run): New function. (ppc_get_pc, ppc_set_pc): Detect and handle SPU PC. (ppc_breakpoint_at): Handle SPU breakpoints.
Diffstat (limited to 'gdb/gdbserver/linux-ppc-low.c')
-rw-r--r--gdb/gdbserver/linux-ppc-low.c97
1 files changed, 90 insertions, 7 deletions
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index d630c17..2f198cf 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -191,10 +191,72 @@ ppc_supply_ptrace_register (int regno, const char *buf)
supply_register (regno, buf);
}
+
+#define INSTR_SC 0x44000002
+#define NR_spu_run 0x0116
+
+/* If the PPU thread is currently stopped on a spu_run system call,
+ return to FD and ADDR the file handle and NPC parameter address
+ used with the system call. Return non-zero if successful. */
+static int
+parse_spufs_run (int *fd, CORE_ADDR *addr)
+{
+ CORE_ADDR curr_pc;
+ int curr_insn;
+ int curr_r0;
+
+ if (register_size (0) == 4)
+ {
+ unsigned int pc, r0, r3, r4;
+ collect_register_by_name ("pc", &pc);
+ collect_register_by_name ("r0", &r0);
+ collect_register_by_name ("orig_r3", &r3);
+ collect_register_by_name ("r4", &r4);
+ curr_pc = (CORE_ADDR) pc;
+ curr_r0 = (int) r0;
+ *fd = (int) r3;
+ *addr = (CORE_ADDR) r4;
+ }
+ else
+ {
+ unsigned long pc, r0, r3, r4;
+ collect_register_by_name ("pc", &pc);
+ collect_register_by_name ("r0", &r0);
+ collect_register_by_name ("orig_r3", &r3);
+ collect_register_by_name ("r4", &r4);
+ curr_pc = (CORE_ADDR) pc;
+ curr_r0 = (int) r0;
+ *fd = (int) r3;
+ *addr = (CORE_ADDR) r4;
+ }
+
+ /* Fetch instruction preceding current NIP. */
+ if ((*the_target->read_memory) (curr_pc - 4,
+ (unsigned char *) &curr_insn, 4) != 0)
+ return 0;
+ /* It should be a "sc" instruction. */
+ if (curr_insn != INSTR_SC)
+ return 0;
+ /* System call number should be NR_spu_run. */
+ if (curr_r0 != NR_spu_run)
+ return 0;
+
+ return 1;
+}
+
static CORE_ADDR
ppc_get_pc (void)
{
- if (register_size (0) == 4)
+ CORE_ADDR addr;
+ int fd;
+
+ if (parse_spufs_run (&fd, &addr))
+ {
+ unsigned int pc;
+ (*the_target->read_memory) (addr, (unsigned char *) &pc, 4);
+ return ((CORE_ADDR)1 << 63) | ((CORE_ADDR)fd << 32) | (CORE_ADDR) (pc - 4);
+ }
+ else if (register_size (0) == 4)
{
unsigned int pc;
collect_register_by_name ("pc", &pc);
@@ -211,7 +273,15 @@ ppc_get_pc (void)
static void
ppc_set_pc (CORE_ADDR pc)
{
- if (register_size (0) == 4)
+ CORE_ADDR addr;
+ int fd;
+
+ if (parse_spufs_run (&fd, &addr))
+ {
+ unsigned int newpc = pc;
+ (*the_target->write_memory) (addr, (unsigned char *) &newpc, 4);
+ }
+ else if (register_size (0) == 4)
{
unsigned int newpc = pc;
supply_register_by_name ("pc", &newpc);
@@ -355,11 +425,24 @@ ppc_breakpoint_at (CORE_ADDR where)
{
unsigned int insn;
- (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
- if (insn == ppc_breakpoint)
- return 1;
- /* If necessary, recognize more trap instructions here. GDB only uses the
- one. */
+ if (where & ((CORE_ADDR)1 << 63))
+ {
+ char mem_annex[32];
+ sprintf (mem_annex, "%d/mem", (int)((where >> 32) & 0x7fffffff));
+ (*the_target->qxfer_spu) (mem_annex, (unsigned char *) &insn,
+ NULL, where & 0xffffffff, 4);
+ if (insn == 0x3fff)
+ return 1;
+ }
+ else
+ {
+ (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
+ if (insn == ppc_breakpoint)
+ return 1;
+ /* If necessary, recognize more trap instructions here. GDB only uses
+ the one. */
+ }
+
return 0;
}