Subject: port-pc532/11562: Gdb corrupts stack when executing code in inferior process
To: None <gnats-bugs@gnats.netbsd.org>
From: Ian Dall <ian@beware.dropbear.id.au>
List: netbsd-bugs
Date: 11/24/2000 16:12:14
>Number:         11562
>Category:       port-pc532
>Synopsis:       Gdb corrupts stack when executing code in inferior process
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-pc532-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Nov 24 16:12:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Ian Dall
>Release:        <NetBSD-current source date> NetBSD-current 10 Nov 2000
>Organization:
	
>Environment:
	
System: NetBSD gateway.beware.dropbear.id.au 1.5_ALPHA NetBSD 1.5_ALPHA (SIBYL) #0: Sun Aug 13 15:28:38 CST 2000 ian@sibyl.beware.dropbear.id.au:/usr3/netbsd-src/bsrc/sys/arch/pc532/compile/SIBYL pc532


>Description:
	
Gdb corrupts stack when executing code in inferior process. The error message:
Error accessing memory address 0x0: Invalid argument.
warning: Unable to restore previously selected frame.
is produced.
>How-To-Repeat:
	
Debug pretty much any process containing a call to printf.
(gdb) break main
(gdb) run
(gdb) set printf ("Hello World")

>Fix:
	

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 ();
  }

>Release-Note:
>Audit-Trail:
>Unformatted: