This is the mail archive of the
rda@sourceware.org
mailing list for the rda project.
[PATCH] Add support for am33 linux
- From: Kevin Buettner <kevinb at redhat dot com>
- To: rda at sources dot redhat dot com
- Date: Tue, 23 Aug 2005 18:15:53 -0700
- Subject: [PATCH] Add support for am33 linux
- Organization: Red Hat
I've just committed the patch below.
* configure.in (am33_2.0*linux*): New target.
* Makefile.in: Regenerate.
* aclocal.m4: Regenerate.
* config.in: Regenerate.
* configure: Regenerate.
* gdbserv-thread-db.h (mips_singlestep): Change return type to
``void''.
(am33_singlestep): New declaration.
* linux-target.c [AM33_2_0_LINUX_TARGET]
(GETREGS_SETREGS_REGINFO, SOFTWARE_SINGLESTEP, PC_REGNUM, A0_REGNUM)
(A1_REGNUM, A2_REGNUM, A3_REGNUM, LAR_REGNUM, MDR_REGNUM, SP_REGNUM)
(NUM_REGS, sign_extend): Define.
(PT_A3, PT_A2, PT_D3, PT_D2, PT_MCVF, PT_MCRL, PT_MCRH, PT_MDRQ)
(PT_E1, PT_E0, PT_E7, PT_E6, PT_E5, PT_E4, PT_E3, PT_E2, PT_SP)
(PT_LAR, PT_LIR, PT_MDR, PT_A1, PT_A0, PT_D1, PT_D0, PT_ORIG_D0)
(PT_EPSW, PT_PC): Define.
(reginfo): New table.
(stock_table_to_am33, am33_table_to_stock, stock_bp_to_am33)
(am33_bp_to_stock, am33_make_bp_table, am33_set_bp, am33_delete_bp)
(am33_bp_hit_p, am33_make_arch): New functions.
(MAKE_ARCH): Define.
(am33_singlestep_program, am33_read_byte, am33_read_disp16)
(am33_read_disp32, am33_get_register, am33_get_areg, am33_singlestep):
New functions.
(am33_opcode_size): New table.
[MIPS_LINUX_TARGET | MIPS64_LINUX_TARGET] (SOFTWARE_SINGLESTEP):
Define.
(linux_attach): Set am33 specific ``singlestep_program''. Revise
proprocessor condition upon which ``is_ss'' is set.
[SOFTWARE_SINGLESTEP] (set_singlestep_breakpoint): New function.
(mips_get_reg, mips_poke_instruction): Delete.
(mips_singlestep): Adjust return type. Use set_singlestep_breakpoint()
where appropriate.
* ptrace-target.c (handle_waitstatus): Adjust call to ptrace_set_mem()
to account for different type of singlestep breakpoint shadow value.
Also, pass the stored breakpoint size. Add diagnostics.
(ptrace_attach): Add AM33_2_0_LINUX_TARGET to list of targets needing
to clear ``is_ss''.
(singlestep_lwp): Add code to call am33 specific singlestep code.
* server.h (struct ss_save): Add AM33_2_0_LINUX_TARGET to the list
of preprocessor conditions which declare this struct. Revise type
of ``ss_val'' from ``int'' to a ``char'' array. Add new field
``ss_size''.
(struct child_process): Define fields ``is_ss'' and ``ss_info'' for
AM33_2_0_LINUX_TARGET.
Index: configure.in
===================================================================
RCS file: /cvs/src/src/rda/unix/configure.in,v
retrieving revision 1.8
diff -u -p -r1.8 configure.in
--- configure.in 30 Jun 2005 03:24:18 -0000 1.8
+++ configure.in 24 Aug 2005 01:12:08 -0000
@@ -64,6 +64,16 @@ AH_TEMPLATE(PTRACE_XFER_TYPE_LONG_LONG,
[Define if ptrace transfer type is long long or unsigned long long.])
case "$target" in
+ am33_2.0*linux*)
+ TARGET_MODULES="linux-target.o thread-db.o lwp-pool.o ptrace-target.o"
+ AC_DEFINE(LINUX_TARGET)
+ AC_DEFINE(GREGSET_T, prgregset_t)
+ AC_DEFINE(HAVE_LWPID_T)
+ AC_DEFINE(HAVE_PSADDR_T)
+ AC_DEFINE(HAVE_PRGREGSET_T)
+ AC_DEFINE(FPREGSET_T, prfpregset_t)
+ AC_DEFINE(HAVE_PRFPREGSET_T)
+ ;;
mips64*linux*)
TARGET_MODULES="linux-target.o thread-db.o lwp-pool.o ptrace-target.o"
AC_DEFINE(LINUX_TARGET)
@@ -110,7 +120,7 @@ esac
# Some architectures use the stock breakpoint model.
case "$target" in
- i?86*linux* | frv*linux*)
+ i?86*linux* | frv*linux* | am33*linux*)
TARGET_MODULES="$TARGET_MODULES stock-breakpoints.o"
AC_DEFINE(STOCK_BREAKPOINTS, [1],
[Define if the target uses the stock-breakpoints.o module.])
@@ -120,6 +130,16 @@ esac
AC_SUBST(TARGET_MODULES)
case "$target" in
+ am33_2.0*linux*)
+ AC_DEFINE(AM33_2_0_LINUX_TARGET, [1],
+ [Define if target is am33 Linux.])
+ AC_DEFINE(PTRACE_XFER_SIZE, 4)
+ AC_DEFINE(PTRACE_XFER_TYPE_LONG)
+ AC_DEFINE(PTRACE_ARG1_TYPE_LONG)
+ AC_DEFINE(PTRACE_ARG2_TYPE_LONG)
+ AC_DEFINE(PTRACE_ARG3_TYPE_LONG)
+ AC_DEFINE(PTRACE_ARG4_TYPE_LONG)
+ ;;
*solaris*)
dnl FIXME: differentiate between flavors of Solaris!
AC_DEFINE(SPARC32_SOLARIS_TARGET, [1],
Index: gdbserv-thread-db.h
===================================================================
RCS file: /cvs/src/src/rda/unix/gdbserv-thread-db.h,v
retrieving revision 1.5
diff -u -p -r1.5 gdbserv-thread-db.h
--- gdbserv-thread-db.h 23 Aug 2005 23:22:17 -0000 1.5
+++ gdbserv-thread-db.h 24 Aug 2005 01:12:08 -0000
@@ -86,8 +86,12 @@ extern int reg_from_xregset (struct gdbs
/* Software singlestep for mips. */
#if defined (MIPS_LINUX_TARGET) || defined (MIPS64_LINUX_TARGET)
-extern int mips_singlestep (struct gdbserv *serv, pid_t pid, int sig);
+extern void mips_singlestep (struct gdbserv *serv, pid_t pid, int sig);
#endif
+#if defined (AM33_2_0_LINUX_TARGET)
+extern void am33_singlestep (struct gdbserv *serv, pid_t pid, int sig);
+#endif
+
/* Fetch the value of PC for debugging purposes. */
extern unsigned long debug_get_pc (struct gdbserv *serv, pid_t pid);
Index: linux-target.c
===================================================================
RCS file: /cvs/src/src/rda/unix/linux-target.c,v
retrieving revision 1.18
diff -u -p -r1.18 linux-target.c
--- linux-target.c 23 Aug 2005 23:22:17 -0000 1.18
+++ linux-target.c 24 Aug 2005 01:12:08 -0000
@@ -482,6 +482,242 @@ x86_make_arch (void)
/* End of X86_LINUX_TARGET */
+#elif defined (AM33_2_0_LINUX_TARGET) || defined (AM33_LINUX_TARGET)
+
+/* AM33 needs to use PTRACE_GETREGS / PTRACE_SETREGS, PTRACE_GETFPREGS /
+ PTRACE_SETFPREGS in order to access all of the registers. */
+#define GETREGS_SETREGS_REGINFO 1
+#define SOFTWARE_SINGLESTEP 1
+
+enum
+{
+ PC_REGNUM = 9,
+ A0_REGNUM = 4,
+ A1_REGNUM = 5,
+ A2_REGNUM = 6,
+ A3_REGNUM = 7,
+ LAR_REGNUM = 13,
+ MDR_REGNUM = 10,
+ SP_REGNUM = 8,
+ NUM_REGS = 64,
+ sign_extend=0
+};
+
+/* These should match the constants defined in <asm/ptrace.h> */
+#define PT_A3 0
+#define PT_A2 1
+#define PT_D3 2
+#define PT_D2 3
+#define PT_MCVF 4
+#define PT_MCRL 5
+#define PT_MCRH 6
+#define PT_MDRQ 7
+#define PT_E1 8
+#define PT_E0 9
+#define PT_E7 10
+#define PT_E6 11
+#define PT_E5 12
+#define PT_E4 13
+#define PT_E3 14
+#define PT_E2 15
+#define PT_SP 16
+#define PT_LAR 17
+#define PT_LIR 18
+#define PT_MDR 19
+#define PT_A1 20
+#define PT_A0 21
+#define PT_D1 22
+#define PT_D0 23
+#define PT_ORIG_D0 24
+#define PT_EPSW 25
+#define PT_PC 26
+
+static struct getregs_setregs_reginfo reginfo[] =
+{
+ { GREGS, PT_D0 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_D1 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_D2 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_D3 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_A0 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_A1 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_A2 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_A3 * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_SP * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_PC * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_MDR * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_EPSW * 4, sizeof (greg_t), 4 }, /* psw */
+ { GREGS, PT_LIR * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_LAR * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_MDRQ * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_E0 * 4, sizeof (greg_t), 4 }, /* r0 */
+ { GREGS, PT_E1 * 4, sizeof (greg_t), 4 }, /* r1 */
+ { GREGS, PT_E2 * 4, sizeof (greg_t), 4 }, /* r2 */
+ { GREGS, PT_E3 * 4, sizeof (greg_t), 4 }, /* r3 */
+ { GREGS, PT_E4 * 4, sizeof (greg_t), 4 }, /* r4 */
+ { GREGS, PT_E5 * 4, sizeof (greg_t), 4 }, /* r5 */
+ { GREGS, PT_E6 * 4, sizeof (greg_t), 4 }, /* r6 */
+ { GREGS, PT_E7 * 4, sizeof (greg_t), 4 }, /* r7 */
+ { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, /* ssp */
+ { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, /* msp */
+ { GREGS, PT_SP * 4, sizeof (greg_t), 4 }, /* usp */
+ { GREGS, PT_MCRH * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_MCRL * 4, sizeof (greg_t), 4 },
+ { GREGS, PT_MCVF * 4, sizeof (greg_t), 4 },
+
+ /* AM33 uses single precision floating point registers where two
+ consecutive registers are combined to form a double. The
+ register layout is defined (in the kernel sources) in
+ include/asm-mn10300/processor.h. Unfortunately, this file is not
+ easily included, so we'll use hard coded constants for the
+ offsets and sizes... */
+
+ { FPREGS, 32 * 4, 4, 4 }, /* fpcr */
+
+ /* The "g" packet has a gap between fpcr and fs0. */
+ { NOREGS, 0, 0, 4 },
+ { NOREGS, 0, 0, 4 },
+
+ { FPREGS, 0 * 4, 4, 4 }, /* fs0 */
+ { FPREGS, 1 * 4, 4, 4 }, /* fs1 ... */
+ { FPREGS, 2 * 4, 4, 4 },
+ { FPREGS, 3 * 4, 4, 4 },
+ { FPREGS, 4 * 4, 4, 4 },
+ { FPREGS, 5 * 4, 4, 4 },
+ { FPREGS, 6 * 4, 4, 4 },
+ { FPREGS, 7 * 4, 4, 4 },
+ { FPREGS, 8 * 4, 4, 4 },
+ { FPREGS, 9 * 4, 4, 4 },
+ { FPREGS, 10 * 4, 4, 4 },
+ { FPREGS, 11 * 4, 4, 4 },
+ { FPREGS, 12 * 4, 4, 4 },
+ { FPREGS, 13 * 4, 4, 4 },
+ { FPREGS, 14 * 4, 4, 4 },
+ { FPREGS, 15 * 4, 4, 4 },
+ { FPREGS, 16 * 4, 4, 4 },
+ { FPREGS, 17 * 4, 4, 4 },
+ { FPREGS, 18 * 4, 4, 4 },
+ { FPREGS, 19 * 4, 4, 4 },
+ { FPREGS, 20 * 4, 4, 4 },
+ { FPREGS, 21 * 4, 4, 4 },
+ { FPREGS, 22 * 4, 4, 4 },
+ { FPREGS, 23 * 4, 4, 4 },
+ { FPREGS, 24 * 4, 4, 4 },
+ { FPREGS, 25 * 4, 4, 4 },
+ { FPREGS, 26 * 4, 4, 4 },
+ { FPREGS, 27 * 4, 4, 4 },
+ { FPREGS, 28 * 4, 4, 4 },
+ { FPREGS, 29 * 4, 4, 4 },
+ { FPREGS, 30 * 4, 4, 4 },
+ { FPREGS, 31 * 4, 4, 4 } /* fs31 */
+};
+
+static void am33_singlestep_program (struct gdbserv *serv);
+
+/* Breakpoint methods for the am33. Except for bp_hit_p, these
+ are just wrappers for the stock breakpoint methods. In C++, we
+ could use multiple inheritance for this, and it would all just
+ work... */
+
+/* am33 breakpoints tables are just stock breakpoint tables. But we
+ like static typechecking; casts swallow error messages. */
+static struct arch_bp_table *
+stock_table_to_am33 (struct stock_bp_table *table)
+{
+ return (struct arch_bp_table *) table;
+}
+
+static struct stock_bp_table *
+am33_table_to_stock (struct arch_bp_table *table)
+{
+ return (struct stock_bp_table *) table;
+}
+
+/* am33 breakpoints are just stock breakpoints. But we like static
+ typechecking; casts swallow error messages. */
+static struct arch_bp *
+stock_bp_to_am33 (struct stock_bp *bp)
+{
+ return (struct arch_bp *) bp;
+}
+
+static struct stock_bp *
+am33_bp_to_stock (struct arch_bp *bp)
+{
+ return (struct stock_bp *) bp;
+}
+
+struct arch_bp_table *
+am33_make_bp_table (struct arch *arch,
+ struct gdbserv *serv,
+ struct gdbserv_target *target)
+{
+ struct stock_bp_table *table = stock_bp_make_table (serv, target);
+
+ /* Use 0xff as the breakpoint instruction. */
+ stock_bp_set_bp_insn (table, 1, "\xff");
+
+ return stock_table_to_am33 (table);
+}
+
+
+static struct arch_bp *
+am33_set_bp (struct arch_bp_table *table,
+ struct gdbserv_reg *addr)
+{
+ /* am33 arch breakpoints are just stock breakpoints. */
+ return stock_bp_to_am33 (stock_bp_set_bp (am33_table_to_stock (table),
+ addr));
+}
+
+
+static int
+am33_delete_bp (struct arch_bp *bp)
+{
+ return stock_bp_delete_bp (am33_bp_to_stock (bp));
+}
+
+
+static int
+am33_bp_hit_p (struct gdbserv_thread *thread,
+ struct arch_bp *arch_bp)
+{
+ struct stock_bp *bp = am33_bp_to_stock (arch_bp);
+ struct stock_bp_table *table = stock_bp_table (bp);
+ struct gdbserv *serv = stock_bp_table_serv (table);
+ struct gdbserv_target *target = stock_bp_table_target (table);
+ struct gdbserv_reg bp_addr, pc;
+ unsigned long bp_addr_int, pc_int;
+
+ stock_bp_addr (&bp_addr, bp);
+ gdbserv_reg_to_ulong (serv, &bp_addr, &bp_addr_int);
+ target->get_thread_reg (serv, thread, PC_REGNUM, &pc);
+ gdbserv_reg_to_ulong (serv, &pc, &pc_int);
+
+ /* When the am33 hits a breakpoint, the reported PC value is equal to
+ address of the breakpoint. */
+ return bp_addr_int == pc_int;
+}
+
+
+/* Construct an architecture object for the am33. */
+static struct arch *
+am33_make_arch (void)
+{
+ struct arch *a = allocate_empty_arch ();
+
+ a->closure = 0; /* No closure needed at the moment. */
+ a->make_bp_table = am33_make_bp_table;
+ a->set_bp = am33_set_bp;
+ a->delete_bp = am33_delete_bp;
+ a->bp_hit_p = am33_bp_hit_p;
+
+ return a;
+}
+
+#define MAKE_ARCH() (am33_make_arch ())
+
+/* End of AM33_LINUX_TARGET */
+
#elif defined (SH_LINUX_TARGET)
/* Needs to be converted to use either GETREGS_SETREGS_REGINFO or
@@ -529,6 +765,7 @@ is_extended_reg (int regnum)
#elif defined MIPS_LINUX_TARGET || (defined MIPS64_LINUX_TARGET && defined MIPS_ABI_O32)
#define PEEKUSER_POKEUSER_REGINFO 1
+#define SOFTWARE_SINGLESTEP 1
enum
{
@@ -682,6 +919,7 @@ static void mips_singlestep_program (str
#elif defined(MIPS64_LINUX_TARGET)
#define PEEKUSER_POKEUSER_REGINFO 1
+#define SOFTWARE_SINGLESTEP 1
enum
{
@@ -2969,6 +3207,8 @@ linux_attach (struct gdbserv *serv, void
linux_target->restart_program = NULL;
#if defined(_MIPSEL) || defined(_MIPSEB)
linux_target->singlestep_program = mips_singlestep_program;
+#elif defined(AM33_2_0_LINUX_TARGET)
+ linux_target->singlestep_program = am33_singlestep_program;
#else
linux_target->singlestep_program = ptrace_target->singlestep_program;
#endif
@@ -2996,7 +3236,7 @@ linux_attach (struct gdbserv *serv, void
else
process->breakpoint_table = 0;
-#if defined(_MIPSEL) || defined(_MIPSEB)
+#if defined(SOFTWARE_SINGLESTEP)
process->is_ss = 0;
#endif
@@ -3091,23 +3331,57 @@ decr_pc_after_break (struct gdbserv *ser
}
#endif
+#ifdef SOFTWARE_SINGLESTEP
-#if defined(_MIPSEL) || defined(_MIPSEB)
-
-/*
- * Worker function to get and return a register
- */
+/* Set a software-singlestep breakpoint. */
-static ptrace_xfer_type
-mips_get_reg(struct gdbserv *serv, int pid, int regno)
+static void
+set_singlestep_breakpoint (struct gdbserv *serv, ptrace_arg3_type addr,
+ char *breakpoint_bytes, int breakpoint_length)
{
- ptrace_xfer_type value;
+ int i = 0;
+ struct child_process *process = gdbserv_target_data (serv);
- if (read_reg_bytes (serv, pid, regno, &value) < 0)
- return 0;
- else
- return value;
+ if (process->ss_info[i].in_use)
+ i++;
+
+ assert (!process->ss_info[i].in_use);
+
+ /* set flag so handle_waitstatus can restore breakpoint stuff */
+ process->is_ss = 1;
+
+ /* Mark the breakpoint used. */
+ process->ss_info[i].in_use = 1;
+
+ /* Convert ``addr'' to a struct gdbserv_reg. */
+ gdbserv_host_bytes_to_reg (serv,
+ &addr,
+ sizeof (addr),
+ &process->ss_info[i].ss_addr,
+ sizeof (ptrace_arg3_type),
+ sign_extend);
+
+ /* Set the breakpoint size. */
+ process->ss_info[i].ss_size = breakpoint_length;
+
+ /* Fetch the contents of the memory at which the breakpoint will be
+ placed. */
+ ptrace_get_mem (serv,
+ &process->ss_info[i].ss_addr,
+ process->ss_info[i].ss_val,
+ process->ss_info[i].ss_size);
+
+ /* Finally, set the breakpoint! */
+ ptrace_set_mem (serv,
+ &process->ss_info[i].ss_addr,
+ breakpoint_bytes,
+ process->ss_info[i].ss_size);
+ if (process->debug_backend)
+ fprintf (stderr, "Singlestep breakpoint %d set at location %lx\n", i, addr);
}
+#endif /* SOFTWARE_SINGLESTEP */
+
+#if defined(_MIPSEL) || defined(_MIPSEB)
static struct gdbserv_reg
mips_addr_as_reg (struct gdbserv *serv, ptrace_arg3_type addr)
@@ -3134,21 +3408,13 @@ mips_peek_instruction (struct gdbserv *s
return insn;
}
-static void
-mips_poke_instruction (struct gdbserv *serv, ptrace_arg3_type addr,
- unsigned int insn)
-{
- struct gdbserv_reg addr_as_reg;
-
- addr_as_reg = mips_addr_as_reg (serv, addr);
- ptrace_set_mem (serv, &addr_as_reg, &insn, sizeof (insn));
-}
-
/*
* mips singlestep
*
* necessary since no support in ptrace.
*/
+void mips_singlestep (struct gdbserv *serv, pid_t pid, int sig);
+
static void
mips_singlestep_program (struct gdbserv *serv)
{
@@ -3160,12 +3426,11 @@ mips_singlestep_program (struct gdbserv
process->signal_to_send = 0;
}
-int
+void
mips_singlestep (struct gdbserv *serv, pid_t pid, int sig)
{
struct child_process *process = gdbserv_target_data (serv);
- ptrace_arg3_type targ;
- ptrace_xfer_type mips_pc;
+ ptrace_xfer_type targ, mips_pc;
union mips_instruction insn;
int is_branch, is_cond, i;
@@ -3181,7 +3446,7 @@ mips_singlestep (struct gdbserv *serv, p
/* Following is equiv to ptrace (PTRACE_SINGLESTEP, pid, 1L, sig); */
/* get the current PC */
- mips_pc = mips_get_reg(serv, pid, PC_REGNUM);
+ mips_pc = debug_get_reg(serv, pid, PC_REGNUM);
targ = mips_pc;
/* get the word there (opcode) */
@@ -3190,9 +3455,6 @@ mips_singlestep (struct gdbserv *serv, p
is_branch = is_cond = 0;
- /* set flag so handle_waitstatus can restore breakpoint stuff */
- process->is_ss = 1;
-
switch (insn.i_format.opcode) {
/*
* jr and jalr are in r_format format.
@@ -3201,7 +3463,7 @@ mips_singlestep (struct gdbserv *serv, p
switch (insn.r_format.func) {
case jalr_op:
case jr_op:
- targ = mips_get_reg(serv, pid, insn.r_format.rs);
+ targ = debug_get_reg(serv, pid, insn.r_format.rs);
is_branch = 1;
break;
}
@@ -3271,30 +3533,368 @@ mips_singlestep (struct gdbserv *serv, p
i = 0;
if (is_cond && targ != (mips_pc + 8))
{
- process->ss_info[i].in_use = 1;
- process->ss_info[i].ss_addr = mips_addr_as_reg (serv, mips_pc + 8);
- process->ss_info[i++].ss_val
- = mips_peek_instruction (serv, mips_pc + 8);
- mips_poke_instruction (serv, mips_pc + 8, bp_inst);
+ set_singlestep_breakpoint (serv, mips_pc + 8, &bp_inst,
+ sizeof (bp_inst));
}
- process->ss_info[i].in_use = 1;
- process->ss_info[i].ss_addr = mips_addr_as_reg (serv, targ);
- process->ss_info[i].ss_val = mips_peek_instruction (serv, targ);
- mips_poke_instruction (serv, targ, bp_inst);
+ set_singlestep_breakpoint (serv, targ, &bp_inst,
+ sizeof (bp_inst));
}
else
{
- process->ss_info[0].in_use = 1;
- process->ss_info[0].ss_addr = mips_addr_as_reg (serv, mips_pc + 4);
- process->ss_info[0].ss_val = mips_peek_instruction (serv, mips_pc + 4);
- mips_poke_instruction (serv, mips_pc + 4, bp_inst);
+ set_singlestep_breakpoint (serv, mips_pc + 4, &bp_inst,
+ sizeof (bp_inst));
}
ptrace (PTRACE_CONT, pid, 1L, sig);
- return 0;
}
#endif /* _MIPSEL */
+#if defined (AM33_2_0_LINUX_TARGET)
+/* AM33 single-step support. Lifted from Redboot which was in turn
+ lifted from Cygmon. */
+
+void am33_singlestep (struct gdbserv *serv, pid_t pid, int sig);
+
+static void
+am33_singlestep_program (struct gdbserv *serv)
+{
+ struct child_process *process = gdbserv_target_data (serv);
+
+ am33_singlestep (serv, process->pid, process->signal_to_send);
+ process->stop_signal = 0;
+ process->stop_status = 0;
+ process->signal_to_send = 0;
+}
+
+/* Read a 16-bit displacement from address 'addr'. */
+static unsigned char
+am33_read_byte(struct gdbserv *serv, ptrace_arg3_type addr)
+{
+ unsigned char val;
+ struct gdbserv_reg addr_as_reg;
+
+ gdbserv_host_bytes_to_reg (serv, &addr, sizeof (addr),
+ &addr_as_reg, sizeof (ptrace_arg3_type),
+ sign_extend);
+ ptrace_get_mem (serv, &addr_as_reg, &val, sizeof (val));
+
+ return val;
+}
+
+static short
+am33_read_disp16(struct gdbserv *serv, ptrace_arg3_type addr)
+{
+ short val;
+ struct gdbserv_reg addr_as_reg;
+
+ gdbserv_host_bytes_to_reg (serv, &addr, sizeof (addr),
+ &addr_as_reg, sizeof (ptrace_arg3_type),
+ sign_extend);
+ ptrace_get_mem (serv, &addr_as_reg, &val, sizeof (val));
+
+ return val;
+}
+
+/* Read a 32-bit displacement from address 'p'. The
+ value is stored little-endian. */
+
+static long
+am33_read_disp32(struct gdbserv *serv, ptrace_arg3_type addr)
+{
+ long val;
+ struct gdbserv_reg addr_as_reg;
+
+ gdbserv_host_bytes_to_reg (serv, &addr, sizeof (addr),
+ &addr_as_reg, sizeof (ptrace_arg3_type),
+ sign_extend);
+ ptrace_get_mem (serv, &addr_as_reg, &val, sizeof (val));
+
+ return val;
+}
+
+static ptrace_arg3_type
+am33_get_register (struct gdbserv *serv, pid_t pid, int regno)
+{
+ return debug_get_reg (serv, pid, regno);
+}
+
+
+/* Get the contents of An register. */
+
+static unsigned int
+am33_get_areg (struct gdbserv *serv, pid_t pid, int n)
+{
+ switch (n)
+ {
+ case 0:
+ return am33_get_register (serv, pid, A0_REGNUM);
+ case 1:
+ return am33_get_register (serv, pid, A1_REGNUM);
+ case 2:
+ return am33_get_register (serv, pid, A2_REGNUM);
+ case 3:
+ return am33_get_register (serv, pid, A3_REGNUM);
+ }
+ return 0;
+}
+
+
+/* Table of instruction sizes, indexed by first byte of instruction,
+ used to determine the address of the next instruction for single stepping.
+ If an entry is zero, special code must handle the case (for example,
+ branches or multi-byte opcodes). */
+
+static char am33_opcode_size[256] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /*------------------------------------------------*/
+/* 0 */ 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3,
+/* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 2 */ 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
+/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1,
+/* 4 */ 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2,
+/* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+/* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 8 */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
+/* 9 */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
+/* a */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
+/* b */ 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
+/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2,
+/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* e */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* f */ 0, 2, 2, 2, 2, 2, 2, 1, 0, 3, 0, 4, 0, 6, 7, 1
+};
+
+/* Set breakpoint(s) to simulate a single step from the current PC. */
+
+void
+am33_singlestep (struct gdbserv *serv, pid_t pid, int sig)
+{
+ struct child_process *process = gdbserv_target_data (serv);
+ ptrace_arg3_type pc;
+ unsigned int opcode;
+ int displ;
+ static char bp_inst = 0xff;
+ static int hw_singlestep_okay = 1;
+
+ if (hw_singlestep_okay)
+ {
+ if (process->debug_backend)
+ fprintf (stderr, "PTRACE_SINGLESTEP (am33): pid=%d signal=%d\n",
+ pid, sig);
+ errno = 0;
+ ptrace (PTRACE_SINGLESTEP, pid, 1L, sig);
+ if (errno == 0)
+ return;
+ /* EINVAL is the expected error when the kernel doesn't support
+ PTRACE_SINGLESTEP. Report all other errors. */
+ if (errno != EINVAL)
+ fprintf (stderr, "PTRACE_SINGLESTEP (am33) error: %s in %d\n",
+ strerror (errno), pid);
+ else
+ {
+ if (process->debug_backend)
+ fprintf (stderr,
+ "Disabling use of PTRACE_SINGLESTEP: It's not supported by this kernel.\n");
+ hw_singlestep_okay = 0;
+ }
+ /* Fall through into software singlestep code. */
+ }
+
+ pc = am33_get_register (serv, pid, PC_REGNUM);
+ opcode = am33_read_byte (serv, pc);
+
+ /* Check the table for the simple cases. */
+ displ = am33_opcode_size[opcode];
+ if (displ != 0)
+ {
+ set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst));
+ }
+ else
+
+ /* Handle the more complicated cases. */
+ switch (opcode)
+ {
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ /*
+ * bxx (d8,PC)
+ */
+ displ = (signed char) am33_read_byte (serv, pc + 1);
+ set_singlestep_breakpoint (serv, pc + 2, &bp_inst, sizeof (bp_inst));
+ if (displ < 0 || displ > 2)
+ set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ /*
+ * lxx (d8,PC)
+ */
+ if (pc != am33_get_register (serv, pid, LAR_REGNUM))
+ set_singlestep_breakpoint (serv,
+ am33_get_register (serv, pid, LAR_REGNUM),
+ &bp_inst, sizeof (bp_inst));
+ set_singlestep_breakpoint (serv, pc + 1, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xdb:
+ /*
+ * setlb requires special attention. It loads the next four instruction
+ * bytes into the LIR register, so we can't insert a breakpoint in any
+ * of those locations.
+ */
+ set_singlestep_breakpoint (serv, pc + 5, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xcc:
+ case 0xcd:
+ /*
+ * jmp (d16,PC) or call (d16,PC)
+ */
+ displ = am33_read_disp16(serv, pc + 1);
+ set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xdc:
+ case 0xdd:
+ /*
+ * jmp (d32,PC) or call (d32,PC)
+ */
+ displ = am33_read_disp32(serv, pc + 1);
+ set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xde:
+ /*
+ * retf
+ */
+ set_singlestep_breakpoint (serv, am33_get_register (serv, pid, MDR_REGNUM),
+ &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xdf:
+ /*
+ * ret
+ */
+ displ = (signed char) am33_read_byte (serv, pc + 2);
+ set_singlestep_breakpoint (
+ serv,
+ am33_read_disp32 (serv,
+ am33_get_register (serv, pid, SP_REGNUM) + displ),
+ &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xf0:
+ /*
+ * Some branching 2-byte instructions.
+ */
+ opcode = am33_read_byte (serv, pc + 1);
+ if (opcode >= 0xf0 && opcode <= 0xf7)
+ {
+ /* jmp (An) / calls (An) */
+ set_singlestep_breakpoint (serv,
+ am33_get_areg (serv, pid, opcode & 3),
+ &bp_inst, sizeof (bp_inst));
+
+ }
+ else if (opcode == 0xfc)
+ {
+ /* rets */
+ set_singlestep_breakpoint (
+ serv,
+ am33_read_disp32 (serv, am33_get_register (serv, pid, SP_REGNUM)),
+ &bp_inst, sizeof (bp_inst));
+
+ }
+ else if (opcode == 0xfd)
+ {
+ /* rti */
+ set_singlestep_breakpoint (
+ serv,
+ am33_read_disp32 (serv,
+ am33_get_register (serv, pid, SP_REGNUM) + 4),
+ &bp_inst, sizeof (bp_inst));
+
+ }
+ else
+ set_singlestep_breakpoint (serv, pc + 2, &bp_inst, sizeof (bp_inst));
+
+ break;
+
+ case 0xf8:
+ /*
+ * Some branching 3-byte instructions.
+ */
+ opcode = am33_read_byte (serv, pc + 1);
+ if (opcode >= 0xe8 && opcode <= 0xeb)
+ {
+ displ = (signed char) am33_read_byte (serv, pc + 2);
+ set_singlestep_breakpoint (serv, pc + 3, &bp_inst, sizeof (bp_inst));
+ if (displ < 0 || displ > 3)
+ set_singlestep_breakpoint (serv, pc + displ,
+ &bp_inst, sizeof (bp_inst));
+
+ }
+ else
+ set_singlestep_breakpoint (serv, pc + 3, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xfa:
+ opcode = am33_read_byte (serv, pc + 1);
+ if (opcode == 0xff)
+ {
+ /* calls (d16,PC) */
+ displ = am33_read_disp16 (serv, pc + 2);
+ set_singlestep_breakpoint (serv, pc + displ,
+ &bp_inst, sizeof (bp_inst));
+ }
+ else
+ set_singlestep_breakpoint (serv, pc + 4, &bp_inst, sizeof (bp_inst));
+ break;
+
+ case 0xfc:
+ opcode = am33_read_byte (serv, pc + 1);
+ if (opcode == 0xff)
+ {
+ /* calls (d32,PC) */
+ displ = am33_read_disp32 (serv, pc + 2);
+ set_singlestep_breakpoint (serv, pc + displ, &bp_inst, sizeof (bp_inst));
+ }
+ else
+ set_singlestep_breakpoint (serv, pc + 6, &bp_inst, sizeof (bp_inst));
+ break;
+
+ }
+
+ if (process->debug_backend)
+ fprintf (stderr, "PTRACE_CONT (am33): pid=%d signal=%d\n", pid, sig);
+ errno = 0;
+ ptrace (PTRACE_CONT, pid, 0, sig);
+ if (errno)
+ fprintf (stderr, "PTRACE_CONT (am33) error: %s in %d\n",
+ strerror (errno), pid);
+}
+#endif
/* proc_service callback functions */
Index: ptrace-target.c
===================================================================
RCS file: /cvs/src/src/rda/unix/ptrace-target.c,v
retrieving revision 1.9
diff -u -p -r1.9 ptrace-target.c
--- ptrace-target.c 30 Jun 2005 03:24:18 -0000 1.9
+++ ptrace-target.c 24 Aug 2005 01:12:08 -0000
@@ -161,7 +161,7 @@ handle_waitstatus (struct child_process
return (process->stop_signal = WTERMSIG (w));
}
-#if defined(_MIPSEL) || defined(_MIPSEB)
+#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET)
/*
* If we were single_stepping, restore the opcodes hoisted
* for the breakpoint[s].
@@ -174,9 +174,19 @@ handle_waitstatus (struct child_process
{
ptrace_set_mem (process->serv,
&process->ss_info[i].ss_addr,
- &process->ss_info[i].ss_val,
- sizeof (process->ss_info[i].ss_val));
+ process->ss_info[i].ss_val,
+ process->ss_info[i].ss_size);
process->ss_info[i].in_use = 0;
+ if (process->debug_backend)
+ {
+ long addr;
+ gdbserv_host_bytes_from_reg (process->serv, &addr,
+ sizeof (addr),
+ &process->ss_info[i].ss_addr, 0);
+ fprintf (stderr,
+ "Singlestep breakpoint %d cleared at location %lx\n",
+ i, addr);
+ }
}
process->is_ss = 0;
}
@@ -1239,7 +1249,7 @@ ptrace_attach (struct gdbserv *serv, voi
ptrace_target->data = data; /* Save ptr to child_process struct. */
-#if defined(_MIPSEL) || defined(_MIPSEB)
+#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET)
process->is_ss = 0;
#endif
@@ -1288,13 +1298,15 @@ int
singlestep_lwp (struct gdbserv *serv, pid_t lwp, int signal)
{
-#if defined (MIPS_LINUX_TARGET) || defined (MIPS64_LINUX_TARGET)
- {
- if (thread_db_noisy)
- fprintf (stderr, "<singlestep_lwp lwp=%d signal=%d>\n", lwp, signal);
- mips_singlestep (serv, lwp, signal);
- return 0;
- }
+#if defined (AM33_2_0_LINUX_TARGET)
+ if (thread_db_noisy)
+ fprintf (stderr, "<singlestep_lwp lwpid=%d signal=%d>\n", lwp, signal);
+ am33_singlestep (serv, lwp, signal);
+ return 0;
+#elif defined (MIPS_LINUX_TARGET) || defined (MIPS64_LINUX_TARGET)
+ if (thread_db_noisy)
+ fprintf (stderr, "<singlestep_lwp lwpid=%d signal=%d>\n", lwp, signal);
+ mips_singlestep (serv, lwp, signal);
#else
if (thread_db_noisy)
fprintf (stderr, "<ptrace (PTRACE_SINGLESTEP, %d, 0, %d)>\n", lwp, signal);
Index: server.h
===================================================================
RCS file: /cvs/src/src/rda/unix/server.h,v
retrieving revision 1.3
diff -u -p -r1.3 server.h
--- server.h 30 Jun 2005 03:24:18 -0000 1.3
+++ server.h 24 Aug 2005 01:12:08 -0000
@@ -24,7 +24,7 @@
/* Shared definitions for an RDA based native gdb server. */
-#if defined(_MIPSEL) || defined(_MIPSEB)
+#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET)
/*
* We single-step by setting breakpoints. When an exception
* is handled, we need to restore the previous instructions
@@ -35,7 +35,8 @@
struct ss_save {
int in_use;
struct gdbserv_reg ss_addr;
- unsigned int ss_val;
+ char ss_val[8];
+ int ss_size;
};
#endif
@@ -66,7 +67,7 @@ struct child_process {
int debug_informational;
int running;
-#if defined(_MIPSEL) || defined(_MIPSEB)
+#if defined(_MIPSEL) || defined(_MIPSEB) || defined(AM33_2_0_LINUX_TARGET)
int is_ss; /* we are single stepping */
struct ss_save ss_info[2]; /* single stepping saved information */
#endif