This is the mail archive of the gdb-patches@sourceware.cygnus.com mailing list for the GDB project. See the GDB home page for more information.


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

Re: GDB 4.17 Patch for stack aligned i386 code


> Actually, the last I looked at this, I was unclear about what/which of
> several patches were needed, and in which order.  If you had a single
> integrated set and could resend, that would be helpful...

Here's both patches consolidated into one.

This patch adds support for debugging functions where the
frame pointer has been eliminated and the stack pointer
is unchanging.  It also adds support for debugging functions
where the stack has been aligned.

There are no regressions evident from running the gdb 4.17
testsuite on Solaris 2.5.1 with gcc 2.7.2.1, egcs (from cvs on
1999-02-25), and egcs -momit-leaf-frame-pointer with this patch
installed.  There were no regressions evident from running the
gdb 4.17 testsuite on FreeBSD 3.0 and Solaris 2.5.1 with gcc
2.7.2.1, egcs (from cvs on 1999-01-14), and egcs
-momit-leaf-frame-pointer with the original two separate
patches installed.

Notes:

  1) The SVR4 changes to support sigtramp backtraces are untested.

  2) Platforms other than those tested may require some work in order
     to properly support sigtramp backtraces.  Start by looking at
     the BSD and Solaris definitions of:

       i386_sigcontext_addr
       SIGCONTEXT_FP_OFFSET
       SIGCONTEXT_SP_OFFSET

ChangeLog:

Wed Jan 20 22:14:03 EST 1999  John Wehle  (john@feith.com)

	* tm-i386.h (FRAME_CHAIN): Call i386_frame_chain for
	signal handler callers.
	(EXTRA_FRAME_INFO): Define stack_mask.
	(FRAME_ARGS_ADDRESS, FRAME_LOCALS_ADDRESS): Use it.
	* i386-tdep.c (i386_get_frame_setup): Set it.
	(i386_frame_find_saved_regs): Use it.
	(i386_init_extra_frame_info): Initialize it.
	(i386_frame_find_saved_regs): Don't accidently zero
	fi->fsr.regs[FP_REGNUM].
	(i386_sigcontext_addr): New function.
	(i386v4_sigtramp_saved_pc): Use it.
	(i386_analyze_prologue): Use it.
	(i386_analyze_prologue): Handle dummy frames.
	(i386_analyze_prologue): If the start of a function can't
	be located than assume the frame is in the frame pointer.
	(i386_frame_chain): If the caller's prologue can't be
	analyze then return the current frame as the frame.
	(i386_frame_chain): Check the current frame for FP_REGNUM.
	(i386_frame_chain): Handle chaining back from a signal
	handler caller to a function which uses the stack pointer
	for the frame pointer.
	(i386_frame_chain): Include the stack space occupied by
	FP_REGNUM when caculating the caller's frame.
	(i386_pop_frame): Don't bother explicitly restoring PC_REGNUM,
	it is restored by the for loop.
	* tm-i386bsd.h (SIGCONTEXT_FP_OFFSET,
	SIGCONTEXT_SP_OFFSET): Define.
	* tm-i386sol2.h: Likewise.
	* tm-i386v4.h: Likewise.

Wed Nov  4 22:29:19 EST 1998  John Wehle  (john@feith.com)

	* i386-tdep.c (codestream_fill): Use read_memory_nobpt.
	(i386_analyze_prologue, i386_frame_chain,
	i386_init_extra_frame_info): New functions.
	(i386_get_frame_setup, i386_frame_find_saved_regs,
	i386_skip_prologue, i386_pop_frame): Support prologues
	which don't setup a frame pointer.
	* tm-i386.h (EXTRA_FRAME_INFO, INIT_EXTRA_FRAME_INFO,
	INIT_FRAME_PC): Define.
	(FRAME_CHAIN): Call i386_frame_chain.
	(FRAME_FIND_SAVED_REGS, FRAME_SAVED_PC): Use fsr to
	locate the saved registers.
	(FRAMELESS_FUNCTION_INVOCATION): Don't define.
	(i386_init_extra_frame_info, i386_frame_chain): Add
	prototypes.

-- John Wehle
------------------8<------------------------8<------------------------
*** gdb/i386-tdep.c.ORIGINAL	Sat Apr 11 01:39:37 1998
--- gdb/i386-tdep.c	Thu Feb 25 22:24:11 1999
*************** Foundation, Inc., 59 Temple Place - Suit
*** 28,37 ****
  #include "symtab.h"
  #include "gdbcmd.h"
  
- static long i386_get_frame_setup PARAMS ((CORE_ADDR));
- 
- static void i386_follow_jump PARAMS ((void));
- 
  static void codestream_read PARAMS ((unsigned char *, int));
  
  static void codestream_seek PARAMS ((CORE_ADDR));
