Subject: GDB problem with dummy frames for ns32k
To: None <tech-toolchain@netbsd.org>
From: Ian Dall <ian@beware.dropbear.id.au>
List: tech-toolchain
Date: 01/27/2000 22:15:26
When calling a function in the inferior process from the debugger, the
frame gets lost. The implimentation of FRAME_FIND_SAVED_REGS, tries
to find the enter instruction, and interprete that to find how many arguments
etc. CALL_DUMMY carefully contains an enter instruction (even though
CALL_DUMMY_START_OFFSET is set so as the enter instruction is never executed)
just so it can be interpreted by FRAME_FIND_SAVED_REGS.

This all used to kind of work once when the enter instruction was found by
a backward search. At some point, the method of finding the entry point for
a function was changed to involve a symbol lookup. Of course, there is no
symbol for the dummy frame and the method fails ungracefully.

This patch copies the i386 method of finding the registers in the dummy frame.
It also moves the body of some complex macros into functions for easier
maintenance. This is also copied from the i386 port.

I have submitted this bugg report to the bug-gdb mailing list, but it
would be good if it were applied to the netbsd tree in the mean time.

Ian


diff -rc ../../../../src/gnu/dist/gdb/config/ns32k/tm-umax.h ./config/ns32k/tm-umax.h
*** ../../../../src/gnu/dist/gdb/config/ns32k/tm-umax.h	Thu Sep 25 20:43:43 1997
--- ./config/ns32k/tm-umax.h	Sun Jan  9 22:28:16 2000
***************
*** 19,24 ****
--- 19,30 ----
  
  /* This is also included by tm-ns32km3.h, as well as being used by umax.  */
  
+ #ifdef __STDC__		/* Forward decl's for prototypes */
+ struct frame_info;
+ struct frame_saved_regs;
+ struct type;
+ #endif
+ 
  #define TARGET_BYTE_ORDER LITTLE_ENDIAN
  
  /* Need to get function ends by adding this to epilogue address from .bf
***************
*** 281,349 ****
     ways in the stack frame.  sp is even more special:
     the address we return for it IS the sp for the next frame.  */
  
! #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs)	\
! { 								\
!   register int	regmask, regnum;				\
!   int		localcount;					\
!   register CORE_ADDR	enter_addr;				\
!   register CORE_ADDR	next_addr;				\
! 								\
!   memset (&(frame_saved_regs), '\0', sizeof (frame_saved_regs));	\
!   enter_addr = ns32k_get_enter_addr ((frame_info)->pc);		\
!   if (enter_addr > 1)						\
!     {								\
!       regmask = read_memory_integer (enter_addr+1, 1) & 0xff;	\
!       localcount = ns32k_localcount (enter_addr);		\
!       next_addr = (frame_info)->frame + localcount;		\
!       for (regnum = 0; regnum < 8; regnum++, regmask >>= 1)	\
! 	(frame_saved_regs).regs[regnum] = (regmask & 1) ?	\
! 					  (next_addr -= 4) : 0;	\
!       (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4;\
!       (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4;\
!       (frame_saved_regs).regs[FP_REGNUM] =			\
! 		  (read_memory_integer ((frame_info)->frame, 4));\
!     }								\
!   else if (enter_addr == 1)					\
!     {								\
!       CORE_ADDR sp = read_register (SP_REGNUM);			\
!       (frame_saved_regs).regs[PC_REGNUM] = sp;			\
!       (frame_saved_regs).regs[SP_REGNUM] = sp + 4;		\
!     }								\
! }
  
  /* Things needed for making the inferior call functions.  */
  
  /* Push an empty stack frame, to record the current PC, etc.  */
  
! #define PUSH_DUMMY_FRAME \
! { register CORE_ADDR sp = read_register (SP_REGNUM);\
!   register int regnum;				    \
!   sp = push_word (sp, read_register (PC_REGNUM));   \
!   sp = push_word (sp, read_register (FP_REGNUM));   \
!   write_register (FP_REGNUM, sp);		    \
!   for (regnum = 0; regnum < 8; regnum++)  \
!     sp = push_word (sp, read_register (regnum));    \
!   write_register (SP_REGNUM, sp);  			\
! }
  
  /* Discard from the stack the innermost frame, restoring all registers.  */
  
! #define POP_FRAME  \
! { register struct frame_info *frame = get_current_frame ();	 \
!   register CORE_ADDR fp;					 \
!   register int regnum;						 \
!   struct frame_saved_regs fsr;					 \
!   struct frame_info *fi;						 \
!   fp = frame->frame;						 \
!   get_frame_saved_regs (frame, &fsr);				 \
!   for (regnum = 0; regnum < 8; regnum++)			 \
!     if (fsr.regs[regnum])					 \
!       write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
!   write_register (FP_REGNUM, read_memory_integer (fp, 4));	 \
!   write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));   \
!   write_register (SP_REGNUM, fp + 8);				 \
!   flush_cached_frames ();					 \
! }
  
  /* This sequence of words is the instructions
       enter	0xff,0		82 ff 00
--- 287,315 ----
     ways in the stack frame.  sp is even more special:
     the address we return for it IS the sp for the next frame.  */
  
