This is the mail archive of the rda@sourceware.org mailing list for the rda project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add support for am33 linux


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]