OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [blockframe.c] - Diff between revs 105 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 105 Rev 1765
/* Get info from stack frames;
/* Get info from stack frames;
   convert between frames, blocks, functions and pc values.
   convert between frames, blocks, functions and pc values.
   Copyright 1986, 87, 88, 89, 91, 94, 95, 96, 97, 1998
   Copyright 1986, 87, 88, 89, 91, 94, 95, 96, 97, 1998
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */
   Boston, MA 02111-1307, USA.  */
 
 
#include "defs.h"
#include "defs.h"
#include "symtab.h"
#include "symtab.h"
#include "bfd.h"
#include "bfd.h"
#include "symfile.h"
#include "symfile.h"
#include "objfiles.h"
#include "objfiles.h"
#include "frame.h"
#include "frame.h"
#include "gdbcore.h"
#include "gdbcore.h"
#include "value.h"              /* for read_register */
#include "value.h"              /* for read_register */
#include "target.h"             /* for target_has_stack */
#include "target.h"             /* for target_has_stack */
#include "inferior.h"           /* for read_pc */
#include "inferior.h"           /* for read_pc */
#include "annotate.h"
#include "annotate.h"
 
 
/* Prototypes for exported functions. */
/* Prototypes for exported functions. */
 
 
void _initialize_blockframe (void);
void _initialize_blockframe (void);
 
 
/* A default FRAME_CHAIN_VALID, in the form that is suitable for most
/* A default FRAME_CHAIN_VALID, in the form that is suitable for most
   targets.  If FRAME_CHAIN_VALID returns zero it means that the given
   targets.  If FRAME_CHAIN_VALID returns zero it means that the given
   frame is the outermost one and has no caller. */
   frame is the outermost one and has no caller. */
 
 
int
int
file_frame_chain_valid (chain, thisframe)
file_frame_chain_valid (chain, thisframe)
     CORE_ADDR chain;
     CORE_ADDR chain;
     struct frame_info *thisframe;
     struct frame_info *thisframe;
{
{
  return ((chain) != 0
  return ((chain) != 0
          && !inside_entry_file (FRAME_SAVED_PC (thisframe)));
          && !inside_entry_file (FRAME_SAVED_PC (thisframe)));
}
}
 
 
/* Use the alternate method of avoiding running up off the end of the
/* Use the alternate method of avoiding running up off the end of the
   frame chain or following frames back into the startup code.  See
   frame chain or following frames back into the startup code.  See
   the comments in objfiles.h. */
   the comments in objfiles.h. */
 
 
int
int
func_frame_chain_valid (chain, thisframe)
func_frame_chain_valid (chain, thisframe)
     CORE_ADDR chain;
     CORE_ADDR chain;
     struct frame_info *thisframe;
     struct frame_info *thisframe;
{
{
  return ((chain) != 0
  return ((chain) != 0
          && !inside_main_func ((thisframe)->pc)
          && !inside_main_func ((thisframe)->pc)
          && !inside_entry_func ((thisframe)->pc));
          && !inside_entry_func ((thisframe)->pc));
}
}
 
 
/* A very simple method of determining a valid frame */
/* A very simple method of determining a valid frame */
 
 
int
int
nonnull_frame_chain_valid (chain, thisframe)
nonnull_frame_chain_valid (chain, thisframe)
     CORE_ADDR chain;
     CORE_ADDR chain;
     struct frame_info *thisframe;
     struct frame_info *thisframe;
{
{
  return ((chain) != 0);
  return ((chain) != 0);
}
}
 
 
/* Is ADDR inside the startup file?  Note that if your machine
/* 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
   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
   to call this function from FRAME_CHAIN_VALID; the reason for
   doing so is that some machines have no way of detecting bottom
   doing so is that some machines have no way of detecting bottom
   of stack.
   of stack.
 
 
   A PC of zero is always considered to be the bottom of the stack. */
   A PC of zero is always considered to be the bottom of the stack. */
 
 
int
int
inside_entry_file (addr)
inside_entry_file (addr)
     CORE_ADDR addr;
     CORE_ADDR addr;
{
{
  if (addr == 0)
  if (addr == 0)
    return 1;
    return 1;
  if (symfile_objfile == 0)
  if (symfile_objfile == 0)
    return 0;
    return 0;
  if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
  if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
    {
    {
      /* Do not stop backtracing if the pc is in the call dummy
      /* Do not stop backtracing if the pc is in the call dummy
         at the entry point.  */
         at the entry point.  */
      /* FIXME: Won't always work with zeros for the last two arguments */
      /* FIXME: Won't always work with zeros for the last two arguments */
      if (PC_IN_CALL_DUMMY (addr, 0, 0))
      if (PC_IN_CALL_DUMMY (addr, 0, 0))
        return 0;
        return 0;
    }
    }
  return (addr >= symfile_objfile->ei.entry_file_lowpc &&
  return (addr >= symfile_objfile->ei.entry_file_lowpc &&
          addr < symfile_objfile->ei.entry_file_highpc);
          addr < symfile_objfile->ei.entry_file_highpc);
}
}
 
 
/* Test a specified PC value to see if it is in the range of addresses
/* Test a specified PC value to see if it is in the range of addresses
   that correspond to the main() function.  See comments above for why
   that correspond to the main() function.  See comments above for why
   we might want to do this.
   we might want to do this.
 
 
   Typically called from FRAME_CHAIN_VALID.
   Typically called from FRAME_CHAIN_VALID.
 
 
   A PC of zero is always considered to be the bottom of the stack. */
   A PC of zero is always considered to be the bottom of the stack. */
 
 
int
int
inside_main_func (pc)
inside_main_func (pc)
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  if (pc == 0)
  if (pc == 0)
    return 1;
    return 1;
  if (symfile_objfile == 0)
  if (symfile_objfile == 0)
    return 0;
    return 0;
 
 
  /* If the addr range is not set up at symbol reading time, set it up now.
  /* If the addr range is not set up at symbol reading time, set it up now.
     This is for FRAME_CHAIN_VALID_ALTERNATE. I do this for coff, because
     This is for FRAME_CHAIN_VALID_ALTERNATE. I do this for coff, because
     it is unable to set it up and symbol reading time. */
     it is unable to set it up and symbol reading time. */
 
 
  if (symfile_objfile->ei.main_func_lowpc == INVALID_ENTRY_LOWPC &&
  if (symfile_objfile->ei.main_func_lowpc == INVALID_ENTRY_LOWPC &&
      symfile_objfile->ei.main_func_highpc == INVALID_ENTRY_HIGHPC)
      symfile_objfile->ei.main_func_highpc == INVALID_ENTRY_HIGHPC)
    {
    {
      struct symbol *mainsym;
      struct symbol *mainsym;
 
 
      mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL);
      mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL);
      if (mainsym && SYMBOL_CLASS (mainsym) == LOC_BLOCK)
      if (mainsym && SYMBOL_CLASS (mainsym) == LOC_BLOCK)
        {
        {
          symfile_objfile->ei.main_func_lowpc =
          symfile_objfile->ei.main_func_lowpc =
            BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym));
            BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym));
          symfile_objfile->ei.main_func_highpc =
          symfile_objfile->ei.main_func_highpc =
            BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym));
            BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym));
        }
        }
    }
    }
  return (symfile_objfile->ei.main_func_lowpc <= pc &&
  return (symfile_objfile->ei.main_func_lowpc <= pc &&
          symfile_objfile->ei.main_func_highpc > pc);
          symfile_objfile->ei.main_func_highpc > pc);
}
}
 
 
/* Test a specified PC value to see if it is in the range of addresses
/* Test a specified PC value to see if it is in the range of addresses
   that correspond to the process entry point function.  See comments
   that correspond to the process entry point function.  See comments
   in objfiles.h for why we might want to do this.
   in objfiles.h for why we might want to do this.
 
 
   Typically called from FRAME_CHAIN_VALID.
   Typically called from FRAME_CHAIN_VALID.
 
 
   A PC of zero is always considered to be the bottom of the stack. */
   A PC of zero is always considered to be the bottom of the stack. */
 
 
int
int
inside_entry_func (pc)
inside_entry_func (pc)
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  if (pc == 0)
  if (pc == 0)
    return 1;
    return 1;
  if (symfile_objfile == 0)
  if (symfile_objfile == 0)
    return 0;
    return 0;
  if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
  if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
    {
    {
      /* Do not stop backtracing if the pc is in the call dummy
      /* Do not stop backtracing if the pc is in the call dummy
         at the entry point.  */
         at the entry point.  */
      /* FIXME: Won't always work with zeros for the last two arguments */
      /* FIXME: Won't always work with zeros for the last two arguments */
      if (PC_IN_CALL_DUMMY (pc, 0, 0))
      if (PC_IN_CALL_DUMMY (pc, 0, 0))
        return 0;
        return 0;
    }
    }
  return (symfile_objfile->ei.entry_func_lowpc <= pc &&
  return (symfile_objfile->ei.entry_func_lowpc <= pc &&
          symfile_objfile->ei.entry_func_highpc > pc);
          symfile_objfile->ei.entry_func_highpc > pc);
}
}
 
 
/* Info about the innermost stack frame (contents of FP register) */
/* Info about the innermost stack frame (contents of FP register) */
 
 
static struct frame_info *current_frame;
static struct frame_info *current_frame;
 
 
/* Cache for frame addresses already read by gdb.  Valid only while
/* Cache for frame addresses already read by gdb.  Valid only while
   inferior is stopped.  Control variables for the frame cache should
   inferior is stopped.  Control variables for the frame cache should
   be local to this module.  */
   be local to this module.  */
 
 