! #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
! { ns32k_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); }
! 
! extern void ns32k_frame_find_saved_regs PARAMS ((struct frame_info *,
! 						struct frame_saved_regs *));
  
  /* Things needed for making the inferior call functions.  */
  
  /* Push an empty stack frame, to record the current PC, etc.  */
  
! /* Push an empty stack frame, to record the current PC, etc.  */
! 
! #define PUSH_DUMMY_FRAME { ns32k_push_dummy_frame (); }
! 
! extern void ns32k_push_dummy_frame PARAMS ((void));
! 
  
  /* Discard from the stack the innermost frame, restoring all registers.  */
  
! #define POP_FRAME  { ns32k_pop_frame (); }
! 
! extern void ns32k_pop_frame PARAMS ((void));
! 
  
  /* This sequence of words is the instructions
       enter	0xff,0		82 ff 00
diff -rc ../../../../src/gnu/dist/gdb/ns32k-tdep.c ./ns32k-tdep.c
*** ../../../../src/gnu/dist/gdb/ns32k-tdep.c	Tue Mar  2 22:37:44 1999
--- ./ns32k-tdep.c	Sun Jan  9 22:28:14 2000
***************
*** 19,24 ****
--- 19,25 ----
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  
  #include "defs.h"
+ #include "inferior.h"
  
  void
  _initialize_ns32k_tdep ()
***************
*** 156,159 ****
--- 157,256 ----
      return 0;		/* function has no enter/exit */
  
    return enter_addr;	/* pc is between enter and exit */
+ }
+ 
+ void ns32k_frame_find_saved_regs (frame_info, frame_saved_regs)
+      struct frame_info *frame_info;
+      struct frame_saved_regs *frame_saved_regs;
+ {
+   int regmask, regnum;
+   int localcount;
+   CORE_ADDR enter_addr;
+   CORE_ADDR next_addr;
+   CORE_ADDR dummy_bottom;
+ 
+   memset (frame_saved_regs, '\0', sizeof *frame_saved_regs);
+   /* if frame is the end of a dummy, compute where the
+    * beginning would be
+    */
+   dummy_bottom = (frame_info->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH);
+   
+   /* check if the PC is in the stack, in a dummy frame */
+   if (dummy_bottom <= frame_info->pc && frame_info->pc <= frame_info->frame) 
+     {
+       /* all regs were saved by PUSH_DUMMY_FRAME */
+       CORE_ADDR adr = frame_info->frame;
+       for (regnum = 0; regnum < NUM_REGS; regnum++) 
+ 	{
+ 	  adr -= REGISTER_RAW_SIZE (regnum);
+ 	  frame_saved_regs->regs[regnum] = adr;
+ 	}
+       return;
+     }
+   
+   enter_addr = ns32k_get_enter_addr (frame_info->pc);
+   if (enter_addr > 1)
+     {
+       regmask = read_memory_integer (enter_addr+1, 1) & 0xff;
+       localcount = ns32k_localcount (enter_addr);
+       next_addr = frame_info->frame + localcount;
+       for (regnum = 0; regnum < 8; regnum++, regmask >>= 1)
+ 	frame_saved_regs->regs[regnum] = (regmask & 1) ?
+ 	  (next_addr -= 4) : 0;
+       frame_saved_regs->regs[SP_REGNUM] = frame_info->frame + 4;
+       frame_saved_regs->regs[PC_REGNUM] = frame_info->frame + 4;
+       frame_saved_regs->regs[FP_REGNUM] =
+ 	(read_memory_integer (frame_info->frame, 4));
+     }
+   else if (enter_addr == 1)
+     {
+       CORE_ADDR sp = read_register (SP_REGNUM);
+       frame_saved_regs->regs[PC_REGNUM] = sp;
+       frame_saved_regs->regs[SP_REGNUM] = sp + 4;
+     }
+ }
+ 
+ void ns32k_push_dummy_frame()
+ {
+   register CORE_ADDR sp = read_register (SP_REGNUM);
+   register int regnum;
+   char regbuf[MAX_REGISTER_RAW_SIZE];
+ 
+   sp = push_word (sp, read_register (PC_REGNUM));
+   sp = push_word (sp, read_register (FP_REGNUM));
+   write_register (FP_REGNUM, sp);
+   for (regnum = 0; regnum < NUM_REGS; regnum++)
+     {
+       read_register_gen (regnum, regbuf);
+       sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
+     }
+   write_register (SP_REGNUM, sp);
+ }
+ 
+ 
+ void ns32k_pop_frame ()
+ {
+   struct frame_info *frame = get_current_frame ();
+   CORE_ADDR fp;
+   int regnum;
+   struct frame_saved_regs fsr;
+   char regbuf[MAX_REGISTER_RAW_SIZE];
+ 
+   struct frame_info *fi;
+   fp = frame->frame;
+   get_frame_saved_regs (frame, &fsr);
+   for (regnum = 0; regnum < NUM_REGS; regnum++)
+     {
+       CORE_ADDR adr = fsr.regs[regnum];
+       if (adr)
+ 	{
+ 	  read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
+ 	  write_register_bytes (REGISTER_BYTE (regnum), regbuf,
+ 				REGISTER_RAW_SIZE (regnum));
+ 	}
+     }
+   write_register (FP_REGNUM, read_memory_integer (fp, 4));
+   write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+   write_register (SP_REGNUM, fp + 8);
+   flush_cached_frames ();
  }