This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB 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]

Many fixes/improvements to Sparc/Linux



With the current CVS I found that there were nearly a thousand
testsuite failures, so I went and fixed it. :-)

With the fixes below and current compiler tools it is down to just
under 100 failures in the GDB testsuite.  Most of the remaining issues
are in thread handling, and I'm going to fix that stuff up next.

2002-04-06  David S. Miller  <davem@redhat.com>

	* sparc-linux-tdep.c: New file.
	* Makefile.in: Add sparc-linux-tdep.c to ALLDEPFILES.
	Add dependencies.
	* sparc-linux-nat.c: Include gdbcore.h and gdb_string.h
	(fetch_core_registers, sparc_linux_core_fns,
	_initialize_core_sparc_linux): New.
	* sparc-nat.c (SPARC_PIDGET): New macro.
	(fetch_inferior_registers, store_inferior_registers): Use it to
	convert inferior_ptid to ptrace pid arg.  Kill ambiguous else
	compile warning.
	* sparc-tdep.c (X_RS2): Define.
	(examine_prologue): Move static decl. before
	sparc_init_extra_frame_info.  Interpret mov %iX, %foo as part of
	the prologue.
	(sparc_init_extra_frame_info): Use examine_prologue to determine
	the instruction range in which to look for save instruction.
	(sparc_fix_call_dummy): When doing a non-skip unimp dummy call,
	do not forget to put the trap instruction in the right place.
	(sparc64_push_arguments): 16-byte float requests are only valid
	if SPARC_TARGET_LONG_DOUBLE_SZ is 16.
	(sparc_gdbarch_init): Set long double bits based upon
	SPARC_TARGET_LONG_DOUBLE_SZ.
	* config/sparc/linux.mt (TDEPFILES): Add sparc-linux-tdep.o
	* config/sparc/nm-linux.h (CHILD_PREPARE_TO_STORE): Define.
	(SPARC_PIDGET): Define.
	* config/sparc/tm-sparc.h (SPARC_TARGET_LONG_DOUBLE_SZ): Define
	to 16.
	* config/sparc/tm-linux.h (GDB_MULTI_ARCH): Set to
	GDB_MULTI_ARCH_PARTIAL.
	(SIGCONTEXT_PC_OFFSET): Delete.
	(SPARC_TARGET_LONG_DOUBLE_SZ): Override to 8.
	(IN_SIGTRAMP, SKIP_SOLIB_RESOLVER): Define.
	(FRAME_SAVED_PC, FRAME_CHAIN, SAVED_PC_AFTER_CALL,
	SKIP_PROLOGUE_FRAMELESS_P): Override to linux specific versions.
	* config/sparc/tm-sp64linux.h (GDB_MULTI_ARCH): Delete.
	(SIGCONTEXT_PC_OFFSET): Correct.
	(tm-linux.h): Include.
	(IN_SIGTRAMP, SKIP_SOLIB_RESOLVER): Define.
	(FRAME_SAVED_PC, FRAME_CHAIN, SAVED_PC_AFTER_CALL,
	SKIP_PROLOGUE_FRAMELESS_P): Override to linux specific versions.
	(tm-sysv4.h): Delete include.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.167
diff -u -p -r1.167 Makefile.in
--- Makefile.in	2002/03/29 01:22:41	1.167
+++ Makefile.in	2002/04/06 09:29:12
@@ -1210,7 +1210,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 2
 	ser-go32.c ser-pipe.c ser-tcp.c \
 	sh-tdep.c solib.c solib-svr4.c solib-sunos.c sparc-linux-nat.c \
 	sparc-nat.c \
-	sparc-tdep.c sparcl-tdep.c sun3-nat.c \
+	sparc-tdep.c sparcl-tdep.c sparc-linux-tdep.c sun3-nat.c \
 	symm-tdep.c symm-nat.c \
 	vax-tdep.c \
 	vx-share/xdr_ld.c vx-share/xdr_ptrace.c vx-share/xdr_rdb.c \