--- 28,33 ----
*************** static unsigned char 
*** 72,82 ****
  codestream_fill (peek_flag)
      int peek_flag;
  {
    codestream_addr = codestream_next_addr;
    codestream_next_addr += CODESTREAM_BUFSIZ;
    codestream_off = 0;
    codestream_cnt = CODESTREAM_BUFSIZ;
!   read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
    
    if (peek_flag)
      return (codestream_peek());
--- 68,83 ----
  codestream_fill (peek_flag)
      int peek_flag;
  {
+   int status;
+ 
    codestream_addr = codestream_next_addr;
    codestream_next_addr += CODESTREAM_BUFSIZ;
    codestream_off = 0;
    codestream_cnt = CODESTREAM_BUFSIZ;
!   status = read_memory_nobpt (codestream_addr,
! 			      (char *) codestream_buf, CODESTREAM_BUFSIZ);
!   if (status != 0)
!     memory_error (status, codestream_addr);
    
    if (peek_flag)
      return (codestream_peek());
*************** i386_follow_jump ()
*** 161,185 ****
  }
  
  /*
!  * find & return amound a local space allocated, and advance codestream to
!  * first register push (if any)
   *
!  * if entry sequence doesn't make sense, return -1, and leave 
!  * codestream pointer random
   */
  
! static long
! i386_get_frame_setup (pc)
!      CORE_ADDR pc;
  {
    unsigned char op;
  
-   codestream_seek (pc);
- 
-   i386_follow_jump ();
- 
    op = codestream_get ();
- 
    if (op == 0x58)		/* popl %eax */
      {
        /*
--- 162,186 ----
  }
  
  /*
!  * Determine the amount of local space allocated, and advance codestream to
!  * first register push (if any).
   *
!  * If the entry sequence doesn't make sense, then assume it is a frameless
!  * function with no local space.
   */
  
! #define MY_FRAME_IN_SP   0x1
! #define MY_FRAME_IN_FP   0x2
! #define NO_MORE_FRAMES   0x4
! #define INCOMPLETE_FRAME 0x8
! 
! static void
! i386_get_frame_setup (fi)
!      struct frame_info *fi;
  {
    unsigned char op;
  
    op = codestream_get ();
    if (op == 0x58)		/* popl %eax */
      {
        /*
*************** i386_get_frame_setup (pc)
*** 214,285 ****
    if (op == 0x55)		/* pushl %ebp */
      {			
        /* check for movl %esp, %ebp - can be written two ways */
!       switch (codestream_get ())
! 	{
! 	case 0x8b:
! 	  if (codestream_get () != 0xec)
! 	    return (-1);
! 	  break;
! 	case 0x89:
! 	  if (codestream_get () != 0xe5)
! 	    return (-1);
! 	  break;
! 	default:
! 	  return (-1);
  	}
!       /* check for stack adjustment 
!        *
!        *  subl $XXX, %esp
!        *
!        * note: you can't subtract a 16 bit immediate
!        * from a 32 bit reg, so we don't have to worry
!        * about a data16 prefix 
!        */
!       op = codestream_peek ();
!       if (op == 0x83)
  	{
! 	  /* subl with 8 bit immed */
! 	  codestream_get ();
! 	  if (codestream_get () != 0xec)
! 	    /* Some instruction starting with 0x83 other than subl.  */
! 	    {
! 	      codestream_seek (codestream_tell () - 2);
! 	      return 0;
! 	    }
! 	  /* subl with signed byte immediate 
! 	   * (though it wouldn't make sense to be negative)
! 	   */
! 	  return (codestream_get());
  	}
!       else if (op == 0x81)
  	{
! 	  char buf[4];
! 	  /* Maybe it is subl with 32 bit immedediate.  */
! 	  codestream_get();
! 	  if (codestream_get () != 0xec)
! 	    /* Some instruction starting with 0x81 other than subl.  */
! 	    {
! 	      codestream_seek (codestream_tell () - 2);
! 	      return 0;
! 	    }
! 	  /* It is subl with 32 bit immediate.  */
! 	  codestream_read ((unsigned char *)buf, 4);
! 	  return extract_signed_integer (buf, 4);
  	}
!       else
  	{
! 	  return (0);
  	}
      }
!   else if (op == 0xc8)
      {
!       char buf[2];
!       /* enter instruction: arg is 16 bit unsigned immed */
!       codestream_read ((unsigned char *)buf, 2);
!       codestream_get (); /* flush final byte of enter instruction */
!       return extract_unsigned_integer (buf, 2);
      }
!   return (-1);
  }
  
  /* Return number of args passed to a frame.
--- 215,328 ----
    if (op == 0x55)		/* pushl %ebp */
      {			
        /* check for movl %esp, %ebp - can be written two ways */
!       unsigned char buf[2];
!       static unsigned char proto1[2] = { 0x8b,0xec };
!       static unsigned char proto2[2] = { 0x89,0xe5 };
!       codestream_read (buf, sizeof(buf));
!       if (memcmp (buf, proto1, 2) != 0
! 	  && memcmp (buf, proto2, 2) != 0)
! 	{
! 	  /* frameless function with no local space */
! 	  codestream_seek (codestream_tell () - 3);
! 	  return;
  	}
!       fi->status = MY_FRAME_IN_FP;
!     }
!   else if (op == 0xc8)
!     {
!       char buf[2];
!       /* enter instruction: arg is 16 bit unsigned immed */
!       codestream_read ((unsigned char *)buf, 2);
!       codestream_get (); /* flush final byte of enter instruction */
!       fi->status = MY_FRAME_IN_FP;
!       fi->stack_size = extract_unsigned_integer (buf, 2);
!       return;
!     }
!   else
!     codestream_seek (codestream_tell () - 1);
! 
!   if ( (fi->status & MY_FRAME_IN_SP) )
!     fi->stack_mask = -1;
! 
!   /* check for stack alignment 
!    *
!    *  andl $XXX, %esp
!    *
!    * note: you can't and a 16 bit immediate
!    * with a 32 bit reg, so we don't have to worry
!    * about a data16 prefix 
!    */
!   op = codestream_peek ();
!   if (op == 0x83)
!     {
!       /* andl with 8 bit immed */
!       codestream_get ();
!       if (codestream_get () != 0xe4)
! 	/* Some instruction starting with 0x83 other than andl.  */
! 	codestream_seek (codestream_tell () - 2);
!       else
  	{
!           /* andl with signed byte immediate  */
!           fi->stack_mask = (char)codestream_get();
  	}
!     }
!   else if (op == 0x81)
!     {
!       char buf[4];
!       /* Maybe it is andl with 32 bit immediate.  */
!       codestream_get();
!       if (codestream_get () != 0xe4)
! 	/* Some instruction starting with 0x81 other than andl.  */
! 	codestream_seek (codestream_tell () - 2);
!       else
  	{
!           /* It is andl with 32 bit immediate.  */
!           codestream_read ((unsigned char *)buf, 4);
!           fi->stack_mask = extract_signed_integer (buf, 4);
  	}
!     }
! 
!   /* check for stack adjustment 
!    *
!    *  subl $XXX, %esp
!    *
!    * note: you can't subtract a 16 bit immediate
!    * from a 32 bit reg, so we don't have to worry
!    * about a data16 prefix 
!    */
!   op = codestream_peek ();
!   if (op == 0x83)
!     {
!       /* subl with 8 bit immed */
!       codestream_get ();
!       if (codestream_get () != 0xec)
! 	/* Some instruction starting with 0x83 other than subl.  */
  	{
! 	  codestream_seek (codestream_tell () - 2);
! 	  return;
  	}
+       /* subl with signed byte immediate 
+        * (though it wouldn't make sense to be negative)
+        */
+       fi->stack_size = codestream_get();
      }
!   else if (op == 0x81)
      {
!       char buf[4];
!       /* Maybe it is subl with 32 bit immedediate.  */
!       codestream_get();
!       if (codestream_get () != 0xec)
! 	/* Some instruction starting with 0x81 other than subl.  */
! 	{
! 	  codestream_seek (codestream_tell () - 2);
! 	  return;
! 	}
!       /* It is subl with 32 bit immediate.  */
!       codestream_read ((unsigned char *)buf, 4);
!       fi->stack_size = extract_signed_integer (buf, 4);
      }
! 
!   return;
  }
  
  /* Return number of args passed to a frame.
*************** i386_frame_num_args (fi)
*** 358,372 ****
  #endif
  }
  
  /*
!  * parse the first few instructions of the function to see
!  * what registers were stored.
   *
   * We handle these cases:
   *
   * The startup sequence can be at the start of the function,
   * or the function can start with a branch to startup code at the end.
   *
   * %ebp can be set up with either the 'enter' instruction, or 
   * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
   * but was once used in the sys5 compiler)
--- 401,562 ----
  #endif
  }
  
+ #if defined(I386V4_SIGTRAMP_SAVED_PC)
+ /*
+  * Determine the location of the registers saved in the signal context
+  * for all three variants of SVR4 sigtramps.
+  */
+ 
+ static CORE_ADDR
+ i386_sigcontext_addr (fi)
+      struct frame_info *fi;
+ {
+   int offset = 0;
+   char *name = NULL;
+ 
+   find_pc_partial_function (fi->pc, &name, NULL, NULL);
+   if (name)
+     {
+       if (STREQ (name, "_sigreturn"))
+ 	offset = 132;
+       else if (STREQ (name, "_sigacthandler"))
+ 	offset = 80;
+       else if (STREQ (name, "sigvechandler"))
+ 	offset = 120;
+     }
+ 
+   if (offset == 0)
+     return 0;
+ 
+   if (fi->next)
+     return fi->next->frame + offset;
+ 
+   return read_register (SP_REGNUM) + offset;
+ }
+ 
+ /* Get saved user PC for sigtramp from the pushed ucontext on the stack.  */
+ 
+ CORE_ADDR
+ i386v4_sigtramp_saved_pc (fi)
+      struct frame_info *frame;
+ {
+ 
+   return read_memory_integer (i386_sigcontext_addr (fi) + 14 * 4, 4);
+ }
+ 
+ #elif defined(SIGCONTEXT_FP_OFFSET)
+ /*
+  * Determine the location of the signal context.
+  */
+ 
+ static CORE_ADDR
+ i386_sigcontext_addr (fi)
+      struct frame_info *fi;
+ {
+   CORE_ADDR sigcontext_addr;
+   int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+   int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
+ 
+   /* Get sigcontext address, it is the third parameter on the stack.  */
+   if (fi->next)
+     sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (fi->next)
+ 					   + FRAME_ARGS_SKIP
+ 					   + sigcontext_offs,
+ 					   ptrbytes);
+   else
+     sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
+ 					    + sigcontext_offs,
+ 					   ptrbytes);
+ 
+   return sigcontext_addr;
+ }
+ #endif
+ 
  /*
!  * Determine where the registers were stored.
!  */
! 
! static void
! i386_frame_find_saved_regs (fi)
!      struct frame_info *fi;
! {
!   unsigned char op;
!   CORE_ADDR adr;
!   int i;
!   int offset;
!   
!   /*
!    * First determine the offset of each register that has
!    * been placed on the stack.
!    */
! 
!   offset = fi->stack_size;
! 
!   for (i = 0; i < 8; i++) 
!     {
!       op = codestream_peek ();
!       if (op < 0x50 || op > 0x57)
! 	break;
!       codestream_get ();
!       offset += 4;
! #ifdef I386_REGNO_TO_SYMMETRY
!       /* Dynix uses different internal numbering.  Ick.  */
!       fi->fsr.regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = offset;
! #else
!       fi->fsr.regs[op - 0x50] = offset;
! #endif
!     }
! 
!   /*
!    * Then determine the actual location of each register
!    * that has been placed on the stack.
!    */
! 
!   if (fi->status == MY_FRAME_IN_SP)
!     {
!       /* Fix fi->frame if it's bogus at this point.  */
!       if (fi->next == NULL)
! 	fi->frame = read_sp() + offset;
!     }
! 
!   adr = fi->stack_mask ? (fi->frame & fi->stack_mask) : fi->frame;
! 
!   for (i = 0; i < 8; i++) 
!     {
! #ifdef I386_REGNO_TO_SYMMETRY
!       /* Dynix uses different internal numbering.  Ick.  */
!       if (fi->fsr.regs[I386_REGNO_TO_SYMMETRY(i)])
! 	fi->fsr.regs[I386_REGNO_TO_SYMMETRY(i)] =
! 	  adr - fi->fsr.regs[I386_REGNO_TO_SYMMETRY(i)];
! #else
!       if (fi->fsr.regs[i])
! 	fi->fsr.regs[i] = adr - fi->fsr.regs[i];
! #endif
!     }
! 
!   /*
!    * Finally determine where some important registers are located
!    */
! 
!   if (fi->status == MY_FRAME_IN_FP)
!     {
!       fi->fsr.regs[FP_REGNUM] = fi->frame;
!       fi->fsr.regs[PC_REGNUM] = fi->frame + 4;
!     }
!   else if (fi->status == MY_FRAME_IN_SP)
!     fi->fsr.regs[PC_REGNUM] = fi->frame;
! }
! 
! /*
!  * Parse the prologue.
   *
   * We handle these cases:
   *
   * The startup sequence can be at the start of the function,
   * or the function can start with a branch to startup code at the end.
   *
+  * The function can be frameless.
+  *
   * %ebp can be set up with either the 'enter' instruction, or 
   * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
   * but was once used in the sys5 compiler)
*************** i386_frame_num_args (fi)
*** 374,448 ****
   * Local space is allocated just below the saved %ebp by either the
   * 'enter' instruction, or by 'subl $<size>, %esp'.  'enter' has
   * a 16 bit unsigned argument for space to allocate, and the
!  * 'addl' instruction could have either a signed byte, or
   * 32 bit immediate.
   *
   * Next, the registers used by this function are pushed.  In
   * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
   * (and sometimes a harmless bug causes it to also save but not restore %eax);
!  * however, the code below is willing to see the pushes in any order,
   * and will handle up to 8 of them.
   *
   * If the setup sequence is at the end of the function, then the
   * next instruction will be a branch back to the start.
   */
  
! void
! i386_frame_find_saved_regs (fip, fsrp)
!      struct frame_info *fip;
!      struct frame_saved_regs *fsrp;
  {
-   long locals = -1;
-   unsigned char op;
-   CORE_ADDR dummy_bottom;
    CORE_ADDR adr;
!   CORE_ADDR pc;
    int i;
!   
!   memset (fsrp, 0, sizeof *fsrp);
!   
    /* if frame is the end of a dummy, compute where the
     * beginning would be
     */
!   dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
    
    /* check if the PC is in the stack, in a dummy frame */
!   if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) 
      {
!       /* all regs were saved by push_call_dummy () */
!       adr = fip->frame;
        for (i = 0; i < NUM_REGS; i++) 
  	{
  	  adr -= REGISTER_RAW_SIZE (i);
! 	  fsrp->regs[i] = adr;
  	}
        return;
      }
    
!   pc = get_pc_function_start (fip->pc);
!   if (pc != 0)
!     locals = i386_get_frame_setup (pc);
!   
!   if (locals >= 0) 
      {
!       adr = fip->frame - 4 - locals;
!       for (i = 0; i < 8; i++) 
! 	{
! 	  op = codestream_get ();
! 	  if (op < 0x50 || op > 0x57)
! 	    break;
  #ifdef I386_REGNO_TO_SYMMETRY
! 	  /* Dynix uses different internal numbering.  Ick.  */
! 	  fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr;
  #else
! 	  fsrp->regs[op - 0x50] = adr;
  #endif
! 	  adr -= 4;
! 	}
      }
-   
-   fsrp->regs[PC_REGNUM] = fip->frame + 4;
-   fsrp->regs[FP_REGNUM] = fip->frame;
  }
  
  /* return pc of first real instruction */
--- 564,771 ----
   * Local space is allocated just below the saved %ebp by either the
   * 'enter' instruction, or by 'subl $<size>, %esp'.  'enter' has
   * a 16 bit unsigned argument for space to allocate, and the
!  * 'subl' instruction could have either a signed byte, or
   * 32 bit immediate.
   *
   * Next, the registers used by this function are pushed.  In
   * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
   * (and sometimes a harmless bug causes it to also save but not restore %eax);
!  * however, the code is willing to see the pushes in any order,
   * and will handle up to 8 of them.
   *
   * If the setup sequence is at the end of the function, then the
   * next instruction will be a branch back to the start.
   */
  
! static void
! i386_analyze_prologue (fi, skip_prologue)
!     struct frame_info *fi;
!     int skip_prologue;
  {
    CORE_ADDR adr;
!   CORE_ADDR dummy_bottom;
!   CORE_ADDR func_addr, func_end;
!   char *name;
!   unsigned char op;
    int i;
!   int status;
! 
!   /* Find the start of this function.  */
!   status = find_pc_partial_function (fi->pc, &name, &func_addr, &func_end);
! 
!   /* If we're in a sigtramp which has a sigcontext then record the location
!      of the frame and the stack pointer so that i386_frame_chain will work.
!      At some point it may be worth while to also record the location of the
!      other registers.  */
! #if defined(SIGCONTEXT_FP_OFFSET)
!   if (IN_SIGTRAMP (fi->pc, name))
!     {
!       fi->fsr.regs[FP_REGNUM]
! 	= i386_sigcontext_addr (fi) + SIGCONTEXT_FP_OFFSET;
!       fi->fsr.regs[SP_REGNUM]
! 	= i386_sigcontext_addr (fi) + SIGCONTEXT_SP_OFFSET;
!       return;
!     }
! #endif
! 
    /* if frame is the end of a dummy, compute where the
     * beginning would be
     */
!   dummy_bottom = fi->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
    
    /* check if the PC is in the stack, in a dummy frame */
!   if (dummy_bottom <= fi->pc && fi->pc <= fi->frame) 
      {
!       /* all regs were saved by i386_push_dummy_frame */
!       fi->status = MY_FRAME_IN_FP;
!       adr = fi->frame;
        for (i = 0; i < NUM_REGS; i++) 
  	{
  	  adr -= REGISTER_RAW_SIZE (i);
! 	  fi->fsr.regs[i] = adr;
  	}
+       fi->fsr.regs[FP_REGNUM] = fi->frame;
+       fi->fsr.regs[PC_REGNUM] = fi->frame + 4;
        return;
      }
+ 
+   /* If we couldn't find the start of this function then assume that
+      it's frame is in the frame pointer so that we can chain back to
+      a dummy frame.  */
+   if (status == 0)
+     {
+       fi->status = MY_FRAME_IN_FP;
+       return;
+     }
+ 
+   /* If we're in start, then give up.  */
+   if (strcmp (name, "start") == 0)
+     {
+       fi->status = NO_MORE_FRAMES;
+       return;
+     }
+ 
+   /* At the start of a function our frame is in the stack pointer.  */
+   fi->status = MY_FRAME_IN_SP;
+ 
+   /* If we're physically on the first insn of a prologue, then our frame
+      hasn't been allocated yet.  And if we're physically on an "return"
+      instruction, then our frame has already been deallocated.  */
+   if (!skip_prologue)
+     {
+       codestream_seek (fi->pc);
+       op = codestream_peek();
+       if (fi->pc == func_addr
+ 	  || op == 0xc2 || op == 0xc3 || op == 0xca || op == 0xcb)
+ 	{
+ 	  /* Fix fi->frame if it's bogus at this point.  */
+ 	  if (fi->next == NULL)
+ 	    fi->frame = read_sp();
+ 	  fi->fsr.regs[PC_REGNUM] = fi->frame;
+ 	  fi->status = INCOMPLETE_FRAME;
+           return;
+ 	}
+     }
+ 
+   /* Start scanning on the first instruction of this function.  */
+   codestream_seek (func_addr);
+ 
+   i386_follow_jump ();
+ 
+   i386_get_frame_setup (fi);
    
!   i386_frame_find_saved_regs (fi);
! }
! 
! /* Function: frame_chain
!    Figure out and return the caller's frame pointer given current
!    frame_info struct.
! 
!    We don't handle dummy frames yet but we would probably just return the
!    stack pointer that was in use at the time the function call was made?  */
! 
! CORE_ADDR
! i386_frame_chain (fi)
!      struct frame_info *fi;
! {
!   struct frame_info dummy_frame;
! 
!   /* Walk through the prologue to determine the stack size,
!      location of saved registers, end of the prologue, etc.  */
!   if (fi->status == 0)
!     i386_init_extra_frame_info (fi);
! 
!   /* Quit now if i386_analyze_prologue set NO_MORE_FRAMES.  */
!   if (fi->status & NO_MORE_FRAMES)
!     return 0;
! 
!   /* Now that we've analyzed our prologue, determine the frame
!      pointer for our caller.
! 
!      If our caller has a frame pointer, then we need to
!      find the entry value of %ebp to our function.
! 
!        If fsr.regs[FP_REGNUM] is nonzero, then it's at the memory
!        location pointed to by fsr.regs[FP_REGNUM].
! 
!        Else it's still in %ebp.
! 
!      If our caller does not have a frame pointer, then his
!      frame base is fi->frame + <pc save space> +
!      <caller's register save space> + <caller's stack size>
!      assuming that the caller's stack pointer was unchanging.
!        
!      The easiest way to get that info is to analyze our caller's frame.
!      So we set up a dummy frame and call i386_init_extra_frame_info to
!      find stuff for us.  BTW, the actual value of dummy_frame.frame
!      doesn't matter so long as it isn't zero.  */
! 
!   dummy_frame.next = fi;
!   dummy_frame.frame = fi->frame;
!   i386_init_extra_frame_info (&dummy_frame);
! 
!   if (! dummy_frame.status)
!     return fi->frame;
! 
!   if (dummy_frame.status & MY_FRAME_IN_FP)
!     {
!       char buf[MAX_REGISTER_RAW_SIZE];
! 
!       /* Our caller has a frame pointer.  So find the frame in %ebp or
!          in the stack.  */
!       if (fi->fsr.regs[FP_REGNUM])
! 	return read_memory_integer (fi->fsr.regs[FP_REGNUM], 4);
!       get_saved_register(buf, NULL, NULL, fi, FP_REGNUM, NULL);
!       return extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
!     }
!   else
      {
!       int offset;
!       int i;
! 
!       offset = dummy_frame.stack_size;
! 
!       for (i = 0; i < 8; i++)
  #ifdef I386_REGNO_TO_SYMMETRY
! 	/* Dynix uses different internal numbering.  Ick.  */
! 	if (dummy_frame.fsr.regs[I386_REGNO_TO_SYMMETRY(i)])
! 	  offset += 4;
  #else
! 	if (dummy_frame.fsr.regs[i])
! 	  offset += 4;
  #endif
! 
!       if (fi->signal_handler_caller && fi->fsr.regs[SP_REGNUM])
! 	return read_memory_integer (fi->fsr.regs[SP_REGNUM], 4) + offset;
! 
!       offset += (fi->status & MY_FRAME_IN_FP) ? 8 : 4;
! 
!       /* Our caller does not have a frame pointer.  Assume his stack
! 	 pointer was constant which means that his frame starts at
! 	 the base of our frame (fi->frame) + pc save space +
! 	 <his register save space> + <his size>. */
!       return fi->frame + offset;
      }
  }
  
  /* return pc of first real instruction */