static struct obstack frame_cache_obstack;
static struct obstack frame_cache_obstack;
 
 
void *
void *
frame_obstack_alloc (size)
frame_obstack_alloc (size)
     unsigned long size;
     unsigned long size;
{
{
  return obstack_alloc (&frame_cache_obstack, size);
  return obstack_alloc (&frame_cache_obstack, size);
}
}
 
 
void
void
frame_saved_regs_zalloc (fi)
frame_saved_regs_zalloc (fi)
     struct frame_info *fi;
     struct frame_info *fi;
{
{
  fi->saved_regs = (CORE_ADDR *)
  fi->saved_regs = (CORE_ADDR *)
    frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
    frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
  memset (fi->saved_regs, 0, SIZEOF_FRAME_SAVED_REGS);
  memset (fi->saved_regs, 0, SIZEOF_FRAME_SAVED_REGS);
}
}
 
 
 
 
/* Return the innermost (currently executing) stack frame.  */
/* Return the innermost (currently executing) stack frame.  */
 
 
struct frame_info *
struct frame_info *
get_current_frame ()
get_current_frame ()
{
{
  if (current_frame == NULL)
  if (current_frame == NULL)
    {
    {
      if (target_has_stack)
      if (target_has_stack)
        current_frame = create_new_frame (read_fp (), read_pc ());
        current_frame = create_new_frame (read_fp (), read_pc ());
      else
      else
        error ("No stack.");
        error ("No stack.");
    }
    }
  return current_frame;
  return current_frame;
}
}
 
 
void
void
set_current_frame (frame)
set_current_frame (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  current_frame = frame;
  current_frame = frame;
}
}
 
 
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
   Always returns a non-NULL value.  */
   Always returns a non-NULL value.  */
 
 
struct frame_info *
struct frame_info *
create_new_frame (addr, pc)
create_new_frame (addr, pc)
     CORE_ADDR addr;
     CORE_ADDR addr;
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  struct frame_info *fi;
  struct frame_info *fi;
  char *name;
  char *name;
 
 
  fi = (struct frame_info *)
  fi = (struct frame_info *)
    obstack_alloc (&frame_cache_obstack,
    obstack_alloc (&frame_cache_obstack,
                   sizeof (struct frame_info));
                   sizeof (struct frame_info));
 
 
  /* Arbitrary frame */
  /* Arbitrary frame */
  fi->saved_regs = NULL;
  fi->saved_regs = NULL;
  fi->next = NULL;
  fi->next = NULL;
  fi->prev = NULL;
  fi->prev = NULL;
  fi->frame = addr;
  fi->frame = addr;
  fi->pc = pc;
  fi->pc = pc;
  find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
  find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
  fi->signal_handler_caller = IN_SIGTRAMP (fi->pc, name);
  fi->signal_handler_caller = IN_SIGTRAMP (fi->pc, name);
 
 
#ifdef INIT_EXTRA_FRAME_INFO
#ifdef INIT_EXTRA_FRAME_INFO
  INIT_EXTRA_FRAME_INFO (0, fi);
  INIT_EXTRA_FRAME_INFO (0, fi);
#endif
#endif
 
 
  return fi;
  return fi;
}
}
 
 
/* Return the frame that FRAME calls (NULL if FRAME is the innermost
/* Return the frame that FRAME calls (NULL if FRAME is the innermost
   frame).  */
   frame).  */
 
 
struct frame_info *
struct frame_info *
get_next_frame (frame)
get_next_frame (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  return frame->next;
  return frame->next;
}
}
 
 
/* Flush the entire frame cache.  */
/* Flush the entire frame cache.  */
 
 
void
void
flush_cached_frames ()
flush_cached_frames ()
{
{
  /* Since we can't really be sure what the first object allocated was */
  /* Since we can't really be sure what the first object allocated was */
  obstack_free (&frame_cache_obstack, 0);
  obstack_free (&frame_cache_obstack, 0);
  obstack_init (&frame_cache_obstack);
  obstack_init (&frame_cache_obstack);
 
 
  current_frame = NULL;         /* Invalidate cache */
  current_frame = NULL;         /* Invalidate cache */
  select_frame (NULL, -1);
  select_frame (NULL, -1);
  annotate_frames_invalid ();
  annotate_frames_invalid ();
}
}
 
 
/* Flush the frame cache, and start a new one if necessary.  */
/* Flush the frame cache, and start a new one if necessary.  */
 
 
void
void
reinit_frame_cache ()
reinit_frame_cache ()
{
{
  flush_cached_frames ();
  flush_cached_frames ();
 
 
  /* FIXME: The inferior_pid test is wrong if there is a corefile.  */
  /* FIXME: The inferior_pid test is wrong if there is a corefile.  */
  if (inferior_pid != 0)
  if (inferior_pid != 0)
    {
    {
      select_frame (get_current_frame (), 0);
      select_frame (get_current_frame (), 0);
    }
    }
}
}
 
 
/* Return nonzero if the function for this frame lacks a prologue.  Many
/* Return nonzero if the function for this frame lacks a prologue.  Many
   machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
   machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
   function.  */
   function.  */
 
 
int
int
frameless_look_for_prologue (frame)
frameless_look_for_prologue (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  CORE_ADDR func_start, after_prologue;
  CORE_ADDR func_start, after_prologue;
 
 
  func_start = get_pc_function_start (frame->pc);
  func_start = get_pc_function_start (frame->pc);
  if (func_start)
  if (func_start)
    {
    {
      func_start += FUNCTION_START_OFFSET;
      func_start += FUNCTION_START_OFFSET;
      after_prologue = func_start;
      after_prologue = func_start;
#ifdef SKIP_PROLOGUE_FRAMELESS_P
#ifdef SKIP_PROLOGUE_FRAMELESS_P
      /* This is faster, since only care whether there *is* a
      /* This is faster, since only care whether there *is* a
         prologue, not how long it is.  */
         prologue, not how long it is.  */
      after_prologue = SKIP_PROLOGUE_FRAMELESS_P (after_prologue);
      after_prologue = SKIP_PROLOGUE_FRAMELESS_P (after_prologue);
#else
#else
      after_prologue = SKIP_PROLOGUE (after_prologue);
      after_prologue = SKIP_PROLOGUE (after_prologue);
#endif
#endif
      return after_prologue == func_start;
      return after_prologue == func_start;
    }
    }
  else if (frame->pc == 0)
  else if (frame->pc == 0)
    /* A frame with a zero PC is usually created by dereferencing a
    /* A frame with a zero PC is usually created by dereferencing a
       NULL function pointer, normally causing an immediate core dump
       NULL function pointer, normally causing an immediate core dump
       of the inferior. Mark function as frameless, as the inferior
       of the inferior. Mark function as frameless, as the inferior
       has no chance of setting up a stack frame.  */
       has no chance of setting up a stack frame.  */
    return 1;
    return 1;
  else
  else
    /* If we can't find the start of the function, we don't really
    /* 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
       know whether the function is frameless, but we should be able
       to get a reasonable (i.e. best we can do under the
       to get a reasonable (i.e. best we can do under the
       circumstances) backtrace by saying that it isn't.  */
       circumstances) backtrace by saying that it isn't.  */
    return 0;
    return 0;
}
}
 
 
/* Default a few macros that people seldom redefine.  */
/* Default a few macros that people seldom redefine.  */
 
 
#if !defined (INIT_FRAME_PC)
#if !defined (INIT_FRAME_PC)
#define INIT_FRAME_PC(fromleaf, prev) \
#define INIT_FRAME_PC(fromleaf, prev) \
  prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
  prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
              prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
              prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
#endif
#endif
 
 
#ifndef FRAME_CHAIN_COMBINE
#ifndef FRAME_CHAIN_COMBINE
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
#endif
#endif
 
 
/* Return a structure containing various interesting information
/* Return a structure containing various interesting information
   about the frame that called NEXT_FRAME.  Returns NULL
   about the frame that called NEXT_FRAME.  Returns NULL
   if there is no such frame.  */
   if there is no such frame.  */
 
 
struct frame_info *
struct frame_info *
get_prev_frame (next_frame)
get_prev_frame (next_frame)
     struct frame_info *next_frame;
     struct frame_info *next_frame;
{
{
  CORE_ADDR address = 0;
  CORE_ADDR address = 0;
  struct frame_info *prev;
  struct frame_info *prev;
  int fromleaf = 0;
  int fromleaf = 0;
  char *name;
  char *name;
 
 
  /* If the requested entry is in the cache, return it.
  /* If the requested entry is in the cache, return it.
     Otherwise, figure out what the address should be for the entry
     Otherwise, figure out what the address should be for the entry
     we're about to add to the cache. */
     we're about to add to the cache. */
 
 
  if (!next_frame)
  if (!next_frame)
    {
    {
#if 0
#if 0
      /* This screws value_of_variable, which just wants a nice clean
      /* This screws value_of_variable, which just wants a nice clean
         NULL return from block_innermost_frame if there are no frames.
         NULL return from block_innermost_frame if there are no frames.
         I don't think I've ever seen this message happen otherwise.
         I don't think I've ever seen this message happen otherwise.
         And returning NULL here is a perfectly legitimate thing to do.  */
         And returning NULL here is a perfectly legitimate thing to do.  */
      if (!current_frame)
      if (!current_frame)
        {
        {
          error ("You haven't set up a process's stack to examine.");
          error ("You haven't set up a process's stack to examine.");
        }
        }
#endif
#endif
 
 
      return current_frame;
      return current_frame;
    }
    }
 
 
  /* If we have the prev one, return it */
  /* If we have the prev one, return it */
  if (next_frame->prev)
  if (next_frame->prev)
    return next_frame->prev;
    return next_frame->prev;
 
 
  /* On some machines it is possible to call a function without
  /* On some machines it is possible to call a function without
     setting up a stack frame for it.  On these machines, we
     setting up a stack frame for it.  On these machines, we
     define this macro to take two args; a frameinfo pointer
     define this macro to take two args; a frameinfo pointer
     identifying a frame and a variable to set or clear if it is
     identifying a frame and a variable to set or clear if it is
     or isn't leafless.  */
     or isn't leafless.  */
 
 
  /* Still don't want to worry about this except on the innermost
  /* Still don't want to worry about this except on the innermost
     frame.  This macro will set FROMLEAF if NEXT_FRAME is a
     frame.  This macro will set FROMLEAF if NEXT_FRAME is a
     frameless function invocation.  */
     frameless function invocation.  */
  if (!(next_frame->next))
  if (!(next_frame->next))
    {
    {
      fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame);
      fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame);
      if (fromleaf)
      if (fromleaf)
        address = FRAME_FP (next_frame);
        address = FRAME_FP (next_frame);
    }
    }
 
 
  if (!fromleaf)
  if (!fromleaf)
    {
    {
      /* Two macros defined in tm.h specify the machine-dependent
      /* Two macros defined in tm.h specify the machine-dependent
         actions to be performed here.
         actions to be performed here.
         First, get the frame's chain-pointer.
         First, get the frame's chain-pointer.
         If that is zero, the frame is the outermost frame or a leaf
         If that is zero, the frame is the outermost frame or a leaf
         called by the outermost frame.  This means that if start
         called by the outermost frame.  This means that if start
         calls main without a frame, we'll return 0 (which is fine
         calls main without a frame, we'll return 0 (which is fine
         anyway).
         anyway).
 
 
         Nope; there's a problem.  This also returns when the current
         Nope; there's a problem.  This also returns when the current
         routine is a leaf of main.  This is unacceptable.  We move
         routine is a leaf of main.  This is unacceptable.  We move
         this to after the ffi test; I'd rather have backtraces from
         this to after the ffi test; I'd rather have backtraces from
         start go curfluy than have an abort called from main not show
         start go curfluy than have an abort called from main not show
         main.  */
         main.  */
      address = FRAME_CHAIN (next_frame);
      address = FRAME_CHAIN (next_frame);
      if (!FRAME_CHAIN_VALID (address, next_frame))
      if (!FRAME_CHAIN_VALID (address, next_frame))
        return 0;
        return 0;
      address = FRAME_CHAIN_COMBINE (address, next_frame);
      address = FRAME_CHAIN_COMBINE (address, next_frame);
    }
    }
  if (address == 0)
  if (address == 0)
    return 0;
    return 0;
 
 
  prev = (struct frame_info *)
  prev = (struct frame_info *)
    obstack_alloc (&frame_cache_obstack,
    obstack_alloc (&frame_cache_obstack,
                   sizeof (struct frame_info));
                   sizeof (struct frame_info));
 
 
  prev->saved_regs = NULL;
  prev->saved_regs = NULL;
  if (next_frame)
  if (next_frame)
    next_frame->prev = prev;
    next_frame->prev = prev;
  prev->next = next_frame;
  prev->next = next_frame;
  prev->prev = (struct frame_info *) 0;
  prev->prev = (struct frame_info *) 0;
  prev->frame = address;
  prev->frame = address;
  prev->signal_handler_caller = 0;
  prev->signal_handler_caller = 0;
 
 