@@ -2036,7 +2036,11 @@ source.o: source.c $(defs_h) $(expressio
 	$(symtab_h) $(gdb_string_h) $(source_h) $(completer_h) $(linespec_h) \
 	$(ui_out_h)
 
-sparc-linux-nat.o: sparc-linux-nat.c $(defs_h) $(regcache_h)
+sparc-linux-nat.o: sparc-linux-nat.c $(defs_h) $(regcache_h) $(gdbcore_h) \
+	$(gdb_string_h)
+
+sparc-linux-tdep.o: sparc-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \
+	$(value_h) $(regcache_h)
 
 sparc-nat.o: sparc-nat.c $(bfd_h) $(defs_h) $(inferior_h) $(gdbcore_h) \
 	$(target_h) $(regcache_h)
Index: sparc-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-linux-nat.c,v
retrieving revision 1.3
diff -u -p -r1.3 sparc-linux-nat.c
--- sparc-linux-nat.c	2002/02/24 22:14:33	1.3
+++ sparc-linux-nat.c	2002/04/06 09:29:14
@@ -21,6 +21,8 @@
 
 #include "defs.h"
 #include "regcache.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
    
 #include <sys/procfs.h>
 
@@ -97,4 +99,58 @@ fill_fpregset (elf_fpregset_t *fpregsetp
 
   if (regno == -1 || regno == FPS_REGNUM)
     regcache_collect (FPS_REGNUM, &fpregsetp->pr_fsr);
+}
+
+/*  Use a local version of this function to get the correct types for
+    regsets, until multi-arch core support is ready.  */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+		      int which, CORE_ADDR reg_addr)
+{
+  elf_gregset_t gregset;
+  elf_fpregset_t fpregset;
+
+  if (which == 0)
+    {
+      if (core_reg_size != sizeof (gregset))
+	{
+	  warning ("wrong size gregset struct in core file");
+	}
+      else
+	{
+	  memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
+	  supply_gregset (&gregset);
+	}
+    }
+  else if (which == 2)
+    {
+      if (core_reg_size != sizeof (fpregset))
+	{
+	  warning ("wrong size fpregset struct in core file");
+	}
+      else
+	{
+	  memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
+	  supply_fpregset (&fpregset);
+	}
+    }
+}
+
+/* Register that we are able to handle ELF file formats using standard
+   procfs "regset" structures.  */
+
+static struct core_fns sparc_linux_core_fns =
+{
+  bfd_target_elf_flavour,		/* core_flavour */
+  default_check_format,			/* check_format */
+  default_core_sniffer,			/* core_sniffer */
+  fetch_core_registers,			/* core_read_registers */
+  NULL					/* next */
+};
+
+void
+_initialize_core_sparc_linux (void)
+{
+  add_core_fns (&sparc_linux_core_fns);
 }
Index: sparc-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-nat.c,v
retrieving revision 1.12
diff -u -p -r1.12 sparc-nat.c
--- sparc-nat.c	2002/03/21 02:03:13	1.12
+++ sparc-nat.c	2002/04/06 09:29:15
@@ -38,6 +38,10 @@
 #endif
 #include <sys/user.h>
 
+#ifndef SPARC_PIDGET
+#define SPARC_PIDGET(INF_PTID)	PIDGET (INF_PTID)
+#endif
+
 /* We don't store all registers immediately when requested, since they
    get sent over in large chunks anyway.  Instead, we accumulate most
    of the changes and send them over once.  "deferred_stores" keeps
@@ -57,7 +61,9 @@ fetch_inferior_registers (int regno)
 {
   struct regs inferior_registers;
   struct fp_status inferior_fp_registers;
-  int i;
+  int i, proc_id;
+
+  proc_id = SPARC_PIDGET (inferior_ptid);
 
   /* We should never be called with deferred stores, because a prerequisite
      for writing regs is to have fetched them all (PREPARE_TO_STORE), sigh.  */