*************** i386_skip_prologue (pc)
*** 457,479 ****
  				      0x5b,             /* popl   %ebx */
  				    };
    CORE_ADDR pos;
    
!   if (i386_get_frame_setup (pc) < 0)
!     return (pc);
!   
!   /* found valid frame setup - codestream now points to 
!    * start of push instructions for saving registers
!    */
!   
!   /* skip over register saves */
!   for (i = 0; i < 8; i++)
!     {
!       op = codestream_peek ();
!       /* break if not pushl inst */
!       if (op < 0x50 || op > 0x57) 
! 	break;
!       codestream_get ();
!     }
  
    /* The native cc on SVR4 in -K PIC mode inserts the following code to get
       the address of the global offset table (GOT) into register %ebx.
--- 780,791 ----
  				      0x5b,             /* popl   %ebx */
  				    };
    CORE_ADDR pos;
+   struct frame_info fi;
    
!   fi.frame = 0;
!   fi.pc = pc;
! 
!   i386_analyze_prologue (&fi, 1);
  
    /* The native cc on SVR4 in -K PIC mode inserts the following code to get
       the address of the global offset table (GOT) into register %ebx.
*************** i386_skip_prologue (pc)
*** 525,531 ****
    
    i386_follow_jump ();
    
!   return (codestream_tell ());
  }
  
  void
--- 837,843 ----
    
    i386_follow_jump ();
    
!   return codestream_tell ();
  }
  
  void
*************** void
*** 550,562 ****
  i386_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];
    
-   fp = FRAME_FP (frame);
    get_frame_saved_regs (frame, &fsr);
    for (regnum = 0; regnum < NUM_REGS; regnum++) 
      {
        CORE_ADDR adr;
--- 862,873 ----
  i386_pop_frame ()
  {
    struct frame_info *frame = get_current_frame ();
    int regnum;
    struct frame_saved_regs fsr;
    char regbuf[MAX_REGISTER_RAW_SIZE];
    
    get_frame_saved_regs (frame, &fsr);
+ 
    for (regnum = 0; regnum < NUM_REGS; regnum++) 
      {
        CORE_ADDR adr;
*************** i386_pop_frame ()
*** 568,576 ****
  				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 ();
  }
  
--- 879,887 ----
  				REGISTER_RAW_SIZE (regnum));
  	}
      }
! 
!   write_register (SP_REGNUM, fsr.regs[PC_REGNUM] + 4);
! 
    flush_cached_frames ();
  }
  
*************** i386_extract_return_value(type, regbuf, 
*** 632,665 ****
      }
  }
  
- #ifdef I386V4_SIGTRAMP_SAVED_PC
- /* Get saved user PC for sigtramp from the pushed ucontext on the stack
-    for all three variants of SVR4 sigtramps.  */
- 
- CORE_ADDR
- i386v4_sigtramp_saved_pc (frame)
-      struct frame_info *frame;
- {
-   CORE_ADDR saved_pc_offset = 4;
-   char *name = NULL;
- 
-   find_pc_partial_function (frame->pc, &name, NULL, NULL);
-   if (name)
-     {
-       if (STREQ (name, "_sigreturn"))
- 	saved_pc_offset = 132 + 14 * 4;
-       else if (STREQ (name, "_sigacthandler"))
- 	saved_pc_offset = 80 + 14 * 4;
-       else if (STREQ (name, "sigvechandler"))
- 	saved_pc_offset = 120 + 14 * 4;
-     }
- 
-   if (frame->next)
-     return read_memory_integer (frame->next->frame + saved_pc_offset, 4);
-   return read_memory_integer (read_register (SP_REGNUM) + saved_pc_offset, 4);
- }
- #endif /* I386V4_SIGTRAMP_SAVED_PC */
- 
  #ifdef STATIC_TRANSFORM_NAME
  /* SunPRO encodes the static variables.  This is not related to C++ mangling,
     it is done for C too.  */
