Subject: port-arm32/6781: GDB 'call' command doesn't work
To: None <gnats-bugs@gnats.netbsd.org>
From: Richard Earnshaw <rearnsha@cambridge.arm.com>
List: netbsd-bugs
Date: 01/10/1999 16:10:15
>Number:         6781
>Category:       port-arm32
>Synopsis:       GDB 'call' command doesn't work
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-arm32-maintainer (NetBSD/arm32 Portmaster)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jan 10 08:20:01 1999
>Last-Modified:
>Originator:     Richard Earnshaw
>Organization:
ARM
>Release:        NetBSD-current
>Environment:
	
System: NetBSD buzzard.cambridge.arm.com 1.3I NetBSD 1.3I (BUZZARD) #35: Sat Jan 9 18:01:38 GMT 1999 rearnsha@buzzard.cambridge.arm.com:/home/rearnsha/netbsd/src/sys/arch/arm32/compile/BUZZARD arm32


>Description:
	Gdb currently crashes the executing program if you try to use the 
	CALL command to run a function in the inferior.  Patch below fixes 
	the problem (the old code is a legacy from the APCS-26 days of 
	RISCiX).
>How-To-Repeat:
	Try to use the CALL command in gdb.
>Fix:
	Patch below.

Index: tm-armnbsd.h
===================================================================
RCS file: /xx/rearnsha.old/netbsd/usr/cvs/src/gnu/dist/gdb/config/arm/tm-armnbsd.h,v
retrieving revision 1.1.1.1
diff -p -p -r1.1.1.1 tm-armnbsd.h
*** tm-armnbsd.h	1998/07/25 00:02:41	1.1.1.1
--- tm-armnbsd.h	1999/01/10 16:01:50
*************** Foundation, Inc., 59 Temple Place - Suit
*** 24,30 ****
  
  #define IEEE_FLOAT
  
! #define ADDR_BITS_REMOVE(val) (val)
  
  /* Offset from address of function to start of its code.
     Zero on most machines.  */
--- 24,30 ----
  
  #define IEEE_FLOAT
  
! #define ADDR_BITS_REMOVE(val) ((val) & ~3)
  
  /* Offset from address of function to start of its code.
     Zero on most machines.  */
*************** Foundation, Inc., 59 Temple Place - Suit
*** 342,419 ****
  
  /* 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;					\
!     /* opcode for ldmdb fp,{v1-v6,fp,ip,lr,pc}^ */		\
!     sp = push_word(sp, 0xe92bdbf0); /* dummy return_data_save ins */ \
!     /* push a pointer to the dummy instruction minus 12 */	\
!     sp = push_word(sp, read_register (SP_REGNUM) - 16);		\
!     sp = push_word(sp, read_register (PS_REGNUM));		\
!     sp = push_word(sp, read_register (SP_REGNUM));		\
!     sp = push_word(sp, read_register (FP_REGNUM));		\
!     for (regnum = 9; regnum >= 4; regnum --)			\
! 	sp = push_word(sp, read_register (regnum));		\
!     write_register (FP_REGNUM, read_register (SP_REGNUM) - 8);	\
!     write_register (SP_REGNUM, sp); }
  
  /* Discard from the stack the innermost frame, restoring all registers.  */
  
! #define POP_FRAME \
  {									\
!     register CORE_ADDR fp = read_register (FP_REGNUM);			\
!     register unsigned long return_data_save =				\
! 	read_memory_integer ( ADDR_BITS_REMOVE(read_memory_integer (fp, 4))	\
! 			       - 12, 4);			\
!     register int regnum;						\
!     write_register (PS_REGNUM, read_memory_integer (fp - 4, 4));	\
!     write_register (PC_REGNUM, ADDR_BITS_REMOVE(read_register (PS_REGNUM)));	\
!     write_register (SP_REGNUM, read_memory_integer (fp - 8, 4));	\
!     write_register (FP_REGNUM, read_memory_integer (fp - 12, 4));	\
!     fp -= 12;								\
!     for (regnum = 9; regnum >= 4; regnum--)				\
! 	if (return_data_save & (1<<regnum)) {				\
! 	    fp -= 4;							\
! 	    write_register (regnum, read_memory_integer(fp, 4));	\
! 	}								\
!     flush_cached_frames ();						\
  }
  
! /* This sequence of words is the instructions
  
!      ldmia	sp!,{a1-a4}
!      mov 	lk,pc
!      bl		*+8
!      swi	bkpt_swi
  
!    Note this is 16 bytes.  */
  
! #define CALL_DUMMY {0xe8bd000f, 0xe1a0e00f, 0xeb000000, 0xef180000}
  
  #define CALL_DUMMY_START_OFFSET 0  /* Start execution at beginning of dummy */
  
  /* Insert the specified number of args and function address
     into a call sequence of the above form stored at DUMMYNAME.  */
  