@@ -75,7 +81,7 @@ fetch_inferior_registers (int regno)
       || regno >= Y_REGNUM
       || (!register_valid[SP_REGNUM] && regno < I7_REGNUM))
     {
-      if (0 != ptrace (PTRACE_GETREGS, PIDGET (inferior_ptid),
+      if (0 != ptrace (PTRACE_GETREGS, proc_id,
 		       (PTRACE_ARG3_TYPE) & inferior_registers, 0))
 	perror ("ptrace_getregs");
 
@@ -105,7 +111,7 @@ fetch_inferior_registers (int regno)
       regno == FPS_REGNUM ||
       (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31))
     {
-      if (0 != ptrace (PTRACE_GETFPREGS, PIDGET (inferior_ptid),
+      if (0 != ptrace (PTRACE_GETFPREGS, proc_id,
 		       (PTRACE_ARG3_TYPE) & inferior_fp_registers,
 		       0))
 	perror ("ptrace_getfpregs");
@@ -151,25 +157,30 @@ store_inferior_registers (int regno)
   struct regs inferior_registers;
   struct fp_status inferior_fp_registers;
   int wanna_store = INT_REGS + STACK_REGS + FP_REGS;
+  int proc_id;
+
+  proc_id = SPARC_PIDGET (inferior_ptid);
 
   /* First decide which pieces of machine-state we need to modify.  
      Default for regno == -1 case is all pieces.  */
   if (regno >= 0)
-    if (FP0_REGNUM <= regno && regno < FP0_REGNUM + 32)
-      {
-	wanna_store = FP_REGS;
-      }
-    else
-      {
-	if (regno == SP_REGNUM)
-	  wanna_store = INT_REGS + STACK_REGS;
-	else if (regno < L0_REGNUM || regno > I7_REGNUM)
-	  wanna_store = INT_REGS;
-	else if (regno == FPS_REGNUM)
+    {
+      if (FP0_REGNUM <= regno && regno < FP0_REGNUM + 32)
+	{
 	  wanna_store = FP_REGS;
-	else
-	  wanna_store = STACK_REGS;
-      }
+	}
+      else
+	{
+	  if (regno == SP_REGNUM)
+	    wanna_store = INT_REGS + STACK_REGS;
+	  else if (regno < L0_REGNUM || regno > I7_REGNUM)
+	    wanna_store = INT_REGS;
+	  else if (regno == FPS_REGNUM)
+	    wanna_store = FP_REGS;
+	  else
+	    wanna_store = STACK_REGS;
+	}
+    }
 
   /* See if we're forcing the stores to happen now, or deferring. */
   if (regno == -2)
@@ -231,7 +242,7 @@ store_inferior_registers (int regno)
       inferior_registers.r_y =
 	*(int *) &registers[REGISTER_BYTE (Y_REGNUM)];
 
-      if (0 != ptrace (PTRACE_SETREGS, PIDGET (inferior_ptid),
+      if (0 != ptrace (PTRACE_SETREGS, proc_id,
 		       (PTRACE_ARG3_TYPE) & inferior_registers, 0))
 	perror ("ptrace_setregs");
     }
@@ -245,7 +256,7 @@ store_inferior_registers (int regno)
       memcpy (&inferior_fp_registers.Fpu_fsr,
 	      &registers[REGISTER_BYTE (FPS_REGNUM)], sizeof (FPU_FSR_TYPE));
       if (0 !=
-	  ptrace (PTRACE_SETFPREGS, PIDGET (inferior_ptid),
+	  ptrace (PTRACE_SETFPREGS, proc_id,
 		  (PTRACE_ARG3_TYPE) & inferior_fp_registers, 0))
 	perror ("ptrace_setfpregs");
     }
Index: sparc-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-tdep.c,v
retrieving revision 1.25
diff -u -p -r1.25 sparc-tdep.c
--- sparc-tdep.c	2002/04/06 00:19:44	1.25
+++ sparc-tdep.c	2002/04/06 09:29:22
@@ -173,6 +173,7 @@ fetch_instruction (CORE_ADDR pc)
 #define X_RS1(i) (((i) >> 14) & 0x1f)
 #define X_I(i) (((i) >> 13) & 1)
 #define X_IMM13(i) ((i) & 0x1fff)
+#define X_RS2(i) (((i) >> 0) & 0x1f)
 /* Sign extension macros.  */
 #define X_SIMM13(i) ((X_IMM13 (i) ^ 0x1000) - 0x1000)
 #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
@@ -277,6 +278,9 @@ struct frame_extra_info 
   int sp_offset;
 };
 
+static CORE_ADDR examine_prologue (CORE_ADDR, int, struct frame_info *,
+				   CORE_ADDR *);
+
 /* Call this for each newly created frame.  For SPARC, we need to
    calculate the bottom of the frame, and do some extra work if the
    prologue has been generated via the -mflat option to GCC.  In
@@ -391,22 +395,17 @@ sparc_init_extra_frame_info (int fromlea
 	     to the current value of the stack pointer and set
 	     the in_prologue flag.  */
 	  CORE_ADDR addr;
-	  struct symtab_and_line sal;
 
-	  sal = find_pc_line (prologue_start, 0);
-	  if (sal.line == 0)	/* no line info, use PC */
-	    prologue_end = fi->pc;
-	  else if (sal.end < prologue_end)
-	    prologue_end = sal.end;
+	  prologue_end = examine_prologue (prologue_start, 0, NULL, NULL);
 	  if (fi->pc < prologue_end)
 	    {
-	      for (addr = prologue_start; addr < fi->pc; addr += 4)
+	      for (addr = fi->pc; addr < prologue_end; addr += 4)
 		{
 		  insn = read_memory_integer (addr, 4);
 		  if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
 		    break;	/* SAVE seen, stop searching */
 		}
-	      if (addr >= fi->pc)
+	      if (addr < prologue_end)
 		{
 		  fi->extra_info->in_prologue = 1;
 		  fi->frame = read_register (SP_REGNUM);
@@ -544,9 +543,6 @@ setup_arbitrary_frame (int argc, CORE_AD
    This routine should be more specific in its actions; making sure
    that it uses the same register in the initial prologue section.  */
 
-static CORE_ADDR examine_prologue (CORE_ADDR, int, struct frame_info *,
-				   CORE_ADDR *);
-
 static CORE_ADDR
 examine_prologue (CORE_ADDR start_pc, int frameless_p, struct frame_info *fi,
 		  CORE_ADDR *saved_regs)
@@ -665,6 +661,12 @@ examine_prologue (CORE_ADDR start_pc, in
 	       && X_I (insn)			/* immediate mode */
 	       && X_RS1 (insn) == 30)		/* off of frame pointer */
 	; /* empty statement -- fall thru to end of loop */
+      else if (X_OP (insn) == 2
+	       && X_OP3 (insn) == 2		/* logical or? */
+	       && ! X_I (insn)			/* not immediate mode */
+	       && X_RS1 (insn) == 0		/* %g0 */
+	       && (X_RS2 (insn) & 0x18) == 0x18)/* input register */
+	; /* empty statement -- fall thru to end of loop */
       else if (is_flat
 	       && X_OP (insn) == 3
 	       && X_OP3 (insn) == 4		/* store? */
@@ -2177,7 +2179,10 @@ sparc_fix_call_dummy (char *dummy, CORE_
       set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 0x30);
     }
   else
-    set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 0x2c);
+    {
+      store_unsigned_integer (dummy + 0x2c, 4, 0x91d02001); /* ta 1 */
+      set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 0x2c);
+    }
 
   if (!(GDB_TARGET_IS_SPARC64))
     {
@@ -2380,9 +2385,13 @@ sparc64_push_arguments (int nargs, struc
 		register_counter += 1;
 		break;
 	      case 16:	/* Quad-precision (long double) */
-		fpreg = FP0_REGNUM + 2 * register_counter;
-		register_counter += 2;
-		break;
+		if (SPARC_TARGET_LONG_DOUBLE_SZ == 16)
+		  {
+		    fpreg = FP0_REGNUM + 2 * register_counter;
+		    register_counter += 2;
+		    break;
+		  }
+		/* fallthrough */
 	      default:
 		internal_error (__FILE__, __LINE__, "bad switch");
 	      }
@@ -2968,7 +2977,8 @@ sparc_gdbarch_init (struct gdbarch_info 
   set_gdbarch_init_extra_frame_info (gdbarch, sparc_init_extra_frame_info);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
-  set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+  set_gdbarch_long_double_bit (gdbarch,
+			       SPARC_TARGET_LONG_DOUBLE_SZ * TARGET_CHAR_BIT);
   set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
   set_gdbarch_max_register_raw_size (gdbarch, 8);
   set_gdbarch_max_register_virtual_size (gdbarch, 8);
Index: config/sparc/linux.mt
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/linux.mt,v
retrieving revision 1.3
diff -u -p -r1.3 linux.mt
--- linux.mt	2001/03/10 06:17:24	1.3
+++ linux.mt	2002/04/06 09:29:24
@@ -1,3 +1,3 @@
 # Target: Sparcstation, running Linux
-TDEPFILES= sparc-tdep.o solib.o solib-svr4.o solib-legacy.o
+TDEPFILES= sparc-tdep.o sparc-linux-tdep.o solib.o solib-svr4.o solib-legacy.o
 TM_FILE= tm-linux.h
Index: config/sparc/nm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/nm-linux.h,v
retrieving revision 1.5
diff -u -p -r1.5 nm-linux.h
--- nm-linux.h	2002/02/24 22:56:07	1.5
+++ nm-linux.h	2002/04/06 09:29:24
@@ -30,3 +30,12 @@
 
 #define KERNEL_U_SIZE kernel_u_size()
 extern int kernel_u_size (void);
+
+/* Before storing, we need to read all the registers.  */
+
+#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES)
+
+/* On Linux we need to potentially handle thread-ids.  */
+#define SPARC_PIDGET(INF_PTID)	\
+	(TIDGET (INF_PTID) ? \
+	 TIDGET (INF_PTID) : PIDGET (INF_PTID))
Index: config/sparc/tm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/tm-linux.h,v
retrieving revision 1.3
diff -u -p -r1.3 tm-linux.h
--- tm-linux.h	2002/02/24 22:56:07	1.3
+++ tm-linux.h	2002/04/06 09:29:25
@@ -23,10 +23,44 @@
 #ifndef TM_SPARCLINUX_H
 #define TM_SPARCLINUX_H
 
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_PARTIAL
+
 #include "sparc/tm-sparc.h"
 
-#define SIGCONTEXT_PC_OFFSET 12
+#undef SPARC_TARGET_LONG_DOUBLE_SZ
+#define SPARC_TARGET_LONG_DOUBLE_SZ 8
 
 #include "tm-linux.h"
+
+/* When the sparc Linux kernel calls a signal handler, the return
+   address points to a bit of code on the stack.  These definitions
+   are used to identify this bit of code as a signal trampoline in
+   order to support backtracing through calls to signal handlers.  */
+
+#define IN_SIGTRAMP(pc, name) sparc_linux_in_sigtramp (pc, name)
+extern int sparc_linux_in_sigtramp (CORE_ADDR, char *);
+
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(frame) sparc_linux_frame_saved_pc (frame)
+extern CORE_ADDR sparc_linux_frame_saved_pc (struct frame_info *frame);
+
+#define FRAME_CHAIN(THISFRAME) (sparc_linux_frame_chain (THISFRAME))
+extern CORE_ADDR sparc_linux_frame_chain (struct frame_info *);
+
+#undef SAVED_PC_AFTER_CALL
+#define SAVED_PC_AFTER_CALL(frame) sparc_linux_saved_pc_after_call (frame)
+extern CORE_ADDR sparc_linux_saved_pc_after_call (struct frame_info *);
+
+/* When we call a function in a shared library, and the PLT sends us
+   into the dynamic linker to find the function's real address, we
+   need to skip over the dynamic linker call.  This function decides
+   when to skip, and where to skip to.  See the comments for
+   SKIP_SOLIB_RESOLVER at the top of infrun.c.  */
+#define SKIP_SOLIB_RESOLVER sparc_linux_skip_solib_resolver
+extern CORE_ADDR sparc_linux_skip_solib_resolver (CORE_ADDR pc);
+
+#undef SKIP_PROLOGUE_FRAMELESS_P
+#define SKIP_PROLOGUE_FRAMELESS_P(PC) sparc_linux_skip_prologue_frameless_p (PC)
+extern CORE_ADDR sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc);
 
 #endif /* TM_SPARCLINUX_H */
Index: config/sparc/tm-sp64linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/tm-sp64linux.h,v
retrieving revision 1.2
diff -u -p -r1.2 tm-sp64linux.h
--- tm-sp64linux.h	2002/02/24 22:56:07	1.2
+++ tm-sp64linux.h	2002/04/06 09:29:25
@@ -21,18 +21,47 @@ Foundation, Inc., 59 Temple Place - Suit
 #ifndef TM_SPARC_LIN64_H
 #define TM_SPARC_LIN64_H
 
-#define GDB_MULTI_ARCH 0
-
 #include "sparc/tm-sp64.h"
 
-#define SIGCONTEXT_PC_OFFSET 16  /* See asm-sparc64/sigcontext.h */
+#define SIGCONTEXT_PC_OFFSET (128 + (16 * 8) + 8)  /* See asm-sparc64/sigcontext.h */
 
 /* We always want full V9 + Ultra VIS stuff... */
 #undef TM_PRINT_INSN_MACH
 #define TM_PRINT_INSN_MACH bfd_mach_sparc_v9a
 
 #define GDB_PTRACE_REGS64
+
+#include "tm-linux.h"
+
+/* When the sparc Linux kernel calls a signal handler, the return
+   address points to a bit of code on the stack.  These definitions
+   are used to identify this bit of code as a signal trampoline in
+   order to support backtracing through calls to signal handlers.  */
+
+#define IN_SIGTRAMP(pc, name) sparc_linux_in_sigtramp (pc, name)
+extern int sparc_linux_in_sigtramp (CORE_ADDR, char *);
+
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(frame) sparc_linux_frame_saved_pc (frame)
+extern CORE_ADDR sparc_linux_frame_saved_pc (struct frame_info *frame);
+
+#define FRAME_CHAIN(THISFRAME) (sparc_linux_frame_chain (THISFRAME))
+extern CORE_ADDR sparc_linux_frame_chain (struct frame_info *);
+
+#undef SAVED_PC_AFTER_CALL
+#define SAVED_PC_AFTER_CALL(frame) sparc_linux_saved_pc_after_call (frame)
+extern CORE_ADDR sparc_linux_saved_pc_after_call (struct frame_info *);
+
+/* When we call a function in a shared library, and the PLT sends us
+   into the dynamic linker to find the function's real address, we
+   need to skip over the dynamic linker call.  This function decides
+   when to skip, and where to skip to.  See the comments for
+   SKIP_SOLIB_RESOLVER at the top of infrun.c.  */
+#define SKIP_SOLIB_RESOLVER sparc_linux_skip_solib_resolver
+extern CORE_ADDR sparc_linux_skip_solib_resolver (CORE_ADDR pc);
 
-#include "tm-sysv4.h"
+#undef SKIP_PROLOGUE_FRAMELESS_P
+#define SKIP_PROLOGUE_FRAMELESS_P(PC) sparc_linux_skip_prologue_frameless_p (PC)
+extern CORE_ADDR sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc);
 
 #endif TM_SPARC_LIN64_H
Index: config/sparc/tm-sparc.h
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/tm-sparc.h,v
retrieving revision 1.12
diff -u -p -r1.12 tm-sparc.h
--- tm-sparc.h	2002/01/29 04:42:44	1.12
+++ tm-sparc.h	2002/04/06 09:29:27
@@ -302,6 +302,11 @@ extern CORE_ADDR sparc32_stack_align (CO
   (TYPE_CODE(TYPE) == TYPE_CODE_FLT \
    && TYPE_LENGTH(TYPE) > 8)
 
+/* Long-double's are 16-bytes on most platforms, but this can be
+   overridden.  */
+
+#define SPARC_TARGET_LONG_DOUBLE_SZ 16
+
 /* When passing a structure to a function, Sun cc passes the address
    not the structure itself.  It (under SunOS4) creates two symbols,
    which we need to combine to a LOC_REGPARM.  Gcc version two (as of
--- /dev/null	Tue May  5 13:32:27 1998
+++ sparc-linux-tdep.c	Sat Apr  6 00:58:55 2002
@@ -0,0 +1,404 @@
+/* Target-dependent code for GNU/Linux SPARC.
+
+   Copyright 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "frame.h"
+#include "inferior.h"
+#include "obstack.h"
+#include "target.h"
+#include "value.h"
+#include "bfd.h"
+#include "gdb_string.h"
+#include "regcache.h"
+
+#include "gdbcore.h"
+
+/* For sparc_linux_skip_solib_resolver.  */
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+#include "solib-svr4.h"		/* For struct link_map_offsets.  */
+
+/* Recognizing signal handler frames.  */
+
+/* GNU/Linux has two flavors of signals.  Normal signal handlers, and
+   "realtime" (RT) signals.  The RT signals can provide additional
+   information to the signal handler if the SA_SIGINFO flag is set
+   when establishing a signal handler using `sigaction'.  It is not
+   unlikely that future versions of GNU/Linux will support SA_SIGINFO
+   for normal signals too.  */
+
+/* When the sparc Linux kernel calls a signal handler and the
+   SA_RESTORER flag isn't set, the return address points to a bit of
+   code on the stack.  This function returns whether the PC appears to
+   be within this bit of code.
+
+   The instruction sequence for normal signals is
+	mov __NR_sigreturn, %g1		! hex: 0x821020d8
+	ta  0x10			! hex: 0x91d02010
+
+   Checking for the code sequence should be somewhat reliable, because
+   the effect is to call the system call sigreturn.  This is unlikely
+   to occur anywhere other than a signal trampoline.
+
+   It kind of sucks that we have to read memory from the process in
+   order to identify a signal trampoline, but there doesn't seem to be
+   any other way.  The sparc_linux_in_sigtramp function below arranges to
+   only call us if no function name could be identified, which should
+   be the case since the code is on the stack.  */
+
+#define LINUX_SIGTRAMP_WORD0	(0x821020d8)	/* mov __NR_sigreturn, %g1 */
+#define LINUX_SIGTRAMP_WORD1	(0x91d02010)	/* ta  0x10 */
+#define LINUX_SIGTRAMP_LEN	(8)
+
+/* If PC is in a sigtramp routine, return the address of the start of
+   the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+sparc_linux_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned int buf[2];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the three instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_SIGTRAMP_WORD0)
+    {
+      if (buf[0] != LINUX_SIGTRAMP_WORD1)
+	return 0;
+
+      pc -= 4;
+
+      if (read_memory_nobpt(pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+	return 0;
+    }
+
+  if (buf[0] != LINUX_SIGTRAMP_WORD0
+      || buf[1] != LINUX_SIGTRAMP_WORD0)
+    return 0;
+
+  return pc;
+}
+
+/* This function does the same for RT signals.  Here the instruction
+   sequence is
+       mov __NR_rt_sigreturn, %g1	! hex: 0x82102065
+       ta  {0x10,0x68}			! hex: 0x91d02010 or 0x91d02068
+
+   The effect is to call the system call rt_sigreturn.  The trap number
+   is variable based upon whether this is a 32-bit or 64-bit sparc binary.
+   Note that 64-bit binaries only use this RT signal return method.  */
+
+#define LINUX_RT_SIGTRAMP_WORD0		(0x82102065)
+#define LINUX_RT_SIGTRAMP_WORD1_32	(0x91d02010)
+#define LINUX_RT_SIGTRAMP_WORD1_64	(0x91d02068)
+#define LINUX_RT_SIGTRAMP_LEN		8
+
+/* If PC is in a RT sigtramp routine, return the address of the start
+   of the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+sparc_linux_rt_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned int buf[2];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the two instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_RT_SIGTRAMP_WORD0)
+    {
+      if (buf[0] != LINUX_RT_SIGTRAMP_WORD1_32
+	  && buf[0] != LINUX_RT_SIGTRAMP_WORD1_64)
+	return 0;
+
+      pc -= 4;
+
+      if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+	return 0;
+    }
+
+  if (buf[0] != LINUX_RT_SIGTRAMP_WORD0
+      || (buf[1] != LINUX_RT_SIGTRAMP_WORD1_32
+	  && buf[1] != LINUX_RT_SIGTRAMP_WORD1_64))
+    return 0;
+
+  return pc;
+}
+
+/* Return whether PC is in a GNU/Linux sigtramp routine.  */
+
+int
+sparc_linux_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  if (name)
+    return STREQ ("__sigreturn_stub", name) || STREQ ("__rt_sigreturn_stub", name);
+  
+  return (sparc_linux_sigtramp_start (pc) != 0
+	  || sparc_linux_rt_sigtramp_start (pc) != 0);
+}
+
+/* Size of a general (integer) register: */
+#define SPARC_INTREG_SIZE (REGISTER_RAW_SIZE (G0_REGNUM))
+
+/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
+   PC/SP of the associated sigcontext structure.  */
+
+static CORE_ADDR
+sparc_linux_sigtramp_saved_pc (struct frame_info *frame)
+{
+  CORE_ADDR pc, ret;
+  char *buf;
+
+  if (!frame->next)
+    return 0;
+
+  pc = sparc_linux_sigtramp_start (frame->pc);
+  buf = alloca(SPARC_INTREG_SIZE);
+  if (pc)
+    {
+      /* Stack frame is:
+           standard 32-bit register window + slack	96 bytes
+           siginfo_t					PC at offset 4  */
+
+      read_memory(frame->next->frame + (96 + 4), buf, SPARC_INTREG_SIZE);
+
+      ret = PC_ADJUST (extract_address (buf, SPARC_INTREG_SIZE));
+
+      return ret;
+    }
+
+  pc = sparc_linux_rt_sigtramp_start (frame->pc);
+  if (pc)
+    {
+      /* For 32-bit task, same as non-rt frame.  For 64-bit task
+	 the layout is:
+	      standard 64-bit register window + slack	192 bytes
+	      siginfo_t					128 bytes
+	      pt_regs					PC at offset 136  */
+      if (SPARC_INTREG_SIZE == 4)
+	{
+	  read_memory(frame->next->frame + (96 + 4), buf, SPARC_INTREG_SIZE);
+	}
+      else
+	{
+	  read_memory(frame->next->frame + (192 + 128 + 136), buf, SPARC_INTREG_SIZE);
+	}
+
+      ret = PC_ADJUST (extract_address (buf, SPARC_INTREG_SIZE));
+
+      return ret;
+    }
+
+  error ("Couldn't recognize signal trampoline.");
+  return 0;
+}
+
+extern CORE_ADDR sparc_frame_chain (struct frame_info *);
+
+CORE_ADDR
+sparc_linux_frame_chain (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return frame->frame;
+
+  return sparc_frame_chain (frame);
+}
+
+extern CORE_ADDR sparc_frame_saved_pc (struct frame_info *);
+
+/* Return the saved program counter for FRAME.  */
+
+CORE_ADDR
+sparc_linux_frame_saved_pc (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return sparc_linux_sigtramp_saved_pc (frame);
+
+  return sparc_frame_saved_pc (frame);
+}
+
+CORE_ADDR
+sparc_linux_saved_pc_after_call (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return sparc_linux_sigtramp_saved_pc (frame);
+
+  return sparc_pc_adjust (read_register (RP_REGNUM));
+}
+
+/* Calling functions in shared libraries.  */
+
+/* Find the minimal symbol named NAME, and return both the minsym
+   struct and its objfile.  This probably ought to be in minsym.c, but
+   everything there is trying to deal with things like C++ and
+   SOFUN_ADDRESS_MAYBE_TURQUOISE, ...  Since this is so simple, it may
+   be considered too special-purpose for general consumption.  */
+
+static struct minimal_symbol *
+find_minsym_and_objfile (char *name, struct objfile **objfile_p)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+    {
+      struct minimal_symbol *msym;
+
+      ALL_OBJFILE_MSYMBOLS (objfile, msym)
+	{
+	  if (SYMBOL_NAME (msym)
+	      && STREQ (SYMBOL_NAME (msym), name))
+	    {
+	      *objfile_p = objfile;
+	      return msym;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+static CORE_ADDR
+skip_hurd_resolver (CORE_ADDR pc)
+{
+  /* The HURD dynamic linker is part of the GNU C library, so many
+     GNU/Linux distributions use it.  (All ELF versions, as far as I
+     know.)  An unresolved PLT entry points to "_dl_runtime_resolve",
+     which calls "fixup" to patch the PLT, and then passes control to
+     the function.
+
+     We look for the symbol `_dl_runtime_resolve', and find `fixup' in
+     the same objfile.  If we are at the entry point of `fixup', then
+     we set a breakpoint at the return address (at the top of the
+     stack), and continue.
+  
+     It's kind of gross to do all these checks every time we're
+     called, since they don't change once the executable has gotten
+     started.  But this is only a temporary hack --- upcoming versions
+     of GNU/Linux will provide a portable, efficient interface for
+     debugging programs that use shared libraries.  */
+
+  struct objfile *objfile;
+  struct minimal_symbol *resolver 
+    = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile);
+
+  if (resolver)
+    {
+      struct minimal_symbol *fixup
+	= lookup_minimal_symbol ("fixup", NULL, objfile);
+
+      if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+	return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+
+      fixup = lookup_minimal_symbol("profile_fixup", NULL, objfile);
+      if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+	return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+    }
+
+  return 0;
+}      
+
+/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
+   This function:
+   1) decides whether a PLT has sent us into the linker to resolve
+      a function reference, and 
+   2) if so, tells us where to set a temporary breakpoint that will
+      trigger when the dynamic linker is done.  */
+
+CORE_ADDR
+sparc_linux_skip_solib_resolver (CORE_ADDR pc)
+{
+  CORE_ADDR result;
+
+  /* Plug in functions for other kinds of resolvers here.  */
+  result = skip_hurd_resolver (pc);
+  if (result)
+    return result;
+
+  return 0;
+}
+
+/* We need special processing here because '_dl_runtime_{resolve,profile}'
+   in the dynamic linker looks like it is frameless, but it really does
+   get a frame from its caller in the PLT (which does save).
+
+   Actually, any piece of code which has the same pettern, ie.:
+
+	place1:		save
+			call place2
+			 nop
+
+	place2:		call place3
+			 nop
+			jmp  %reg
+			restore
+
+	place3:		save
+			...
+			ret
+			 restore
+
+   is going to confuse SKIP_PROLOGUE_FRAMELESS_P.  It is hard to
+   formulate a generic fix for this that would not break on sibcalls.  */
+
+CORE_ADDR
+sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc)
+{
+  struct objfile *objfile;
+  struct minimal_symbol *resolver 
+    = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile);
+
+  if (resolver)
+    {
+      CORE_ADDR rpc = SYMBOL_VALUE_ADDRESS (resolver);
+      int resolver_size = (7 * 4);
+
+      if (SPARC_INTREG_SIZE == 8)
+	resolver_size = (33 * 4);
+      if (pc >= rpc && pc < (rpc + resolver_size))
+	return pc + 4;
+
+      resolver = lookup_minimal_symbol ("_dl_runtime_profile", NULL, objfile);
+      if (resolver)
+	{
+	  rpc = SYMBOL_VALUE_ADDRESS (resolver);
+	  if (pc >= rpc && pc < (rpc + resolver_size))
+	    return pc + 4;
+	}
+    }
+
+  return sparc_skip_prologue (pc, 1);
+}


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