Allow PPC users to select which PPC/RS6000 variant they're debugging
[deliverable/binutils-gdb.git] / gdb / blockframe.c
index de2a30be7362d50eee0eb59ae6a0c3b4f993ed55..3cb00c85a48706c0ae209d98008482cc16358e6b 100644 (file)
@@ -1,6 +1,6 @@
 /* Get info from stack frames;
    convert between frames, blocks, functions and pc values.
-   Copyright 1986, 1987, 1988, 1989, 1991, 1994, 1995, 1996
+   Copyright 1986, 87, 88, 89, 91, 94, 95, 96, 97, 1998
              Free Software Foundation, Inc.
 
 This file is part of GDB.
@@ -31,6 +31,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "inferior.h"          /* for read_pc */
 #include "annotate.h"
 
+/* Prototypes for exported functions. */
+
+void _initialize_blockframe PARAMS ((void));
+
 /* Is ADDR inside the startup file?  Note that if your machine
    has a way to detect the bottom of the stack, there is no need
    to call this function from FRAME_CHAIN_VALID; the reason for
@@ -87,8 +91,10 @@ CORE_ADDR pc;
       mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL);
       if (mainsym && SYMBOL_CLASS(mainsym) == LOC_BLOCK)
         {
-          symfile_objfile->ei.main_func_lowpc = BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym));
-          symfile_objfile->ei.main_func_highpc = BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym));
+          symfile_objfile->ei.main_func_lowpc = 
+           BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym));
+          symfile_objfile->ei.main_func_highpc = 
+           BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym));
         }
     }
   return (symfile_objfile -> ei.main_func_lowpc  <= pc &&
@@ -260,6 +266,12 @@ frameless_look_for_prologue (frame)
 #endif
       return after_prologue == func_start;
     }
+  else if (frame->pc == 0)
+    /* A frame with a zero PC is usually created by dereferencing a NULL
+       function pointer, normally causing an immediate core dump of the
+       inferior. Mark function as frameless, as the inferior has no chance
+       of setting up a stack frame.  */
+    return 1;
   else
     /* If we can't find the start of the function, we don't really
        know whether the function is frameless, but we should be able
@@ -529,27 +541,32 @@ get_frame_function (frame)
   return block_function (bl);
 }
 \f
+
 /* Return the blockvector immediately containing the innermost lexical block
-   containing the specified pc value, or 0 if there is none.
+   containing the specified pc value and section, or 0 if there is none.
    PINDEX is a pointer to the index value of the block.  If PINDEX
    is NULL, we don't pass this information back to the caller.  */
 
 struct blockvector *
-blockvector_for_pc (pc, pindex)
+blockvector_for_pc_sect (pc, section, pindex, symtab)
      register CORE_ADDR pc;
+     struct sec *section;
      int *pindex;
+     struct symtab *symtab;
+     
 {
   register struct block *b;
   register int bot, top, half;
-  register struct symtab *s;
   struct blockvector *bl;
 
-  /* First search all symtabs for one whose file contains our pc */
-  s = find_pc_symtab (pc);
-  if (s == 0)
-    return 0;
+  if (symtab == 0)     /* if no symtab specified by caller */
+    {
+      /* First search all symtabs for one whose file contains our pc */
+      if ((symtab = find_pc_sect_symtab (pc, section)) == 0)
+       return 0;
+    }
 
-  bl = BLOCKVECTOR (s);
+  bl = BLOCKVECTOR (symtab);
   b = BLOCKVECTOR_BLOCK (bl, 0);
 
   /* Then search that symtab for the smallest block that wins.  */
@@ -581,45 +598,80 @@ blockvector_for_pc (pc, pindex)
        }
       bot--;
     }
-
   return 0;
 }
 
-/* Return the innermost lexical block containing the specified pc value,
-   or 0 if there is none.  */
+/* Return the blockvector immediately containing the innermost lexical block
+   containing the specified pc value, or 0 if there is none.
+   Backward compatibility, no section.  */
+
+struct blockvector *
+blockvector_for_pc (pc, pindex)
+     register CORE_ADDR pc;
+     int *pindex;
+{
+  return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
+                                 pindex, NULL);
+}
+
+/* Return the innermost lexical block containing the specified pc value
+   in the specified section, or 0 if there is none.  */
 
 struct block *