--- 943,948 ----
*************** skip_trampoline_code (pc, name)
*** 712,717 ****
--- 995,1029 ----
    return 0;			/* not a trampoline */
  }
  
+ /* Function: init_extra_frame_info
+    Setup the frame's frame pointer, pc, and frame addresses for saved
+    registers.  Most of the work is done in i386_analyze_prologue().
+ 
+    Note that when we are called for the last frame (currently active frame),
+    that fi->pc and fi->frame will already be setup.  However, fi->frame will
+    be valid only if this routine uses FP.  For previous frames, fi->frame will
+    always be correct.  i386_analyze_prologue will fix fi->frame if
+    it's not valid.
+ 
+    We can be called with the PC in the call dummy under two circumstances.
+    First, during normal backtracing, second, while figuring out the frame
+    pointer just prior to calling the target function (see run_stack_dummy).  */
+ 
+ void
+ i386_init_extra_frame_info (fi)
+      struct frame_info *fi;
+ {
+ 
+   if (fi->next)
+     fi->pc = FRAME_SAVED_PC (fi->next);
+ 
+   memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs);
+   fi->status = 0;
+   fi->stack_mask = 0;
+   fi->stack_size = 0;
+ 
+   i386_analyze_prologue (fi, 0);
+ }
  
  void
  _initialize_i386_tdep ()