/* This change should not be needed, FIXME!  We should
/* This change should not be needed, FIXME!  We should
   determine whether any targets *need* INIT_FRAME_PC to happen
   determine whether any targets *need* INIT_FRAME_PC to happen
   after INIT_EXTRA_FRAME_INFO and come up with a simple way to
   after INIT_EXTRA_FRAME_INFO and come up with a simple way to
   express what goes on here.
   express what goes on here.
 
 
   INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame
   INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame
   (where the PC is already set up) and here (where it isn't).
   (where the PC is already set up) and here (where it isn't).
   INIT_FRAME_PC is only called from here, always after
   INIT_FRAME_PC is only called from here, always after
   INIT_EXTRA_FRAME_INFO.
   INIT_EXTRA_FRAME_INFO.
 
 
   The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the PC
   The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the PC
   value (which hasn't been set yet).  Some other machines appear to
   value (which hasn't been set yet).  Some other machines appear to
   require INIT_EXTRA_FRAME_INFO before they can do INIT_FRAME_PC.  Phoo.
   require INIT_EXTRA_FRAME_INFO before they can do INIT_FRAME_PC.  Phoo.
 
 
   We shouldn't need INIT_FRAME_PC_FIRST to add more complication to
   We shouldn't need INIT_FRAME_PC_FIRST to add more complication to
   an already overcomplicated part of GDB.   gnu@cygnus.com, 15Sep92.
   an already overcomplicated part of GDB.   gnu@cygnus.com, 15Sep92.
 
 
   Assuming that some machines need INIT_FRAME_PC after
   Assuming that some machines need INIT_FRAME_PC after
   INIT_EXTRA_FRAME_INFO, one possible scheme:
   INIT_EXTRA_FRAME_INFO, one possible scheme:
 
 
   SETUP_INNERMOST_FRAME()
   SETUP_INNERMOST_FRAME()
   Default version is just create_new_frame (read_fp ()),
   Default version is just create_new_frame (read_fp ()),
   read_pc ()).  Machines with extra frame info would do that (or the
   read_pc ()).  Machines with extra frame info would do that (or the
   local equivalent) and then set the extra fields.
   local equivalent) and then set the extra fields.
   SETUP_ARBITRARY_FRAME(argc, argv)
   SETUP_ARBITRARY_FRAME(argc, argv)
   Only change here is that create_new_frame would no longer init extra
   Only change here is that create_new_frame would no longer init extra
   frame info; SETUP_ARBITRARY_FRAME would have to do that.
   frame info; SETUP_ARBITRARY_FRAME would have to do that.
   INIT_PREV_FRAME(fromleaf, prev)
   INIT_PREV_FRAME(fromleaf, prev)
   Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC.  This should
   Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC.  This should
   also return a flag saying whether to keep the new frame, or
   also return a flag saying whether to keep the new frame, or
   whether to discard it, because on some machines (e.g.  mips) it
   whether to discard it, because on some machines (e.g.  mips) it
   is really awkward to have FRAME_CHAIN_VALID called *before*
   is really awkward to have FRAME_CHAIN_VALID called *before*
   INIT_EXTRA_FRAME_INFO (there is no good way to get information
   INIT_EXTRA_FRAME_INFO (there is no good way to get information
   deduced in FRAME_CHAIN_VALID into the extra fields of the new frame).
   deduced in FRAME_CHAIN_VALID into the extra fields of the new frame).
   std_frame_pc(fromleaf, prev)
   std_frame_pc(fromleaf, prev)
   This is the default setting for INIT_PREV_FRAME.  It just does what
   This is the default setting for INIT_PREV_FRAME.  It just does what
   the default INIT_FRAME_PC does.  Some machines will call it from
   the default INIT_FRAME_PC does.  Some machines will call it from
   INIT_PREV_FRAME (either at the beginning, the end, or in the middle).
   INIT_PREV_FRAME (either at the beginning, the end, or in the middle).
   Some machines won't use it.
   Some machines won't use it.
   kingdon@cygnus.com, 13Apr93, 31Jan94, 14Dec94.  */
   kingdon@cygnus.com, 13Apr93, 31Jan94, 14Dec94.  */
 
 
#ifdef INIT_FRAME_PC_FIRST
#ifdef INIT_FRAME_PC_FIRST
  INIT_FRAME_PC_FIRST (fromleaf, prev);
  INIT_FRAME_PC_FIRST (fromleaf, prev);
#endif
#endif
 
 
#ifdef INIT_EXTRA_FRAME_INFO
#ifdef INIT_EXTRA_FRAME_INFO
  INIT_EXTRA_FRAME_INFO (fromleaf, prev);
  INIT_EXTRA_FRAME_INFO (fromleaf, prev);
#endif
#endif
 
 
  /* This entry is in the frame queue now, which is good since
  /* This entry is in the frame queue now, which is good since
     FRAME_SAVED_PC may use that queue to figure out its value
     FRAME_SAVED_PC may use that queue to figure out its value
     (see tm-sparc.h).  We want the pc saved in the inferior frame. */
     (see tm-sparc.h).  We want the pc saved in the inferior frame. */
  INIT_FRAME_PC (fromleaf, prev);
  INIT_FRAME_PC (fromleaf, prev);
 
 
  /* If ->frame and ->pc are unchanged, we are in the process of getting
  /* If ->frame and ->pc are unchanged, we are in the process of getting
     ourselves into an infinite backtrace.  Some architectures check this
     ourselves into an infinite backtrace.  Some architectures check this
     in FRAME_CHAIN or thereabouts, but it seems like there is no reason
     in FRAME_CHAIN or thereabouts, but it seems like there is no reason
     this can't be an architecture-independent check.  */
     this can't be an architecture-independent check.  */
  if (next_frame != NULL)
  if (next_frame != NULL)
    {
    {
      if (prev->frame == next_frame->frame
      if (prev->frame == next_frame->frame
          && prev->pc == next_frame->pc)
          && prev->pc == next_frame->pc)
        {
        {
          next_frame->prev = NULL;
          next_frame->prev = NULL;
          obstack_free (&frame_cache_obstack, prev);
          obstack_free (&frame_cache_obstack, prev);
          return NULL;
          return NULL;
        }
        }
    }
    }
 
 
  find_pc_partial_function (prev->pc, &name,
  find_pc_partial_function (prev->pc, &name,
                            (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
                            (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
  if (IN_SIGTRAMP (prev->pc, name))
  if (IN_SIGTRAMP (prev->pc, name))
    prev->signal_handler_caller = 1;
    prev->signal_handler_caller = 1;
 
 
  return prev;
  return prev;
}
}
 
 
CORE_ADDR
CORE_ADDR
get_frame_pc (frame)
get_frame_pc (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  return frame->pc;
  return frame->pc;
}
}
 
 
 
 
#ifdef FRAME_FIND_SAVED_REGS
#ifdef FRAME_FIND_SAVED_REGS
/* XXX - deprecated.  This is a compatibility function for targets
/* XXX - deprecated.  This is a compatibility function for targets
   that do not yet implement FRAME_INIT_SAVED_REGS.  */
   that do not yet implement FRAME_INIT_SAVED_REGS.  */
/* Find the addresses in which registers are saved in FRAME.  */
/* Find the addresses in which registers are saved in FRAME.  */
 
 
void
void
get_frame_saved_regs (frame, saved_regs_addr)
get_frame_saved_regs (frame, saved_regs_addr)
     struct frame_info *frame;
     struct frame_info *frame;
     struct frame_saved_regs *saved_regs_addr;
     struct frame_saved_regs *saved_regs_addr;
{
{
  if (frame->saved_regs == NULL)
  if (frame->saved_regs == NULL)
    {
    {
      frame->saved_regs = (CORE_ADDR *)
      frame->saved_regs = (CORE_ADDR *)
        frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
        frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
    }
    }
  if (saved_regs_addr == NULL)
  if (saved_regs_addr == NULL)
    {
    {
      struct frame_saved_regs saved_regs;
      struct frame_saved_regs saved_regs;
      FRAME_FIND_SAVED_REGS (frame, saved_regs);
      FRAME_FIND_SAVED_REGS (frame, saved_regs);
      memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS);
      memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS);
    }
    }
  else
  else
    {
    {
      FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr);
      FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr);
      memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS);
      memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS);
    }
    }
}
}
#endif
#endif
 
 
/* Return the innermost lexical block in execution
/* Return the innermost lexical block in execution
   in a specified stack frame.  The frame address is assumed valid.  */
   in a specified stack frame.  The frame address is assumed valid.  */
 
 