-block_for_pc (pc)
+block_for_pc_sect (pc, section)
      register CORE_ADDR pc;
+     struct sec *section;
 {
   register struct blockvector *bl;
   int index;
 
-  bl = blockvector_for_pc (pc, &index);
+  bl = blockvector_for_pc_sect (pc, section, &index, NULL);
   if (bl)
     return BLOCKVECTOR_BLOCK (bl, index);
   return 0;
 }
 
-/* Return the function containing pc value PC.
+/* Return the innermost lexical block containing the specified pc value,
+   or 0 if there is none.  Backward compatibility, no section.  */
+
+struct block *
+block_for_pc (pc)
+     register CORE_ADDR pc;
+{
+  return block_for_pc_sect (pc, find_pc_mapped_section (pc));
+}
+
+/* Return the function containing pc value PC in section SECTION.
    Returns 0 if function is not known.  */
 
 struct symbol *
-find_pc_function (pc)
+find_pc_sect_function (pc, section)
      CORE_ADDR pc;
+     struct sec *section;
 {
-  register struct block *b = block_for_pc (pc);
+  register struct block *b = block_for_pc_sect (pc, section);
   if (b == 0)
     return 0;
   return block_function (b);
 }
 
+/* Return the function containing pc value PC.
+   Returns 0 if function is not known.  Backward compatibility, no section */
+
+struct symbol *
+find_pc_function (pc)
+     CORE_ADDR pc;
+{
+  return find_pc_sect_function (pc, find_pc_mapped_section (pc));
+}
+
 /* These variables are used to cache the most recent result
  * of find_pc_partial_function. */
 
-static CORE_ADDR cache_pc_function_low = 0;
-static CORE_ADDR cache_pc_function_high = 0;
-static char *cache_pc_function_name = 0;
+static CORE_ADDR   cache_pc_function_low     = 0;
+static CORE_ADDR   cache_pc_function_high    = 0;
+static char       *cache_pc_function_name    = 0;
+static struct sec *cache_pc_function_section = NULL;
 
 /* Clear cache, e.g. when symbol table is discarded. */
 
@@ -629,50 +681,58 @@ clear_pc_function_cache()
   cache_pc_function_low = 0;
   cache_pc_function_high = 0;
   cache_pc_function_name = (char *)0;
+  cache_pc_function_section = NULL;
 }
 
 /* Finds the "function" (text symbol) that is smaller than PC but
-   greatest of all of the potential text symbols.  Sets *NAME and/or
-   *ADDRESS conditionally if that pointer is non-null.  If ENDADDR is
-   non-null, then set *ENDADDR to be the end of the function
-   (exclusive), but passing ENDADDR as non-null means that the
-   function might cause symbols to be read.  This function either
+   greatest of all of the potential text symbols in SECTION.  Sets
+   *NAME and/or *ADDRESS conditionally if that pointer is non-null.
+   If ENDADDR is non-null, then set *ENDADDR to be the end of the
+   function (exclusive), but passing ENDADDR as non-null means that
+   the function might cause symbols to be read.  This function either
    succeeds or fails (not halfway succeeds).  If it succeeds, it sets
    *NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
-   If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero
-   and returns 0.  */
+   If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero and
+   returns 0.  */
 
 int