*** gdb/config/i386/tm-i386.h.ORIGINAL	Thu Jan  4 02:23:24 1996
--- gdb/config/i386/tm-i386.h	Thu Feb 25 22:09:21 1999
*************** extern void i386_extract_return_value PA
*** 188,193 ****
--- 188,204 ----
  
  #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
  
+ #define EXTRA_FRAME_INFO \
+   int status; \
+   int stack_mask; \
+   int stack_size; \
+   struct frame_saved_regs fsr;
+ 
+ #define INIT_EXTRA_FRAME_INFO(fromleaf, fi) i386_init_extra_frame_info (fi)
+ #define INIT_FRAME_PC		/* Not necessary */
+ 
+ extern void i386_init_extra_frame_info PARAMS ((struct frame_info *));
+ 
  /* The following redefines make backtracing through sigtramp work.
     They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp
     from the sigcontext structure which is pushed by the kernel on the
*************** extern void i386_extract_return_value PA
*** 200,235 ****
  
  #define FRAME_CHAIN(thisframe)  \
    ((thisframe)->signal_handler_caller \
!    ? (thisframe)->frame \
     : (!inside_entry_file ((thisframe)->pc) \
!       ? read_memory_integer ((thisframe)->frame, 4) \
        : 0))
  
! /* A macro that tells us whether the function invocation represented
!    by FI does not have a frame on the stack associated with it.  If it
!    does not, FRAMELESS is set to 1, else 0.  */
! 
! #define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
!   do { \
!     if ((FI)->signal_handler_caller) \
!       (FRAMELESS) = 0; \
!     else \
!       (FRAMELESS) = frameless_look_for_prologue(FI); \
!   } while (0)
  
  /* Saved Pc.  Get it from sigcontext if within sigtramp.  */
  
  #define FRAME_SAVED_PC(FRAME) \
    (((FRAME)->signal_handler_caller \
      ? sigtramp_saved_pc (FRAME) \
!     : read_memory_integer ((FRAME)->frame + 4, 4)) \
     )
  
  extern CORE_ADDR sigtramp_saved_pc PARAMS ((struct frame_info *));
  