- #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \
- {										\
-     register enum type_code code = TYPE_CODE (type);				\
-     register nargs_in_registers, struct_return = 0;				\
-     /* fix the load-arguments mask to move the first 4 or less arguments	\
-        into a1-a4 but make sure the structure return address in a1 is		\
-        not disturbed if the function is returning a structure */		\
-     if ((code == TYPE_CODE_STRUCT ||						\
- 	 code == TYPE_CODE_UNION ||						\
- 	 code == TYPE_CODE_ARRAY) &&						\
- 	TYPE_LENGTH (type) > 4) {						\
- 	nargs_in_registers = min(nargs + 1, 4);					\
- 	struct_return = 1;							\
-     } else									\
- 	nargs_in_registers = min(nargs, 4);					\
-     *(char *) dummyname = (1 << nargs_in_registers) - 1 - struct_return;	\
-     *(int *)((char *) dummyname + 8) =						\
- 	(((fun - (pc + 16)) / 4) & 0x00ffffff) | 0xeb000000; }
  
  CORE_ADDR arm_get_next_pc PARAMS ((CORE_ADDR));
  
--- 342,425 ----
  
  /* 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;							\
!   /* opcode for stmdb fp!, {r4-r10, fp, ip, lr, pc} */			\
!   sp = push_word (sp, 0xe92bdff0); /* dummy return_data_save ins */	\
!   /* push a pointer to the dummy instruction minus 12 */		\
!   sp = push_word (sp, read_register (SP_REGNUM) - 16);			\
!   sp = push_word (sp, read_register (PC_REGNUM));			\
!   sp = push_word (sp, read_register (SP_REGNUM));			\
!   sp = push_word (sp, read_register (FP_REGNUM));			\
!   for (regnum = 10; regnum >= 4; regnum--)				\
!     sp = push_word (sp, read_register (regnum));			\
!   write_register (FP_REGNUM, read_register (SP_REGNUM) - 8);		\
!   write_register (SP_REGNUM, sp);					\
! }
  
  /* Discard from the stack the innermost frame, restoring all registers.  */
  
! #define POP_FRAME							\
  {									\
!   register CORE_ADDR fp = read_register (FP_REGNUM);			\
!   register unsigned long return_data_save =				\
!     read_memory_integer (ADDR_BITS_REMOVE (read_memory_integer (fp, 4))	\
! 			 - 12, 4);					\
!   register int regnum;							\
!   write_register (PC_REGNUM, read_memory_integer (fp - 4, 4));		\
!   write_register (SP_REGNUM, read_memory_integer (fp - 8, 4));		\
!   write_register (FP_REGNUM, read_memory_integer (fp - 12, 4));		\
!   fp -= 12;								\
!   for (regnum = 10; regnum >= 4; regnum--)				\
!     if (return_data_save & (1 << regnum))				\
!       {									\
! 	fp -= 4;							\
! 	write_register (regnum, read_memory_integer (fp, 4));		\
!       }									\
!   flush_cached_frames ();						\
  }
  
! /* This sequence of words is the instructions.  We use this rather than bl
!    becuase the code segment may not be reachable from the stack.
  
!      ldmia	sp!, {r0-r3}
!      mov 	lr, pc
!      ldr	pc, . + 8
!      Breakpoint
!      <address to call>
  
!    Note this is 20 bytes.  */
  
! #define CALL_DUMMY {0xe8bd000f, 0xe1a0e00f, 0xe59ff000, 0xe6000011, 0}
  
  #define CALL_DUMMY_START_OFFSET 0  /* Start execution at beginning of dummy */
  
  /* Insert the specified number of args and function address
     into a call sequence of the above form stored at DUMMYNAME.  */
+ 
+ #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p)	 \
+ {									 \
+   register enum type_code code = TYPE_CODE (type);			 \
+   register nargs_in_registers, struct_return = 0;			 \
+   /* fix the load-arguments mask to move the first 4 or less arguments 	 \
+      into a1-a4 but make sure the structure return address in a1 is	 \
+      not disturbed if the function is returning a structure */		 \
+   if ((code == TYPE_CODE_STRUCT						 \
+        || code == TYPE_CODE_UNION					 \
+        || code == TYPE_CODE_ARRAY)					 \
+       && TYPE_LENGTH (type) > 4)					 \
+   {					 				 \
+     nargs_in_registers = min(nargs + 1, 4);				 \
+     struct_return = 1;							 \
+   }									 \
+   else									 \
+     nargs_in_registers = min(nargs, 4);					 \
+   *(char *) dummyname = (1 << nargs_in_registers) - 1 - struct_return;	 \
+   *(int *)((char *) dummyname + 16) =	fun;				 \
+ }
  
  
  CORE_ADDR arm_get_next_pc PARAMS ((CORE_ADDR));
  

>Audit-Trail:
>Unformatted: