* hppa-tdep.c (pc_in_linker_stub): New function.
[deliverable/binutils-gdb.git] / gdb / hppa-tdep.c
index 2163ed5d8d16db8467d47177861f99ef060c9db7..6d3929e394b80a0a59369c90454f752bfcd53714 100644 (file)
@@ -61,6 +61,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 static int restore_pc_queue PARAMS ((struct frame_saved_regs *fsr));
 static int hppa_alignof PARAMS ((struct type *arg));
+CORE_ADDR frame_saved_pc PARAMS ((FRAME frame));
 
 \f
 /* Routines to extract various sized constants out of hppa 
@@ -295,6 +296,72 @@ find_unwind_entry(pc)
   return NULL;
 }
 
+/* Called when no unwind descriptor was found for PC.  Returns 1 if it
+   appears that PC is in a linker stub.  */
+static int pc_in_linker_stub PARAMS ((CORE_ADDR));
+
+static int
+pc_in_linker_stub (pc)
+     CORE_ADDR pc;
+{
+  int found_magic_instruction = 0;
+  int i;
+
+  /* We are looking for something like
+
+     ; $$dyncall jams RP into this special spot in the frame (RP')
+     ; before calling the "call stub"
+     ldw     -18(sp),rp
+
+     ldsid   (rp),r1         ; Get space associated with RP into r1
+     mtsp    r1,sp           ; Move it into space register 0
+     be,n    0(sr0),rp)      ; back to your regularly scheduled program
+     */
+
+  /* Maximum known linker stub size is 4 instructions.  Search forward
+     from the given PC, then backward.  */
+  for (i = 0; i < 4; i++)
+    {
+      /* If we hit something with an unwind, stop searching this direction.  
+
+      if (find_unwind_entry (pc + i * 4) != 0)
+       break;
+
+      /* Check for ldsid (rp),r1 which is the magic instruction for a 
+        return from a cross-space function call.  */
+      if (read_memory_integer (pc + i * 4, 4) == 0x004010a1)
+       {
+         found_magic_instruction = 1;
+         break;
+       }
+      /* Add code to handle long call/branch and argument relocation stubs
+        here.  */
+    }
+
+  if (found_magic_instruction != 0)
+    return 1;
+
+  /* Now look backward.  */
+  for (i = 0; i < 4; i++)
+    {
+      /* If we hit something with an unwind, stop searching this direction.  
+
+      if (find_unwind_entry (pc - i * 4) != 0)
+       break;
+
+      /* Check for ldsid (rp),r1 which is the magic instruction for a 
+        return from a cross-space function call.  */
+      if (read_memory_integer (pc - i * 4, 4) == 0x004010a1)
+       {
+         found_magic_instruction = 1;
+         break;
+       }
+      /* Add code to handle long call/branch and argument relocation stubs
+        here.  */
+    }
+  return found_magic_instruction;
+}
+
 static int
 find_return_regnum(pc)
      CORE_ADDR pc;
@@ -312,6 +379,7 @@ find_return_regnum(pc)
   return RP_REGNUM;
 }
 
+/* Return size of frame, or -1 if we should use a frame pointer.  */
 int
 find_proc_framesize(pc)
      CORE_ADDR pc;
@@ -324,27 +392,68 @@ find_proc_framesize(pc)
   u = find_unwind_entry (pc);
 
   if (!u)
+    {
+      if (pc_in_linker_stub (pc))
+       /* Linker stubs have a zero size frame.  */
+       return 0;
+      else
+       return -1;
+    }
+
+  if (u->Save_SP)
+    /* If this bit is set, it means there is a frame pointer and we should
+       use it.  */
     return -1;
 
   return u->Total_frame_size << 3;
 }
 
-int
-rp_saved(pc)
+/* Return offset from sp at which rp is saved, or 0 if not saved.  */
+static int rp_saved PARAMS ((CORE_ADDR));
+
+static int
+rp_saved (pc)
+     CORE_ADDR pc;
 {
   struct unwind_table_entry *u;
 
   u = find_unwind_entry (pc);
 
   if (!u)
-    return 0;
+    {
+      if (pc_in_linker_stub (pc))
+       /* This is the so-called RP'.  */
+       return -24;
+      else
+       return 0;
+    }
 
   if (u->Save_RP)
-    return 1;
+    return -20;
   else
     return 0;
 }
 \f