! #define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
  
! #define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
  
  /* Return number of args passed to a frame.  Can return -1, meaning no way
     to tell, which is typical now that the C compiler delays popping them.  */
--- 211,251 ----
  
  #define FRAME_CHAIN(thisframe)  \
    ((thisframe)->signal_handler_caller \
!    ? i386_frame_chain (thisframe) \
     : (!inside_entry_file ((thisframe)->pc) \
!       ? i386_frame_chain (thisframe) \
        : 0))
  
! extern CORE_ADDR i386_frame_chain PARAMS ((struct frame_info *));
  
  /* Saved Pc.  Get it from sigcontext if within sigtramp.  */
  
  #define FRAME_SAVED_PC(FRAME) \
    (((FRAME)->signal_handler_caller \
      ? sigtramp_saved_pc (FRAME) \
!     : read_memory_integer ((FRAME)->fsr.regs[PC_REGNUM], 4)) \
     )
  
  extern CORE_ADDR sigtramp_saved_pc PARAMS ((struct frame_info *));
  
! /* There are several meanings associated with stack_mask:
! 
!      stack_mask == 0      Both the args and locals use %ebp.
! 
!      stack_mask == -1     Both the args and locals use %esp.
  
!      stack_mask != 0      The args use %ebp and the locals use %esp.
!      && stack_mask != -1  */
! 
! #define FRAME_ARGS_ADDRESS(fi) \
!   (((fi)->stack_mask == -1) \
!    ? ((fi)->frame - (fi)->stack_size) \
!    : (fi)->frame)
! 
! #define FRAME_LOCALS_ADDRESS(fi) \
!   ((fi)->stack_mask \
!    ? (((fi)->frame & (fi)->stack_mask) - (fi)->stack_size) \
!    : (fi)->frame)
  
  /* Return number of args passed to a frame.  Can return -1, meaning no way
     to tell, which is typical now that the C compiler delays popping them.  */