struct block *
struct block *
get_frame_block (frame)
get_frame_block (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  CORE_ADDR pc;
  CORE_ADDR pc;
 
 
  pc = frame->pc;
  pc = frame->pc;
  if (frame->next != 0 && frame->next->signal_handler_caller == 0)
  if (frame->next != 0 && frame->next->signal_handler_caller == 0)
    /* We are not in the innermost frame and we were not interrupted
    /* We are not in the innermost frame and we were not interrupted
       by a signal.  We need to subtract one to get the correct block,
       by a signal.  We need to subtract one to get the correct block,
       in case the call instruction was the last instruction of the block.
       in case the call instruction was the last instruction of the block.
       If there are any machines on which the saved pc does not point to
       If there are any machines on which the saved pc does not point to
       after the call insn, we probably want to make frame->pc point after
       after the call insn, we probably want to make frame->pc point after
       the call insn anyway.  */
       the call insn anyway.  */
    --pc;
    --pc;
  return block_for_pc (pc);
  return block_for_pc (pc);
}
}
 
 
struct block *
struct block *
get_current_block ()
get_current_block ()
{
{
  return block_for_pc (read_pc ());
  return block_for_pc (read_pc ());
}
}
 
 
CORE_ADDR
CORE_ADDR
get_pc_function_start (pc)
get_pc_function_start (pc)
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  register struct block *bl;
  register struct block *bl;
  register struct symbol *symbol;
  register struct symbol *symbol;
  register struct minimal_symbol *msymbol;
  register struct minimal_symbol *msymbol;
  CORE_ADDR fstart;
  CORE_ADDR fstart;
 
 
  if ((bl = block_for_pc (pc)) != NULL &&
  if ((bl = block_for_pc (pc)) != NULL &&
      (symbol = block_function (bl)) != NULL)
      (symbol = block_function (bl)) != NULL)
    {
    {
      bl = SYMBOL_BLOCK_VALUE (symbol);
      bl = SYMBOL_BLOCK_VALUE (symbol);
      fstart = BLOCK_START (bl);
      fstart = BLOCK_START (bl);
    }
    }
  else if ((msymbol = lookup_minimal_symbol_by_pc (pc)) != NULL)
  else if ((msymbol = lookup_minimal_symbol_by_pc (pc)) != NULL)
    {
    {
      fstart = SYMBOL_VALUE_ADDRESS (msymbol);
      fstart = SYMBOL_VALUE_ADDRESS (msymbol);
    }
    }
  else
  else
    {
    {
      fstart = 0;
      fstart = 0;
    }
    }
  return (fstart);
  return (fstart);
}
}
 
 
/* Return the symbol for the function executing in frame FRAME.  */
/* Return the symbol for the function executing in frame FRAME.  */
 
 
struct symbol *
struct symbol *
get_frame_function (frame)
get_frame_function (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  register struct block *bl = get_frame_block (frame);
  register struct block *bl = get_frame_block (frame);
  if (bl == 0)
  if (bl == 0)
    return 0;
    return 0;
  return block_function (bl);
  return block_function (bl);
}
}


 
 
/* Return the blockvector immediately containing the innermost lexical block
/* Return the blockvector immediately containing the innermost lexical block
   containing the specified pc value and section, 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
   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.  */
   is NULL, we don't pass this information back to the caller.  */
 
 
struct blockvector *
struct blockvector *
blockvector_for_pc_sect (pc, section, pindex, symtab)
blockvector_for_pc_sect (pc, section, pindex, symtab)
     register CORE_ADDR pc;
     register CORE_ADDR pc;
     struct sec *section;
     struct sec *section;
     int *pindex;
     int *pindex;
     struct symtab *symtab;
     struct symtab *symtab;
 
 
{
{
  register struct block *b;
  register struct block *b;
  register int bot, top, half;
  register int bot, top, half;
  struct blockvector *bl;
  struct blockvector *bl;
 
 
  if (symtab == 0)               /* if no symtab specified by caller */
  if (symtab == 0)               /* if no symtab specified by caller */
    {
    {
      /* First search all symtabs for one whose file contains our pc */
      /* First search all symtabs for one whose file contains our pc */
      if ((symtab = find_pc_sect_symtab (pc, section)) == 0)
      if ((symtab = find_pc_sect_symtab (pc, section)) == 0)
        return 0;
        return 0;
    }
    }
 
 
  bl = BLOCKVECTOR (symtab);
  bl = BLOCKVECTOR (symtab);
  b = BLOCKVECTOR_BLOCK (bl, 0);
  b = BLOCKVECTOR_BLOCK (bl, 0);
 
 
  /* Then search that symtab for the smallest block that wins.  */
  /* Then search that symtab for the smallest block that wins.  */
  /* Use binary search to find the last block that starts before PC.  */
  /* Use binary search to find the last block that starts before PC.  */
 
 
  bot = 0;
  bot = 0;
  top = BLOCKVECTOR_NBLOCKS (bl);
  top = BLOCKVECTOR_NBLOCKS (bl);
 
 
  while (top - bot > 1)
  while (top - bot > 1)
    {
    {
      half = (top - bot + 1) >> 1;
      half = (top - bot + 1) >> 1;
      b = BLOCKVECTOR_BLOCK (bl, bot + half);
      b = BLOCKVECTOR_BLOCK (bl, bot + half);
      if (BLOCK_START (b) <= pc)
      if (BLOCK_START (b) <= pc)
        bot += half;
        bot += half;
      else
      else
        top = bot + half;
        top = bot + half;
    }
    }
 
 
  /* Now search backward for a block that ends after PC.  */
  /* Now search backward for a block that ends after PC.  */
 
 
  while (bot >= 0)
  while (bot >= 0)
    {
    {
      b = BLOCKVECTOR_BLOCK (bl, bot);
      b = BLOCKVECTOR_BLOCK (bl, bot);
      if (BLOCK_END (b) > pc)
      if (BLOCK_END (b) > pc)
        {
        {
          if (pindex)
          if (pindex)
            *pindex = bot;
            *pindex = bot;
          return bl;
          return bl;
        }
        }
      bot--;
      bot--;
    }
    }
  return 0;
  return 0;
}
}
 
 
/* Return the blockvector immediately containing the innermost lexical block
/* 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, or 0 if there is none.
   Backward compatibility, no section.  */
   Backward compatibility, no section.  */
 
 
struct blockvector *
struct blockvector *
blockvector_for_pc (pc, pindex)
blockvector_for_pc (pc, pindex)
     register CORE_ADDR pc;
     register CORE_ADDR pc;
     int *pindex;
     int *pindex;
{
{
  return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
  return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
                                  pindex, NULL);
                                  pindex, NULL);
}
}
 
 
/* Return the innermost lexical block containing the specified pc value
/* Return the innermost lexical block containing the specified pc value
   in the specified section, or 0 if there is none.  */
   in the specified section, or 0 if there is none.  */
 
 
struct block *
struct block *
block_for_pc_sect (pc, section)
block_for_pc_sect (pc, section)
     register CORE_ADDR pc;
     register CORE_ADDR pc;
     struct sec *section;
     struct sec *section;
{
{
  register struct blockvector *bl;
  register struct blockvector *bl;
  int index;
  int index;
 
 
  bl = blockvector_for_pc_sect (pc, section, &index, NULL);
  bl = blockvector_for_pc_sect (pc, section, &index, NULL);
  if (bl)
  if (bl)
    return BLOCKVECTOR_BLOCK (bl, index);
    return BLOCKVECTOR_BLOCK (bl, index);
  return 0;
  return 0;
}
}
 
 
/* Return the innermost lexical block containing the specified pc value,
/* Return the innermost lexical block containing the specified pc value,
   or 0 if there is none.  Backward compatibility, no section.  */
   or 0 if there is none.  Backward compatibility, no section.  */
 
 
struct block *
struct block *
block_for_pc (pc)
block_for_pc (pc)
     register CORE_ADDR pc;
     register CORE_ADDR pc;
{
{
  return block_for_pc_sect (pc, find_pc_mapped_section (pc));
  return block_for_pc_sect (pc, find_pc_mapped_section (pc));
}
}
 
 
/* Return the function containing pc value PC in section SECTION.
/* Return the function containing pc value PC in section SECTION.
   Returns 0 if function is not known.  */
   Returns 0 if function is not known.  */
 
 
struct symbol *
struct symbol *
find_pc_sect_function (pc, section)
find_pc_sect_function (pc, section)
     CORE_ADDR pc;
     CORE_ADDR pc;
     struct sec *section;
     struct sec *section;
{
{
  register struct block *b = block_for_pc_sect (pc, section);
  register struct block *b = block_for_pc_sect (pc, section);
  if (b == 0)
  if (b == 0)
    return 0;
    return 0;
  return block_function (b);
  return block_function (b);
}
}
 
 
/* Return the function containing pc value PC.
/* Return the function containing pc value PC.
   Returns 0 if function is not known.  Backward compatibility, no section */
   Returns 0 if function is not known.  Backward compatibility, no section */
 
 
struct symbol *
struct symbol *
find_pc_function (pc)
find_pc_function (pc)
     CORE_ADDR pc;
     CORE_ADDR pc;
{
{
  return find_pc_sect_function (pc, find_pc_mapped_section (pc));
  return find_pc_sect_function (pc, find_pc_mapped_section (pc));
}
}
 
 
/* These variables are used to cache the most recent result
/* These variables are used to cache the most recent result
 * of find_pc_partial_function. */
 * of find_pc_partial_function. */
 
 
static CORE_ADDR cache_pc_function_low = 0;
static CORE_ADDR cache_pc_function_low = 0;
static CORE_ADDR cache_pc_function_high = 0;
static CORE_ADDR cache_pc_function_high = 0;
static char *cache_pc_function_name = 0;
static char *cache_pc_function_name = 0;
static struct sec *cache_pc_function_section = NULL;
static struct sec *cache_pc_function_section = NULL;
 
 
/* Clear cache, e.g. when symbol table is discarded. */
/* Clear cache, e.g. when symbol table is discarded. */
 
 
void
void
clear_pc_function_cache ()
clear_pc_function_cache ()
{
{
  cache_pc_function_low = 0;
  cache_pc_function_low = 0;
  cache_pc_function_high = 0;
  cache_pc_function_high = 0;
  cache_pc_function_name = (char *) 0;
  cache_pc_function_name = (char *) 0;
  cache_pc_function_section = NULL;
  cache_pc_function_section = NULL;
}
}
 
 
/* Finds the "function" (text symbol) that is smaller than PC but
/* Finds the "function" (text symbol) that is smaller than PC but
   greatest of all of the potential text symbols in SECTION.  Sets
   greatest of all of the potential text symbols in SECTION.  Sets
   *NAME and/or *ADDRESS conditionally if that pointer is non-null.
   *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
   If ENDADDR is non-null, then set *ENDADDR to be the end of the
   function (exclusive), but passing ENDADDR as non-null means that
   function (exclusive), but passing ENDADDR as non-null means that
   the function might cause symbols to be read.  This function either
   the function might cause symbols to be read.  This function either
   succeeds or fails (not halfway succeeds).  If it succeeds, it sets
   succeeds or fails (not halfway succeeds).  If it succeeds, it sets
   *NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
   *NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
   If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero and
   If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero and
   returns 0.  */
   returns 0.  */
 
 
int
int
find_pc_sect_partial_function (pc, section, name, address, endaddr)
find_pc_sect_partial_function (pc, section, name, address, endaddr)
     CORE_ADDR pc;
     CORE_ADDR pc;
     asection *section;
     asection *section;
     char **name;
     char **name;
     CORE_ADDR *address;
     CORE_ADDR *address;
     CORE_ADDR *endaddr;
     CORE_ADDR *endaddr;
{
{
  struct partial_symtab *pst;
  struct partial_symtab *pst;
  struct symbol *f;
  struct symbol *f;
  struct minimal_symbol *msymbol;
  struct minimal_symbol *msymbol;
  struct partial_symbol *psb;
  struct partial_symbol *psb;
  struct obj_section *osect;
  struct obj_section *osect;
  int i;
  int i;
  CORE_ADDR mapped_pc;
  CORE_ADDR mapped_pc;
 
 
  mapped_pc = overlay_mapped_address (pc, section);
  mapped_pc = overlay_mapped_address (pc, section);
 
 
  if (mapped_pc >= cache_pc_function_low &&
  if (mapped_pc >= cache_pc_function_low &&
      mapped_pc < cache_pc_function_high &&
      mapped_pc < cache_pc_function_high &&
      section == cache_pc_function_section)
      section == cache_pc_function_section)
    goto return_cached_value;
    goto return_cached_value;
 
 
  /* If sigtramp is in the u area, it counts as a function (especially
  /* If sigtramp is in the u area, it counts as a function (especially
     important for step_1).  */
     important for step_1).  */
#if defined SIGTRAMP_START
#if defined SIGTRAMP_START
  if (IN_SIGTRAMP (mapped_pc, (char *) NULL))
  if (IN_SIGTRAMP (mapped_pc, (char *) NULL))
    {
    {
      cache_pc_function_low = SIGTRAMP_START (mapped_pc);
      cache_pc_function_low = SIGTRAMP_START (mapped_pc);
      cache_pc_function_high = SIGTRAMP_END (mapped_pc);
      cache_pc_function_high = SIGTRAMP_END (mapped_pc);
      cache_pc_function_name = "<sigtramp>";
      cache_pc_function_name = "<sigtramp>";
      cache_pc_function_section = section;
      cache_pc_function_section = section;
      goto return_cached_value;
      goto return_cached_value;
    }
    }
#endif
#endif
 
 
  msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
  msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
  pst = find_pc_sect_psymtab (mapped_pc, section);
  pst = find_pc_sect_psymtab (mapped_pc, section);
  if (pst)
  if (pst)
    {
    {
      /* Need to read the symbols to get a good value for the end address.  */
      /* Need to read the symbols to get a good value for the end address.  */
      if (endaddr != NULL && !pst->readin)
      if (endaddr != NULL && !pst->readin)
        {
        {
          /* Need to get the terminal in case symbol-reading produces
          /* Need to get the terminal in case symbol-reading produces
             output.  */
             output.  */
          target_terminal_ours_for_output ();
          target_terminal_ours_for_output ();
          PSYMTAB_TO_SYMTAB (pst);
          PSYMTAB_TO_SYMTAB (pst);
        }
        }
 
 
      if (pst->readin)
      if (pst->readin)
        {
        {
          /* Checking whether the msymbol has a larger value is for the
          /* Checking whether the msymbol has a larger value is for the
             "pathological" case mentioned in print_frame_info.  */
             "pathological" case mentioned in print_frame_info.  */
          f = find_pc_sect_function (mapped_pc, section);
          f = find_pc_sect_function (mapped_pc, section);
          if (f != NULL
          if (f != NULL
              && (msymbol == NULL
              && (msymbol == NULL
                  || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
                  || (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
                      >= SYMBOL_VALUE_ADDRESS (msymbol))))
                      >= SYMBOL_VALUE_ADDRESS (msymbol))))
            {
            {
              cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
              cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
              cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
              cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
              cache_pc_function_name = SYMBOL_NAME (f);
              cache_pc_function_name = SYMBOL_NAME (f);
              cache_pc_function_section = section;
              cache_pc_function_section = section;
              goto return_cached_value;
              goto return_cached_value;
            }
            }
        }
        }
      else
      else
        {
        {
          /* Now that static symbols go in the minimal symbol table, perhaps
          /* Now that static symbols go in the minimal symbol table, perhaps
             we could just ignore the partial symbols.  But at least for now
             we could just ignore the partial symbols.  But at least for now
             we use the partial or minimal symbol, whichever is larger.  */
             we use the partial or minimal symbol, whichever is larger.  */
          psb = find_pc_sect_psymbol (pst, mapped_pc, section);
          psb = find_pc_sect_psymbol (pst, mapped_pc, section);
 
 
          if (psb
          if (psb
              && (msymbol == NULL ||
              && (msymbol == NULL ||
                  (SYMBOL_VALUE_ADDRESS (psb)
                  (SYMBOL_VALUE_ADDRESS (psb)
                   >= SYMBOL_VALUE_ADDRESS (msymbol))))
                   >= SYMBOL_VALUE_ADDRESS (msymbol))))
            {
            {
              /* This case isn't being cached currently. */
              /* This case isn't being cached currently. */
              if (address)
              if (address)
                *address = SYMBOL_VALUE_ADDRESS (psb);
                *address = SYMBOL_VALUE_ADDRESS (psb);
              if (name)
              if (name)
                *name = SYMBOL_NAME (psb);
                *name = SYMBOL_NAME (psb);
              /* endaddr non-NULL can't happen here.  */
              /* endaddr non-NULL can't happen here.  */
              return 1;
              return 1;
            }
            }
        }
        }
    }
    }
 
 
  /* Not in the normal symbol tables, see if the pc is in a known section.
  /* Not in the normal symbol tables, see if the pc is in a known section.
     If it's not, then give up.  This ensures that anything beyond the end
     If it's not, then give up.  This ensures that anything beyond the end
     of the text seg doesn't appear to be part of the last function in the
     of the text seg doesn't appear to be part of the last function in the
     text segment.  */
     text segment.  */
 
 
  osect = find_pc_sect_section (mapped_pc, section);
  osect = find_pc_sect_section (mapped_pc, section);
 
 
  if (!osect)
  if (!osect)
    msymbol = NULL;
    msymbol = NULL;
 
 
  /* Must be in the minimal symbol table.  */
  /* Must be in the minimal symbol table.  */
  if (msymbol == NULL)
  if (msymbol == NULL)
    {
    {
      /* No available symbol.  */
      /* No available symbol.  */
      if (name != NULL)
      if (name != NULL)
        *name = 0;
        *name = 0;
      if (address != NULL)
      if (address != NULL)
        *address = 0;
        *address = 0;
      if (endaddr != NULL)
      if (endaddr != NULL)
        *endaddr = 0;
        *endaddr = 0;
      return 0;
      return 0;
    }
    }
 
 
  cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
  cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
  cache_pc_function_name = SYMBOL_NAME (msymbol);
  cache_pc_function_name = SYMBOL_NAME (msymbol);
  cache_pc_function_section = section;
  cache_pc_function_section = section;
 
 
  /* Use the lesser of the next minimal symbol in the same section, or
  /* Use the lesser of the next minimal symbol in the same section, or
     the end of the section, as the end of the function.  */
     the end of the section, as the end of the function.  */
 
 
  /* Step over other symbols at this same address, and symbols in
  /* Step over other symbols at this same address, and symbols in
     other sections, to find the next symbol in this section with
     other sections, to find the next symbol in this section with
     a different address.  */
     a different address.  */
 
 
  for (i = 1; SYMBOL_NAME (msymbol + i) != NULL; i++)
  for (i = 1; SYMBOL_NAME (msymbol + i) != NULL; i++)
    {
    {
      if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol)
      if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol)
        && SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol))
        && SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol))
        break;
        break;
    }
    }
 
 
  if (SYMBOL_NAME (msymbol + i) != NULL
  if (SYMBOL_NAME (msymbol + i) != NULL
      && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr)
      && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr)
    cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
    cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
  else
  else
    /* We got the start address from the last msymbol in the objfile.
    /* We got the start address from the last msymbol in the objfile.
       So the end address is the end of the section.  */
       So the end address is the end of the section.  */
    cache_pc_function_high = osect->endaddr;
    cache_pc_function_high = osect->endaddr;
 
 