-find_pc_partial_function (pc, name, address, endaddr)
-     CORE_ADDR pc;
-     char **name;
+find_pc_sect_partial_function (pc, section, name, address, endaddr)
+     CORE_ADDR  pc;
+     asection  *section;
+     char     **name;
      CORE_ADDR *address;
      CORE_ADDR *endaddr;
 {
   struct partial_symtab *pst;
-  struct symbol *f;
+  struct symbol         *f;
   struct minimal_symbol *msymbol;
   struct partial_symbol *psb;
-  struct obj_section *sec;
+  struct obj_section    *osect;
+  int i;
+  CORE_ADDR mapped_pc;
 
-  if (pc >= cache_pc_function_low && pc < cache_pc_function_high)
+  mapped_pc = overlay_mapped_address (pc, section);
+
+  if (mapped_pc >= cache_pc_function_low && 
+      mapped_pc < cache_pc_function_high &&
+      section == cache_pc_function_section)
     goto return_cached_value;
 
   /* If sigtramp is in the u area, it counts as a function (especially
      important for step_1).  */
 #if defined SIGTRAMP_START
-  if (IN_SIGTRAMP (pc, (char *)NULL))
+  if (IN_SIGTRAMP (mapped_pc, (char *)NULL))
     {
-      cache_pc_function_low = SIGTRAMP_START (pc);
-      cache_pc_function_high = SIGTRAMP_END (pc);
-      cache_pc_function_name = "<sigtramp>";
-
+      cache_pc_function_low     = SIGTRAMP_START (mapped_pc);
+      cache_pc_function_high    = SIGTRAMP_END (mapped_pc);
+      cache_pc_function_name    = "<sigtramp>";
+      cache_pc_function_section = section;
       goto return_cached_value;
     }
 #endif
 
-  msymbol = lookup_minimal_symbol_by_pc (pc);
-  pst = find_pc_psymtab (pc);
+  msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
+  pst = find_pc_sect_psymtab (mapped_pc, section);
   if (pst)
     {
       /* Need to read the symbols to get a good value for the end address.  */
@@ -688,15 +748,16 @@ find_pc_partial_function (pc, name, address, endaddr)
        {
          /* Checking whether the msymbol has a larger value is for the
             "pathological" case mentioned in print_frame_info.  */
-         f = find_pc_function (pc);
+         f = find_pc_sect_function (mapped_pc, section);
          if (f != NULL
              && (msymbol == NULL
                  || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
                      >= SYMBOL_VALUE_ADDRESS (msymbol))))
            {
-             cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
-             cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
-             cache_pc_function_name = SYMBOL_NAME (f);
+             cache_pc_function_low     = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
+             cache_pc_function_high    = BLOCK_END   (SYMBOL_BLOCK_VALUE (f));
+             cache_pc_function_name    = SYMBOL_NAME (f);
+             cache_pc_function_section = section;
              goto return_cached_value;
            }
        }
@@ -705,7 +766,7 @@ find_pc_partial_function (pc, name, address, endaddr)
          /* Now that static symbols go in the minimal symbol table, perhaps
             we could just ignore the partial symbols.  But at least for now
             we use the partial or minimal symbol, whichever is larger.  */
-         psb = find_pc_psymbol (pst, pc);
+         psb = find_pc_sect_psymbol (pst, mapped_pc, section);
 
          if (psb
              && (msymbol == NULL ||
@@ -728,9 +789,9 @@ find_pc_partial_function (pc, name, address, endaddr)
      of the text seg doesn't appear to be part of the last function in the
      text segment.  */
 
-  sec = find_pc_section (pc);
+  osect = find_pc_sect_section (mapped_pc, section);
 
-  if (!sec)
+  if (!osect)
     msymbol = NULL;
 
   /* Must be in the minimal symbol table.  */
@@ -746,30 +807,79 @@ find_pc_partial_function (pc, name, address, endaddr)
       return 0;
     }
 
-  cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
-  cache_pc_function_name = SYMBOL_NAME (msymbol);
+  cache_pc_function_low     = SYMBOL_VALUE_ADDRESS (msymbol);
+  cache_pc_function_name    = SYMBOL_NAME (msymbol);
+  cache_pc_function_section = section;
 
-  /* Use the lesser of the next minimal symbol, or the end of the section, as
-     the end of the function.  */
+  /* Use the lesser of the next minimal symbol in the same section, or
+     the end of the section, as the end of the function.  */
+  
+  /* Step over other symbols at this same address, and symbols in
+     other sections, to find the next symbol in this section with
+     a different address.  */
 
-  if (SYMBOL_NAME (msymbol + 1) != NULL
-      && SYMBOL_VALUE_ADDRESS (msymbol + 1) < sec->endaddr)
-    cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + 1);
+  for (i=1; SYMBOL_NAME (msymbol+i) != NULL; i++)
+    {
+      if (SYMBOL_VALUE_ADDRESS (msymbol+i) != SYMBOL_VALUE_ADDRESS (msymbol) 
+         && SYMBOL_BFD_SECTION (msymbol+i) == SYMBOL_BFD_SECTION (msymbol))
+       break;
+    }
+
+  if (SYMBOL_NAME (msymbol + i) != NULL
+      && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr)
+    cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
   else
     /* We got the start address from the last msymbol in the objfile.
        So the end address is the end of the section.  */
-    cache_pc_function_high = sec->endaddr;
+    cache_pc_function_high = osect->endaddr;
 
  return_cached_value:
+
   if (address)
-    *address = cache_pc_function_low;
+    {
+      if (pc_in_unmapped_range (pc, section))
+        *address = overlay_unmapped_address (cache_pc_function_low, section);
+      else
+        *address = cache_pc_function_low;
+    }
+    
   if (name)
     *name = cache_pc_function_name;
+
   if (endaddr)
-    *endaddr = cache_pc_function_high;
+    {
+      if (pc_in_unmapped_range (pc, section))
+        {
+         /* Because the high address is actually beyond the end of
+            the function (and therefore possibly beyond the end of
+            the overlay), we must actually convert (high - 1)
+            and then add one to that. */
+
+         *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1, 
+                                                  section);
+        }
+      else
+        *endaddr = cache_pc_function_high;
+    }
+
   return 1;
 }
 