*************** extern int i386_frame_num_args PARAMS ((
*** 248,259 ****
     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) \
! { i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); }
! 
! extern void i386_frame_find_saved_regs PARAMS ((struct frame_info *,
! 						struct frame_saved_regs *));
! 
  
  /* Things needed for making the inferior call functions.  */
  
--- 264,270 ----
     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(fi, regaddr) regaddr = fi->fsr
  
  /* Things needed for making the inferior call functions.  */
  
*** gdb/config/i386/tm-i386bsd.h.ORIGINAL	Sun May 26 17:41:33 1996
--- gdb/config/i386/tm-i386bsd.h	Thu Feb 25 22:09:21 1999
*************** Foundation, Inc., 59 Temple Place - Suit
*** 39,43 ****
--- 39,45 ----
  
  /* Offset to saved PC in sigcontext, from <sys/signal.h>.  */
  #define SIGCONTEXT_PC_OFFSET 20
+ #define SIGCONTEXT_FP_OFFSET 12
+ #define SIGCONTEXT_SP_OFFSET 8
  
  #endif  /* ifndef TM_I386BSD_H */
*** gdb/config/i386/tm-i386sol2.h.ORIGINAL	Sat Apr 11 01:39:47 1998
--- gdb/config/i386/tm-i386sol2.h	Thu Feb 25 22:23:14 1999
*************** Foundation, Inc., 59 Temple Place - Suit
*** 27,33 ****
--- 27,37 ----
     a pointer to an ucontext.  */
  #undef sigtramp_saved_pc
  #undef I386V4_SIGTRAMP_SAVED_PC
+ #undef SIGCONTEXT_FP_OFFSET
+ #undef SIGCONTEXT_SP_OFFSET
  #define SIGCONTEXT_PC_OFFSET (36 + 14 * 4)
+ #define SIGCONTEXT_FP_OFFSET (36 + 6 * 4)
+ #define SIGCONTEXT_SP_OFFSET (36 + 17 * 4)
  #undef IN_SIGTRAMP
  #define IN_SIGTRAMP(pc, name) (pc == 0xFFFFFFFF)
  
*** gdb/config/i386/tm-i386v4.h.ORIGINAL	Thu Nov  2 10:20:44 1995
--- gdb/config/i386/tm-i386v4.h	Thu Feb 25 22:09:21 1999
*************** get_longjmp_target PARAMS ((CORE_ADDR *)
*** 65,70 ****
--- 65,72 ----
     user stack. Unfortunately there are three variants of sigtramp handlers.  */
  
  #define I386V4_SIGTRAMP_SAVED_PC
+ #define SIGCONTEXT_FP_OFFSET (6 * 4)
+ #define SIGCONTEXT_SP_OFFSET (17 * 4)
  #define IN_SIGTRAMP(pc, name) ((name)					\
  			       && (STREQ ("_sigreturn", name)		\
  				   || STREQ ("_sigacthandler", name)	\
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------