return_cached_value:
return_cached_value:
 
 
  if (address)
  if (address)
    {
    {
      if (pc_in_unmapped_range (pc, section))
      if (pc_in_unmapped_range (pc, section))
        *address = overlay_unmapped_address (cache_pc_function_low, section);
        *address = overlay_unmapped_address (cache_pc_function_low, section);
      else
      else
        *address = cache_pc_function_low;
        *address = cache_pc_function_low;
    }
    }
 
 
  if (name)
  if (name)
    *name = cache_pc_function_name;
    *name = cache_pc_function_name;
 
 
  if (endaddr)
  if (endaddr)
    {
    {
      if (pc_in_unmapped_range (pc, section))
      if (pc_in_unmapped_range (pc, section))
        {
        {
          /* Because the high address is actually beyond the end of
          /* Because the high address is actually beyond the end of
             the function (and therefore possibly beyond the end of
             the function (and therefore possibly beyond the end of
             the overlay), we must actually convert (high - 1)
             the overlay), we must actually convert (high - 1)
             and then add one to that. */
             and then add one to that. */
 
 
          *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
          *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
                                                   section);
                                                   section);
        }
        }
      else
      else
        *endaddr = cache_pc_function_high;
        *endaddr = cache_pc_function_high;
    }
    }
 
 
  return 1;
  return 1;
}
}
 
 
/* Backward compatibility, no section argument */
/* Backward compatibility, no section argument */
 
 
int
int
find_pc_partial_function (pc, name, address, endaddr)
find_pc_partial_function (pc, name, address, endaddr)
     CORE_ADDR pc;
     CORE_ADDR pc;
     char **name;
     char **name;
     CORE_ADDR *address;
     CORE_ADDR *address;
     CORE_ADDR *endaddr;
     CORE_ADDR *endaddr;
{
{
  asection *section;
  asection *section;
 
 
  section = find_pc_overlay (pc);
  section = find_pc_overlay (pc);
  return find_pc_sect_partial_function (pc, section, name, address, endaddr);
  return find_pc_sect_partial_function (pc, section, name, address, endaddr);
}
}
 
 
/* Return the innermost stack frame executing inside of BLOCK,
/* Return the innermost stack frame executing inside of BLOCK,
   or NULL if there is no such frame.  If BLOCK is NULL, just return NULL.  */
   or NULL if there is no such frame.  If BLOCK is NULL, just return NULL.  */
 
 
struct frame_info *
struct frame_info *
block_innermost_frame (block)
block_innermost_frame (block)
     struct block *block;
     struct block *block;
{
{
  struct frame_info *frame;
  struct frame_info *frame;
  register CORE_ADDR start;
  register CORE_ADDR start;
  register CORE_ADDR end;
  register CORE_ADDR end;
 
 
  if (block == NULL)
  if (block == NULL)
    return NULL;
    return NULL;
 
 
  start = BLOCK_START (block);
  start = BLOCK_START (block);
  end = BLOCK_END (block);
  end = BLOCK_END (block);
 
 
  frame = NULL;
  frame = NULL;
  while (1)
  while (1)
    {
    {
      frame = get_prev_frame (frame);
      frame = get_prev_frame (frame);
      if (frame == NULL)
      if (frame == NULL)
        return NULL;
        return NULL;
      if (frame->pc >= start && frame->pc < end)
      if (frame->pc >= start && frame->pc < end)
        return frame;
        return frame;
    }
    }
}
}
 
 
/* Return the full FRAME which corresponds to the given CORE_ADDR
/* Return the full FRAME which corresponds to the given CORE_ADDR
   or NULL if no FRAME on the chain corresponds to CORE_ADDR.  */
   or NULL if no FRAME on the chain corresponds to CORE_ADDR.  */
 
 
struct frame_info *
struct frame_info *
find_frame_addr_in_frame_chain (frame_addr)
find_frame_addr_in_frame_chain (frame_addr)
     CORE_ADDR frame_addr;
     CORE_ADDR frame_addr;
{
{
  struct frame_info *frame = NULL;
  struct frame_info *frame = NULL;
 
 
  if (frame_addr == (CORE_ADDR) 0)
  if (frame_addr == (CORE_ADDR) 0)
    return NULL;
    return NULL;
 
 
  while (1)
  while (1)
    {
    {
      frame = get_prev_frame (frame);
      frame = get_prev_frame (frame);
      if (frame == NULL)
      if (frame == NULL)
        return NULL;
        return NULL;
      if (FRAME_FP (frame) == frame_addr)
      if (FRAME_FP (frame) == frame_addr)
        return frame;
        return frame;
    }
    }
}
}
 
 
#ifdef SIGCONTEXT_PC_OFFSET
#ifdef SIGCONTEXT_PC_OFFSET
/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp.  */
/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp.  */
 
 
CORE_ADDR
CORE_ADDR
sigtramp_saved_pc (frame)
sigtramp_saved_pc (frame)
     struct frame_info *frame;
     struct frame_info *frame;
{
{
  CORE_ADDR sigcontext_addr;
  CORE_ADDR sigcontext_addr;
  char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
  char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
  int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
  int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
  int sigcontext_offs = (2 * TARGET_INT_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.  */
  /* Get sigcontext address, it is the third parameter on the stack.  */
  if (frame->next)
  if (frame->next)
    sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next)
    sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next)
                                           + FRAME_ARGS_SKIP
                                           + FRAME_ARGS_SKIP
                                           + sigcontext_offs,
                                           + sigcontext_offs,
                                           ptrbytes);
                                           ptrbytes);
  else
  else
    sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
    sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
                                           + sigcontext_offs,
                                           + sigcontext_offs,
                                           ptrbytes);
                                           ptrbytes);
 
 
  /* Don't cause a memory_error when accessing sigcontext in case the stack
  /* Don't cause a memory_error when accessing sigcontext in case the stack
     layout has changed or the stack is corrupt.  */
     layout has changed or the stack is corrupt.  */
  target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
  target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
  return extract_unsigned_integer (buf, ptrbytes);
  return extract_unsigned_integer (buf, ptrbytes);
}
}
#endif /* SIGCONTEXT_PC_OFFSET */
#endif /* SIGCONTEXT_PC_OFFSET */
 
 
 
 
/* Are we in a call dummy?  The code below which allows DECR_PC_AFTER_BREAK
/* Are we in a call dummy?  The code below which allows DECR_PC_AFTER_BREAK
   below is for infrun.c, which may give the macro a pc without that
   below is for infrun.c, which may give the macro a pc without that
   subtracted out.  */
   subtracted out.  */
 
 
extern CORE_ADDR text_end;
extern CORE_ADDR text_end;
 
 
int
int
pc_in_call_dummy_before_text_end (pc, sp, frame_address)
pc_in_call_dummy_before_text_end (pc, sp, frame_address)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR sp;
     CORE_ADDR sp;
     CORE_ADDR frame_address;
     CORE_ADDR frame_address;
{
{
  return ((pc) >= text_end - CALL_DUMMY_LENGTH
  return ((pc) >= text_end - CALL_DUMMY_LENGTH
          && (pc) <= text_end + DECR_PC_AFTER_BREAK);
          && (pc) <= text_end + DECR_PC_AFTER_BREAK);
}
}
 
 
int
int
pc_in_call_dummy_after_text_end (pc, sp, frame_address)
pc_in_call_dummy_after_text_end (pc, sp, frame_address)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR sp;
     CORE_ADDR sp;
     CORE_ADDR frame_address;
     CORE_ADDR frame_address;
{
{
  return ((pc) >= text_end
  return ((pc) >= text_end
          && (pc) <= text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK);
          && (pc) <= text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK);
}
}
 
 
/* Is the PC in a call dummy?  SP and FRAME_ADDRESS are the bottom and
/* Is the PC in a call dummy?  SP and FRAME_ADDRESS are the bottom and
   top of the stack frame which we are checking, where "bottom" and
   top of the stack frame which we are checking, where "bottom" and
   "top" refer to some section of memory which contains the code for
   "top" refer to some section of memory which contains the code for
   the call dummy.  Calls to this macro assume that the contents of
   the call dummy.  Calls to this macro assume that the contents of
   SP_REGNUM and FP_REGNUM (or the saved values thereof), respectively,
   SP_REGNUM and FP_REGNUM (or the saved values thereof), respectively,
   are the things to pass.
   are the things to pass.
 
 
   This won't work on the 29k, where SP_REGNUM and FP_REGNUM don't
   This won't work on the 29k, where SP_REGNUM and FP_REGNUM don't
   have that meaning, but the 29k doesn't use ON_STACK.  This could be
   have that meaning, but the 29k doesn't use ON_STACK.  This could be
   fixed by generalizing this scheme, perhaps by passing in a frame
   fixed by generalizing this scheme, perhaps by passing in a frame
   and adding a few fields, at least on machines which need them for
   and adding a few fields, at least on machines which need them for
   PC_IN_CALL_DUMMY.
   PC_IN_CALL_DUMMY.
 
 
   Something simpler, like checking for the stack segment, doesn't work,
   Something simpler, like checking for the stack segment, doesn't work,
   since various programs (threads implementations, gcc nested function
   since various programs (threads implementations, gcc nested function
   stubs, etc) may either allocate stack frames in another segment, or
   stubs, etc) may either allocate stack frames in another segment, or
   allocate other kinds of code on the stack.  */
   allocate other kinds of code on the stack.  */
 
 