+int
+frameless_function_invocation (frame)
+     FRAME frame;
+{
+
+  if (use_unwind)
+    {
+      struct unwind_table_entry *u;
+
+      u = find_unwind_entry (frame->pc);
+
+      if (u == 0)
+       return 0;
+
+      return (u->Total_frame_size == 0);
+    }
+  else
+    return frameless_look_for_prologue (frame);
+}
+
 CORE_ADDR
 saved_pc_after_call (frame)
      FRAME frame;
@@ -362,7 +471,7 @@ frame_saved_pc (frame)
 {
   CORE_ADDR pc = get_frame_pc (frame);
 
-  if (frameless_look_for_prologue (frame))
+  if (frameless_function_invocation (frame))
     {
       int ret_regnum;
 
@@ -370,10 +479,15 @@ frame_saved_pc (frame)
 
       return read_register (ret_regnum) & ~0x3;
     }
-  else if (rp_saved (pc))
-    return read_memory_integer (frame->frame - 20, 4) & ~0x3;
   else
-    return read_register (RP_REGNUM) & ~0x3;
+    {
+      int rp_offset = rp_saved (pc);
+
+      if (rp_offset == 0)
+       return read_register (RP_REGNUM) & ~0x3;
+      else
+       return read_memory_integer (frame->frame - rp_offset, 4) & ~0x3;
+    }
 }
 \f
 /* We need to correct the PC and the FP for the outermost frame when we are
@@ -401,7 +515,7 @@ init_extra_frame_info (fromleaf, frame)
   else
     frame->frame = read_register (SP_REGNUM) - framesize;
 
-  if (!frameless_look_for_prologue (frame)) /* Frameless? */
+  if (!frameless_function_invocation (frame)) /* Frameless? */
     return;                                /* No, quit now */
 
   /* For frameless functions, we need to look at the caller's frame */
@@ -444,10 +558,19 @@ frame_chain_valid (chain, thisframe)
 
       u = find_unwind_entry (thisframe->pc);
 
-      if (u && (u->Save_SP || u->Total_frame_size))
-       return 1;
-      else
+      if (u == NULL)
+       /* FIXME, we should probably fall back to some other technique,
+          if we want to deal gracefully with stripped executables or others
+          without unwind info.  */
        return 0;
+
+      if (u->Save_SP || u->Total_frame_size)
+       return 1;
+
+      if (pc_in_linker_stub (thisframe->pc))
+       return 1;
+
+      return 0;
     }
   else
     {
@@ -653,7 +776,7 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
      CORE_ADDR struct_addr;
 {
   /* array of arguments' offsets */
-  int *offset = (int *)alloca(nargs);
+  int *offset = (int *)alloca(nargs * sizeof (int));
   int cum = 0;
   int i, alignment;
   
@@ -671,7 +794,7 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
        cum = (cum + alignment) & -alignment;
       offset[i] = -cum;
     }
-  sp += min ((cum + 7) & -8, 16);
+  sp += max ((cum + 7) & -8, 16);
 
   for (i = 0; i < nargs; i++)
     write_memory (sp + offset[i], VALUE_CONTENTS (args[i]),
@@ -876,11 +999,12 @@ CORE_ADDR
 skip_prologue(pc)
      CORE_ADDR pc;
 {
-  int inst;
+  char buf[4];
+  unsigned long inst;
   int status;
 
-  status = target_read_memory (pc, (char *)&inst, 4);
-  SWAP_TARGET_AND_HOST (&inst, sizeof (inst));
+  status = target_read_memory (pc, buf, 4);
+  inst = extract_unsigned_integer (buf, 4);
   if (status != 0)
     return pc;
 
@@ -931,7 +1055,7 @@ unwind_command (exp, from_tty)
 }
 
 void
-_initialize_hppah_tdep ()
+_initialize_hppa_tdep ()
 {
   add_com ("unwind", class_obscure, unwind_command, "Print unwind info\n");
   add_show_from_set
This page took 0.026221 seconds and 4 git commands to generate.