+/* Backward compatibility, no section argument */
+
+int
+find_pc_partial_function (pc, name, address, endaddr)
+     CORE_ADDR  pc;
+     char     **name;
+     CORE_ADDR *address;
+     CORE_ADDR *endaddr;
+{
+  asection     *section;
+
+  section = find_pc_overlay (pc);
+  return find_pc_sect_partial_function (pc, section, name, address, endaddr);
+}
+
 /* Return the innermost stack frame executing inside of BLOCK,
    or NULL if there is no such frame.  If BLOCK is NULL, just return NULL.  */
 
@@ -850,20 +960,23 @@ sigtramp_saved_pc (frame)
 }
 #endif /* SIGCONTEXT_PC_OFFSET */
 
+#ifdef USE_GENERIC_DUMMY_FRAMES
+
 /*
- * DUMMY FRAMES
+ * GENERIC DUMMY FRAMES
  * 
  * The following code serves to maintain the dummy stack frames for
  * inferior function calls (ie. when gdb calls into the inferior via
  * call_function_by_hand).  This code saves the machine state before 
- * the call in host memory, so it must maintain an independant stack 
+ * the call in host memory, so we must maintain an independant stack 
  * and keep it consistant etc.  I am attempting to make this code 
  * generic enough to be used by many targets.
  *
  * The cheapest and most generic way to do CALL_DUMMY on a new target
  * is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to zero,
  * and CALL_DUMMY_LOCATION to AT_ENTRY.  Then you must remember to define
- * PUSH_RETURN_ADDRESS, because there won't be a call instruction to do it.
+ * PUSH_RETURN_ADDRESS, because no call instruction will be being
+ * executed by the target.
  */
 
 static struct dummy_frame *dummy_frame_stack = NULL;