int
int
pc_in_call_dummy_on_stack (pc, sp, frame_address)
pc_in_call_dummy_on_stack (pc, sp, frame_address)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR sp;
     CORE_ADDR sp;
     CORE_ADDR frame_address;
     CORE_ADDR frame_address;
{
{
  return (INNER_THAN ((sp), (pc))
  return (INNER_THAN ((sp), (pc))
          && (frame_address != 0)
          && (frame_address != 0)
          && INNER_THAN ((pc), (frame_address)));
          && INNER_THAN ((pc), (frame_address)));
}
}
 
 
int
int
pc_in_call_dummy_at_entry_point (pc, sp, frame_address)
pc_in_call_dummy_at_entry_point (pc, sp, frame_address)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR sp;
     CORE_ADDR sp;
     CORE_ADDR frame_address;
     CORE_ADDR frame_address;
{
{
  return ((pc) >= CALL_DUMMY_ADDRESS ()
  return ((pc) >= CALL_DUMMY_ADDRESS ()
          && (pc) <= (CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK));
          && (pc) <= (CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK));
}
}
 
 
 
 
/*
/*
 * GENERIC DUMMY FRAMES
 * GENERIC DUMMY FRAMES
 *
 *
 * The following code serves to maintain the dummy stack frames for
 * The following code serves to maintain the dummy stack frames for
 * inferior function calls (ie. when gdb calls into the inferior via
 * inferior function calls (ie. when gdb calls into the inferior via
 * call_function_by_hand).  This code saves the machine state before
 * call_function_by_hand).  This code saves the machine state before
 * the call in host memory, so we 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
 * and keep it consistant etc.  I am attempting to make this code
 * generic enough to be used by many targets.
 * generic enough to be used by many targets.
 *
 *
 * The cheapest and most generic way to do CALL_DUMMY on a new target
 * 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
 * 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
 * zero, and CALL_DUMMY_LOCATION to AT_ENTRY.  Then you must remember
 * to define PUSH_RETURN_ADDRESS, because no call instruction will be
 * to define PUSH_RETURN_ADDRESS, because no call instruction will be
 * being executed by the target.  Also FRAME_CHAIN_VALID as
 * being executed by the target.  Also FRAME_CHAIN_VALID as
 * generic_{file,func}_frame_chain_valid and FIX_CALL_DUMMY as
 * generic_{file,func}_frame_chain_valid and FIX_CALL_DUMMY as
 * generic_fix_call_dummy.  */
 * generic_fix_call_dummy.  */
 
 
/* Dummy frame.  This saves the processor state just prior to setting
/* Dummy frame.  This saves the processor state just prior to setting
   up the inferior function call.  Older targets save the registers
   up the inferior function call.  Older targets save the registers
   target stack (but that really slows down function calls).  */
   target stack (but that really slows down function calls).  */
 
 
struct dummy_frame
struct dummy_frame
{
{
  struct dummy_frame *next;
  struct dummy_frame *next;
 
 
  CORE_ADDR pc;
  CORE_ADDR pc;
  CORE_ADDR fp;
  CORE_ADDR fp;
  CORE_ADDR sp;
  CORE_ADDR sp;
  CORE_ADDR top;
  CORE_ADDR top;
  char *registers;
  char *registers;
};
};
 
 
static struct dummy_frame *dummy_frame_stack = NULL;
static struct dummy_frame *dummy_frame_stack = NULL;
 
 
/* Function: find_dummy_frame(pc, fp, sp)
/* Function: find_dummy_frame(pc, fp, sp)
   Search the stack of dummy frames for one matching the given PC, FP and SP.
   Search the stack of dummy frames for one matching the given PC, FP and SP.
   This is the work-horse for pc_in_call_dummy and read_register_dummy     */
   This is the work-horse for pc_in_call_dummy and read_register_dummy     */
 
 
char *
char *
generic_find_dummy_frame (pc, fp)
generic_find_dummy_frame (pc, fp)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR fp;
     CORE_ADDR fp;
{
{
  struct dummy_frame *dummyframe;
  struct dummy_frame *dummyframe;
 
 
  if (pc != entry_point_address ())
  if (pc != entry_point_address ())
    return 0;
    return 0;
 
 
  for (dummyframe = dummy_frame_stack; dummyframe != NULL;
  for (dummyframe = dummy_frame_stack; dummyframe != NULL;
       dummyframe = dummyframe->next)
       dummyframe = dummyframe->next)
    if (fp == dummyframe->fp
    if (fp == dummyframe->fp
        || fp == dummyframe->sp
        || fp == dummyframe->sp
        || fp == dummyframe->top)
        || fp == dummyframe->top)
      /* The frame in question lies between the saved fp and sp, inclusive */
      /* The frame in question lies between the saved fp and sp, inclusive */
      return dummyframe->registers;
      return dummyframe->registers;
 
 
  return 0;
  return 0;
}
}
 
 
/* Function: pc_in_call_dummy (pc, fp)
/* Function: pc_in_call_dummy (pc, fp)
   Return true if this is a dummy frame created by gdb for an inferior call */
   Return true if this is a dummy frame created by gdb for an inferior call */
 
 
int
int
generic_pc_in_call_dummy (pc, sp, fp)
generic_pc_in_call_dummy (pc, sp, fp)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR sp;
     CORE_ADDR sp;
     CORE_ADDR fp;
     CORE_ADDR fp;
{
{
  /* if find_dummy_frame succeeds, then PC is in a call dummy */
  /* if find_dummy_frame succeeds, then PC is in a call dummy */
  /* Note: SP and not FP is passed on. */
  /* Note: SP and not FP is passed on. */
  return (generic_find_dummy_frame (pc, sp) != 0);
  return (generic_find_dummy_frame (pc, sp) != 0);
}
}
 
 
/* Function: read_register_dummy
/* Function: read_register_dummy
   Find a saved register from before GDB calls a function in the inferior */
   Find a saved register from before GDB calls a function in the inferior */
 
 
CORE_ADDR
CORE_ADDR
generic_read_register_dummy (pc, fp, regno)
generic_read_register_dummy (pc, fp, regno)
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR fp;
     CORE_ADDR fp;
     int regno;
     int regno;
{
{
  char *dummy_regs = generic_find_dummy_frame (pc, fp);
  char *dummy_regs = generic_find_dummy_frame (pc, fp);
 
 
  if (dummy_regs)
  if (dummy_regs)
    return extract_address (&dummy_regs[REGISTER_BYTE (regno)],
    return extract_address (&dummy_regs[REGISTER_BYTE (regno)],
                            REGISTER_RAW_SIZE (regno));
                            REGISTER_RAW_SIZE (regno));
  else
  else
    return 0;
    return 0;
}
}
 
 
/* Save all the registers on the dummy frame stack.  Most ports save the
/* Save all the registers on the dummy frame stack.  Most ports save the
   registers on the target stack.  This results in lots of unnecessary memory
   registers on the target stack.  This results in lots of unnecessary memory
   references, which are slow when debugging via a serial line.  Instead, we
   references, which are slow when debugging via a serial line.  Instead, we
   save all the registers internally, and never write them to the stack.  The
   save all the registers internally, and never write them to the stack.  The
   registers get restored when the called function returns to the entry point,
   registers get restored when the called function returns to the entry point,
   where a breakpoint is laying in wait.  */
   where a breakpoint is laying in wait.  */
 
 
void
void
generic_push_dummy_frame ()
generic_push_dummy_frame ()
{
{
  struct dummy_frame *dummy_frame;
  struct dummy_frame *dummy_frame;
  CORE_ADDR fp = (get_current_frame ())->frame;
  CORE_ADDR fp = (get_current_frame ())->frame;
 
 
  /* check to see if there are stale dummy frames,
  /* check to see if there are stale dummy frames,
     perhaps left over from when a longjump took us out of a
     perhaps left over from when a longjump took us out of a
     function that was called by the debugger */
     function that was called by the debugger */
 
 
  dummy_frame = dummy_frame_stack;
  dummy_frame = dummy_frame_stack;
  while (dummy_frame)
  while (dummy_frame)
    if (INNER_THAN (dummy_frame->fp, fp))       /* stale -- destroy! */
    if (INNER_THAN (dummy_frame->fp, fp))       /* stale -- destroy! */
      {
      {
        dummy_frame_stack = dummy_frame->next;
        dummy_frame_stack = dummy_frame->next;
        free (dummy_frame->registers);
        free (dummy_frame->registers);
        free (dummy_frame);
        free (dummy_frame);
        dummy_frame = dummy_frame_stack;
        dummy_frame = dummy_frame_stack;
      }
      }
    else
    else
      dummy_frame = dummy_frame->next;
      dummy_frame = dummy_frame->next;
 
 
  dummy_frame = xmalloc (sizeof (struct dummy_frame));
  dummy_frame = xmalloc (sizeof (struct dummy_frame));
  dummy_frame->registers = xmalloc (REGISTER_BYTES);
  dummy_frame->registers = xmalloc (REGISTER_BYTES);
 
 
  dummy_frame->pc = read_register (PC_REGNUM);
  dummy_frame->pc = read_register (PC_REGNUM);
  dummy_frame->sp = read_register (SP_REGNUM);
  dummy_frame->sp = read_register (SP_REGNUM);
  dummy_frame->top = dummy_frame->sp;
  dummy_frame->top = dummy_frame->sp;
  dummy_frame->fp = fp;
  dummy_frame->fp = fp;
  read_register_bytes (0, dummy_frame->registers, REGISTER_BYTES);
  read_register_bytes (0, dummy_frame->registers, REGISTER_BYTES);
  dummy_frame->next = dummy_frame_stack;
  dummy_frame->next = dummy_frame_stack;
  dummy_frame_stack = dummy_frame;
  dummy_frame_stack = dummy_frame;
}
}
 
 
void
void
generic_save_dummy_frame_tos (sp)
generic_save_dummy_frame_tos (sp)
     CORE_ADDR sp;
     CORE_ADDR sp;
{
{
  dummy_frame_stack->top = sp;
  dummy_frame_stack->top = sp;
}
}
 
 
/* Restore the machine state from either the saved dummy stack or a
/* Restore the machine state from either the saved dummy stack or a
   real stack frame. */
   real stack frame. */
 
 
void
void
generic_pop_current_frame (void (*popper) (struct frame_info * frame))
generic_pop_current_frame (void (*popper) (struct frame_info * frame))
{
{
  struct frame_info *frame = get_current_frame ();
  struct frame_info *frame = get_current_frame ();
 
 
  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
    generic_pop_dummy_frame ();
    generic_pop_dummy_frame ();
  else
  else
    (*popper) (frame);
    (*popper) (frame);
}
}
 
 
/* Function: pop_dummy_frame
/* Function: pop_dummy_frame
   Restore the machine state from a saved dummy stack frame. */
   Restore the machine state from a saved dummy stack frame. */
 
 
void
void
generic_pop_dummy_frame ()
generic_pop_dummy_frame ()
{
{
  struct dummy_frame *dummy_frame = dummy_frame_stack;
  struct dummy_frame *dummy_frame = dummy_frame_stack;
 
 
  /* FIXME: what if the first frame isn't the right one, eg..
  /* FIXME: what if the first frame isn't the right one, eg..
     because one call-by-hand function has done a longjmp into another one? */
     because one call-by-hand function has done a longjmp into another one? */
 
 
  if (!dummy_frame)
  if (!dummy_frame)
    error ("Can't pop dummy frame!");
    error ("Can't pop dummy frame!");
  dummy_frame_stack = dummy_frame->next;
  dummy_frame_stack = dummy_frame->next;
  write_register_bytes (0, dummy_frame->registers, REGISTER_BYTES);
  write_register_bytes (0, dummy_frame->registers, REGISTER_BYTES);
  flush_cached_frames ();
  flush_cached_frames ();
 
 
  free (dummy_frame->registers);
  free (dummy_frame->registers);
  free (dummy_frame);
  free (dummy_frame);
}
}
 
 
/* Function: frame_chain_valid
/* Function: frame_chain_valid
   Returns true for a user frame or a call_function_by_hand dummy frame,
   Returns true for a user frame or a call_function_by_hand dummy frame,
   and false for the CRT0 start-up frame.  Purpose is to terminate backtrace */
   and false for the CRT0 start-up frame.  Purpose is to terminate backtrace */
 
 
int
int
generic_file_frame_chain_valid (fp, fi)
generic_file_frame_chain_valid (fp, fi)
     CORE_ADDR fp;
     CORE_ADDR fp;
     struct frame_info *fi;
     struct frame_info *fi;
{
{
  if (PC_IN_CALL_DUMMY (FRAME_SAVED_PC (fi), fp, fp))
  if (PC_IN_CALL_DUMMY (FRAME_SAVED_PC (fi), fp, fp))
    return 1;                   /* don't prune CALL_DUMMY frames */
    return 1;                   /* don't prune CALL_DUMMY frames */
  else                          /* fall back to default algorithm (see frame.h) */
  else                          /* fall back to default algorithm (see frame.h) */
    return (fp != 0
    return (fp != 0
            && (INNER_THAN (fi->frame, fp) || fi->frame == fp)
            && (INNER_THAN (fi->frame, fp) || fi->frame == fp)
            && !inside_entry_file (FRAME_SAVED_PC (fi)));
            && !inside_entry_file (FRAME_SAVED_PC (fi)));
}
}
 
 
int
int
generic_func_frame_chain_valid (fp, fi)
generic_func_frame_chain_valid (fp, fi)
     CORE_ADDR fp;
     CORE_ADDR fp;
     struct frame_info *fi;
     struct frame_info *fi;
{
{
  if (PC_IN_CALL_DUMMY ((fi)->pc, fp, fp))
  if (PC_IN_CALL_DUMMY ((fi)->pc, fp, fp))
    return 1;                   /* don't prune CALL_DUMMY frames */
    return 1;                   /* don't prune CALL_DUMMY frames */
  else                          /* fall back to default algorithm (see frame.h) */
  else                          /* fall back to default algorithm (see frame.h) */
    return (fp != 0
    return (fp != 0
            && (INNER_THAN (fi->frame, fp) || fi->frame == fp)
            && (INNER_THAN (fi->frame, fp) || fi->frame == fp)
            && !inside_main_func ((fi)->pc)
            && !inside_main_func ((fi)->pc)
            && !inside_entry_func ((fi)->pc));
            && !inside_entry_func ((fi)->pc));
}
}
 
 
/* Function: fix_call_dummy
/* Function: fix_call_dummy
   Stub function.  Generic dumy frames typically do not need to fix
   Stub function.  Generic dumy frames typically do not need to fix
   the frame being created */
   the frame being created */
 
 
void
void
generic_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
generic_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
     char *dummy;
     char *dummy;
     CORE_ADDR pc;
     CORE_ADDR pc;
     CORE_ADDR fun;
     CORE_ADDR fun;
     int nargs;
     int nargs;
     struct value **args;
     struct value **args;
     struct type *type;
     struct type *type;
     int gcc_p;
     int gcc_p;
{
{
  return;
  return;
}
}
 
 
/* Function: get_saved_register
/* Function: get_saved_register
   Find register number REGNUM relative to FRAME and put its (raw,
   Find register number REGNUM relative to FRAME and put its (raw,
   target format) contents in *RAW_BUFFER.
   target format) contents in *RAW_BUFFER.
 
 
   Set *OPTIMIZED if the variable was optimized out (and thus can't be
   Set *OPTIMIZED if the variable was optimized out (and thus can't be
   fetched).  Note that this is never set to anything other than zero
   fetched).  Note that this is never set to anything other than zero
   in this implementation.
   in this implementation.
 
 
   Set *LVAL to lval_memory, lval_register, or not_lval, depending on
   Set *LVAL to lval_memory, lval_register, or not_lval, depending on
   whether the value was fetched from memory, from a register, or in a
   whether the value was fetched from memory, from a register, or in a
   strange and non-modifiable way (e.g. a frame pointer which was
   strange and non-modifiable way (e.g. a frame pointer which was
   calculated rather than fetched).  We will use not_lval for values
   calculated rather than fetched).  We will use not_lval for values
   fetched from generic dummy frames.
   fetched from generic dummy frames.
 
 
   Set *ADDRP to the address, either in memory on as a REGISTER_BYTE
   Set *ADDRP to the address, either in memory on as a REGISTER_BYTE
   offset into the registers array.  If the value is stored in a dummy
   offset into the registers array.  If the value is stored in a dummy
   frame, set *ADDRP to zero.
   frame, set *ADDRP to zero.
 
 
   To use this implementation, define a function called
   To use this implementation, define a function called
   "get_saved_register" in your target code, which simply passes all
   "get_saved_register" in your target code, which simply passes all
   of its arguments to this function.
   of its arguments to this function.
 
 
   The argument RAW_BUFFER must point to aligned memory.  */
   The argument RAW_BUFFER must point to aligned memory.  */
 
 
void
void
generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
     char *raw_buffer;
     char *raw_buffer;
     int *optimized;
     int *optimized;
     CORE_ADDR *addrp;
     CORE_ADDR *addrp;
     struct frame_info *frame;
     struct frame_info *frame;
     int regnum;
     int regnum;
     enum lval_type *lval;
     enum lval_type *lval;
{
{
  if (!target_has_registers)
  if (!target_has_registers)
    error ("No registers.");
    error ("No registers.");
 
 
  /* Normal systems don't optimize out things with register numbers.  */
  /* Normal systems don't optimize out things with register numbers.  */
  if (optimized != NULL)
  if (optimized != NULL)
    *optimized = 0;
    *optimized = 0;
 
 
  if (addrp)                    /* default assumption: not found in memory */
  if (addrp)                    /* default assumption: not found in memory */
    *addrp = 0;
    *addrp = 0;
 
 
  /* Note: since the current frame's registers could only have been
  /* Note: since the current frame's registers could only have been
     saved by frames INTERIOR TO the current frame, we skip examining
     saved by frames INTERIOR TO the current frame, we skip examining
     the current frame itself: otherwise, we would be getting the
     the current frame itself: otherwise, we would be getting the
     previous frame's registers which were saved by the current frame.  */
     previous frame's registers which were saved by the current frame.  */
 
 
  while (frame && ((frame = frame->next) != NULL))
  while (frame && ((frame = frame->next) != NULL))
    {
    {
      if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
      if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
        {
        {
          if (lval)             /* found it in a CALL_DUMMY frame */
          if (lval)             /* found it in a CALL_DUMMY frame */
            *lval = not_lval;
            *lval = not_lval;
          if (raw_buffer)
          if (raw_buffer)
            memcpy (raw_buffer,
            memcpy (raw_buffer,
                    generic_find_dummy_frame (frame->pc, frame->frame) +
                    generic_find_dummy_frame (frame->pc, frame->frame) +
                    REGISTER_BYTE (regnum),
                    REGISTER_BYTE (regnum),
                    REGISTER_RAW_SIZE (regnum));
                    REGISTER_RAW_SIZE (regnum));
          return;
          return;
        }
        }
 
 
      FRAME_INIT_SAVED_REGS (frame);
      FRAME_INIT_SAVED_REGS (frame);
      if (frame->saved_regs != NULL
      if (frame->saved_regs != NULL
          && frame->saved_regs[regnum] != 0)
          && frame->saved_regs[regnum] != 0)
        {
        {
          if (lval)             /* found it saved on the stack */
          if (lval)             /* found it saved on the stack */
            *lval = lval_memory;
            *lval = lval_memory;
          if (regnum == SP_REGNUM)
          if (regnum == SP_REGNUM)
            {
            {
              if (raw_buffer)   /* SP register treated specially */
              if (raw_buffer)   /* SP register treated specially */
                store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
                store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
                               frame->saved_regs[regnum]);
                               frame->saved_regs[regnum]);
            }
            }
          else
          else
            {
            {
              if (addrp)        /* any other register */
              if (addrp)        /* any other register */
                *addrp = frame->saved_regs[regnum];
                *addrp = frame->saved_regs[regnum];
              if (raw_buffer)
              if (raw_buffer)
                read_memory (frame->saved_regs[regnum], raw_buffer,
                read_memory (frame->saved_regs[regnum], raw_buffer,
                             REGISTER_RAW_SIZE (regnum));
                             REGISTER_RAW_SIZE (regnum));
            }
            }
          return;
          return;
        }
        }
    }
    }
 
 
  /* If we get thru the loop to this point, it means the register was
  /* If we get thru the loop to this point, it means the register was
     not saved in any frame.  Return the actual live-register value.  */
     not saved in any frame.  Return the actual live-register value.  */
 
 
  if (lval)                     /* found it in a live register */
  if (lval)                     /* found it in a live register */
    *lval = lval_register;
    *lval = lval_register;
  if (addrp)
  if (addrp)
    *addrp = REGISTER_BYTE (regnum);
    *addrp = REGISTER_BYTE (regnum);
  if (raw_buffer)
  if (raw_buffer)
    read_register_gen (regnum, raw_buffer);
    read_register_gen (regnum, raw_buffer);
}
}
 
 
void
void
_initialize_blockframe (void)
_initialize_blockframe (void)
{
{
  obstack_init (&frame_cache_obstack);
  obstack_init (&frame_cache_obstack);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.