@@ -878,51 +991,16 @@ generic_find_dummy_frame (pc, fp)
      CORE_ADDR fp;
 {
   struct dummy_frame * dummyframe;
-#ifdef NEED_TEXT_START_END
-  CORE_ADDR bkpt_address;
-  extern CORE_ADDR text_end;
-#endif
 
-#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
   if (pc != entry_point_address ())
     return 0;
-#endif /* AT_ENTRY_POINT */
-
-#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
-  bkpt_address = text_end - CALL_DUMMY_LENGTH + CALL_DUMMY_BREAKPOINT_OFFSET;
-  if (pc != bkpt_address)
-    return 0;
-#endif /* BEFORE_TEXT_END */
-
-#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
-  bkpt_address = text_end + CALL_DUMMY_BREAKPOINT_OFFSET;
-  if (pc != bkpt_address)
-    return 0;
-#endif /* AFTER_TEXT_END */
-
-#if CALL_DUMMY_LOCATION == ON_STACK
-  /* compute the displacement from the CALL_DUMMY breakpoint 
-     to the frame pointer */
-  if (1 INNER_THAN 2)
-    pc += CALL_DUMMY_LENGTH - CALL_DUMMY_BREAKPOINT_OFFSET;
-  else
-    pc += CALL_DUMMY_BREAKPOINT_OFFSET;
-#endif /* ON_STACK */
 
   for (dummyframe = dummy_frame_stack; dummyframe != NULL;
        dummyframe = dummyframe->next)
     if (fp == dummyframe->fp || fp == dummyframe->sp)
-      {
-       /* The frame in question lies between the saved fp and sp, inclusive */
-#if CALL_DUMMY_LOCATION == ON_STACK
-       /* NOTE: a better way to do this might be simply to test whether 
-          the pc lies between the saved (sp, fp) and CALL_DUMMY_LENGTH.
-          */
-
-       if (pc == dummyframe->fp || pc == dummyframe->sp)
-#endif /* ON_STACK */
-         return dummyframe->regs;
-      }
+      /* The frame in question lies between the saved fp and sp, inclusive */
+      return dummyframe->regs;
+
   return 0;
 }
 
@@ -975,7 +1053,7 @@ generic_push_dummy_frame ()
 
   dummy_frame = dummy_frame_stack;
   while (dummy_frame)
-    if (dummy_frame->fp INNER_THAN fp) /* stale -- destroy! */
+    if (INNER_THAN (dummy_frame->fp, fp))      /* stale -- destroy! */
       {
        dummy_frame_stack = dummy_frame->next;
        free (dummy_frame);
@@ -993,6 +1071,21 @@ generic_push_dummy_frame ()
   dummy_frame_stack = dummy_frame;
 }
 
+/* Function: pop_frame
+   Restore the machine state from either the saved dummy stack or a
+   real stack frame. */
+
+void
+generic_pop_current_frame (pop)
+  void (*pop) PARAMS ((struct frame_info *frame));
+{
+  struct frame_info *frame = get_current_frame ();
+  if (PC_IN_CALL_DUMMY(frame->pc, frame->frame, frame->frame))
+    generic_pop_dummy_frame ();
+  else
+    pop (frame);
+}
+
 /* Function: pop_dummy_frame
    Restore the machine state from a saved dummy stack frame. */
 
@@ -1008,6 +1101,7 @@ generic_pop_dummy_frame ()
     error ("Can't pop dummy frame!");
   dummy_frame_stack = dummy_frame->next;
   write_register_bytes (0, dummy_frame->regs, REGISTER_BYTES);
+  flush_cached_frames ();
   free (dummy_frame);
 }
 
@@ -1020,12 +1114,12 @@ generic_frame_chain_valid (fp, fi)
      CORE_ADDR fp;
      struct frame_info *fi;
 {
-#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT
   if (PC_IN_CALL_DUMMY(FRAME_SAVED_PC(fi), fp, fp))
     return 1;   /* don't prune CALL_DUMMY frames */
   else          /* fall back to default algorithm (see frame.h) */
-#endif
-    return (fp != 0 && !inside_entry_file (FRAME_SAVED_PC(fi)));
+    return (fp != 0
+           && (INNER_THAN (fi->frame, fp) || fi->frame == fp)
+           && !inside_entry_file (FRAME_SAVED_PC(fi)));
 }
  
 /* Function: get_saved_register
@@ -1061,7 +1155,6 @@ generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
      int regnum;
      enum lval_type *lval;
 {
-  CORE_ADDR addr;
   struct frame_saved_regs fsr;
 
   if (!target_has_registers)
@@ -1079,7 +1172,7 @@ generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
      the current frame itself: otherwise, we would be getting the
      previous frame's registers which were saved by the current frame.  */
 
-  while ((frame = frame->next) != NULL)
+  while (frame && ((frame = frame->next) != NULL))
     {
       if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
        {
@@ -1126,6 +1219,7 @@ generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
   if (raw_buffer)
     read_register_gen (regnum, raw_buffer);
 }
+#endif /* USE_GENERIC_DUMMY_FRAMES */
 
 void
 _initialize_blockframe ()
This page took 0.029279 seconds and 4 git commands to generate.