@ -1,6 +1,6 @@
/* Get info from stack frames;
convert between frames , blocks , functions and pc values .
Copyright ( C ) 1986 , 1987 , 1988 , 1989 Free Software Foundation , Inc .
Copyright 1986 , 1987 , 1988 , 1989 , 1991 Free Software Foundation , Inc .
This file is part of GDB .
@ -18,111 +18,75 @@ You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA . */
# include <stdio.h>
# include "defs.h"
# include "param.h"
# include "symtab.h"
# include "bfd.h"
# include "symfile.h"
# include "objfiles.h"
# include "frame.h"
# include "gdbcore.h"
# include "value.h" /* for read_register */
# include "target.h" /* for target_has_stack */
# include "inferior.h" /* for read_pc */
CORE_ADDR read_pc ( ) ; /* In infcmd.c */
/* Start and end of object file containing the entry point.
STARTUP_FILE_END is the first address of the next file .
This file is assumed to be a startup file
and frames with pc ' s inside it
are treated as nonexistent .
Setting these variables is necessary so that backtraces do not fly off
the bottom of the stack . */
CORE_ADDR startup_file_start ;
CORE_ADDR startup_file_end ;
/* Is ADDR outside 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
to call this function from FRAME_CHAIN_VALID ; the reason for
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 . */
int
outside_startup_file ( addr )
inside_entry_file ( addr )
CORE_ADDR addr ;
{
return ! ( addr > = startup_file_start & & addr < startup_file_end ) ;
if ( addr = = 0 )
return 1 ;
if ( symfile_objfile = = 0 )
return 0 ;
return ( addr > = symfile_objfile - > ei . entry_file_lowpc & &
addr < symfile_objfile - > ei . entry_file_highpc ) ;
}
/* Support an alternate method to avoid running off the bottom of
the stack ( or top , depending upon your stack orientation ) .
There are two frames that are " special " , the frame for the function
containing the process entry point , since it has no predecessor frame ,
and the frame for the function containing the user code entry point
( the main ( ) function ) , since all the predecessor frames are for the
process startup code . Since we have no guarantee that the linked
in startup modules have any debugging information that gdb can use ,
we need to avoid following frame pointers back into frames that might
have been built in the startup code , as we might get hopelessly
confused . However , we almost always have debugging information
available for main ( ) .
These variables are used to save the range of PC values which are valid
within the main ( ) function and within the function containing the process
entry point . If we always consider the frame for main ( ) as the outermost
frame when debugging user code , and the frame for the process entry
point function as the outermost frame when debugging startup code , then
all we have to do is have FRAME_CHAIN_VALID return false whenever a
frame ' s current PC is within the range specified by these variables .
In essence , we set " blocks " in the frame chain beyond which we will
not proceed when following the frame chain .
A nice side effect is that we can still debug startup code without
running off the end of the frame chain , assuming that we have usable
debugging information in the startup modules , and if we choose to not
use the block at main , or can ' t find it for some reason , everything
still works as before . And if we have no startup code debugging
information but we do have usable information for main ( ) , backtraces
from user code don ' t go wandering off into the startup code .
To use this method , define your FRAME_CHAIN_VALID macro like :
# define FRAME_CHAIN_VALID(chain, thisframe) \
( chain ! = 0 \
& & ! ( inside_main_scope ( ( thisframe ) - > pc ) ) \
& & ! ( inside_entry_scope ( ( thisframe ) - > pc ) ) )
and add initializations of the four scope controlling variables inside
the object file / debugging information processing modules . */
CORE_ADDR entry_scope_lowpc ;
CORE_ADDR entry_scope_highpc ;
CORE_ADDR main_scope_lowpc ;
CORE_ADDR main_scope_highpc ;
/* 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
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 . */
int
inside_main_scope ( pc )
inside_main_func ( pc )
CORE_ADDR pc ;
{
return ( main_scope_lowpc < = pc & & pc < main_scope_highpc ) ;
if ( pc = = 0 )
return 1 ;
if ( symfile_objfile = = 0 )
return 0 ;
return ( symfile_objfile - > ei . main_func_lowpc < = pc & &
symfile_objfile - > ei . main_func_highpc > pc ) ;
}
/* 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 above
for why we might want to do this .
that correspond to the process entry point function . See comments
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 . */
int
inside_entry_scope ( pc )
inside_entry_func ( pc )
CORE_ADDR pc ;
{
return ( entry_scope_lowpc < = pc & & pc < entry_scope_highpc ) ;
if ( pc = = 0 )
return 1 ;
if ( symfile_objfile = = 0 )
return 0 ;
return ( symfile_objfile - > ei . entry_func_lowpc < = pc & &
symfile_objfile - > ei . entry_func_highpc > pc ) ;
}
/* Address of innermost stack frame (contents of FP register) */
@ -169,8 +133,8 @@ create_new_frame (addr, pc)
fci - > next = ( struct frame_info * ) 0 ;
fci - > prev = ( struct frame_info * ) 0 ;
fci - > frame = addr ;
fci - > next_frame = 0 ; /* Since arbitrary */
fci - > pc = pc ;
fci - > signal_handler_caller = IN_SIGTRAMP ( fci - > pc , ( char * ) NULL ) ;
# ifdef INIT_EXTRA_FRAME_INFO
INIT_EXTRA_FRAME_INFO ( 0 , fci ) ;
@ -223,8 +187,7 @@ reinit_frame_cache ()
FRAME fr = current_frame ;
flush_cached_frames ( ) ;
if ( fr )
set_current_frame ( create_new_frame ( read_register ( FP_REGNUM ) ,
read_pc ( ) ) ) ;
set_current_frame ( create_new_frame ( read_fp ( ) , read_pc ( ) ) ) ;
}
/* Return a structure containing various interesting information
@ -246,7 +209,7 @@ get_frame_info (frame)
frame_info for the frame , and FRAMELESS should be set to nonzero
if it represents a frameless function invocation . */
/* Return nonzero if the function for this frame ha s a prologue. Many
/* Return nonzero if the function for this frame lack s a prologue. Many
machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
function . */
@ -368,7 +331,47 @@ get_prev_frame_info (next_frame)
prev - > next = next_frame ;
prev - > prev = ( struct frame_info * ) 0 ;
prev - > frame = address ;
prev - > next_frame = prev - > next ? prev - > next - > frame : 0 ;
prev - > signal_handler_caller = 0 ;
/* This change should not be needed, FIXME! We should
determine whether any targets * need * INIT_FRAME_PC to happen
after INIT_EXTRA_FRAME_INFO and come up with a simple way to
express what goes on here .
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 ) .
INIT_FRAME_PC is only called from here , always after
INIT_EXTRA_FRAME_INFO .
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
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
an already overcomplicated part of GDB . gnu @ cygnus . com , 15 Sep92 .
To answer the question , yes the sparc needs INIT_FRAME_PC after
INIT_EXTRA_FRAME_INFO . Suggested scheme :
SETUP_INNERMOST_FRAME ( )
Default version is just create_new_frame ( read_fp ( ) ) ,
read_pc ( ) ) . Machines with extra frame info would do that ( or the
local equivalent ) and then set the extra fields .
SETUP_ARBITRARY_FRAME ( argc , argv )
Only change here is that create_new_frame would no longer init extra
frame info ; SETUP_ARBITRARY_FRAME would have to do that .
INIT_PREV_FRAME ( fromleaf , prev )
Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC .
std_frame_pc ( fromleaf , prev )
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
INIT_PREV_FRAME ( either at the beginning , the end , or in the middle ) .
Some machines won ' t use it .
kingdon @ cygnus . com , 13 Apr93 . */
# ifdef INIT_FRAME_PC_FIRST
INIT_FRAME_PC_FIRST ( fromleaf , prev ) ;
# endif
# ifdef INIT_EXTRA_FRAME_INFO
INIT_EXTRA_FRAME_INFO ( fromleaf , prev ) ;
@ -379,6 +382,9 @@ get_prev_frame_info (next_frame)
( see tm - sparc . h ) . We want the pc saved in the inferior frame . */
INIT_FRAME_PC ( fromleaf , prev ) ;
if ( IN_SIGTRAMP ( prev - > pc , ( char * ) NULL ) )
prev - > signal_handler_caller = 1 ;
return prev ;
}
@ -416,7 +422,7 @@ get_frame_block (frame)
fi = get_frame_info ( frame ) ;
pc = fi - > pc ;
if ( fi - > next_frame ! = 0 )
if ( fi - > next ! = 0 )
/* We are not in the innermost frame. We need to subtract one to
get the correct block , in case the call instruction was the
last instruction of the block . If there are any machines on
@ -436,17 +442,26 @@ CORE_ADDR
get_pc_function_start ( pc )
CORE_ADDR pc ;
{
register struct block * bl = block_for_pc ( pc ) ;
register struct block * bl ;
register struct symbol * symbol ;
if ( bl = = 0 | | ( symbol = block_function ( bl ) ) = = 0 )
register struct minimal_symbol * msymbol ;
CORE_ADDR fstart ;
if ( ( bl = block_for_pc ( pc ) ) ! = NULL & &
( symbol = block_function ( bl ) ) ! = NULL )
{
register int misc_index = find_pc_misc_function ( pc ) ;
if ( misc_index > = 0 )
return misc_function_vector [ misc_index ] . address ;
return 0 ;
bl = SYMBOL_BLOCK_VALUE ( symbol ) ;
fstart = BLOCK_START ( bl ) ;
}
bl = SYMBOL_BLOCK_VALUE ( symbol ) ;
return BLOCK_START ( bl ) ;
else if ( ( msymbol = lookup_minimal_symbol_by_pc ( pc ) ) ! = NULL )
{
fstart = SYMBOL_VALUE_ADDRESS ( msymbol ) ;
}
else
{
fstart = 0 ;
}
return ( fstart ) ;
}
/* Return the symbol for the function executing in frame FRAME. */
@ -578,7 +593,7 @@ find_pc_partial_function (pc, name, address)
{
struct partial_symtab * pst ;
struct symbol * f ;
int miscfunc ;
struct minimal_symbol * msymbol ;
struct partial_symbol * psb ;
if ( pc > = cache_pc_function_low & & pc < cache_pc_function_high )
@ -621,19 +636,18 @@ find_pc_partial_function (pc, name, address)
}
/* Get the information from a combination of the pst
( static symbols ) , and the misc function vector ( extern
( static symbols ) , and the minimal symbol table ( extern
symbols ) . */
miscfunc = find_pc_misc_function ( pc ) ;
msymbol = lookup_minimal_symbol_by_pc ( pc ) ;
psb = find_pc_psymbol ( pst , pc ) ;
if ( ! psb & & miscfunc = = - 1 )
if ( ! psb & & ( msymbol = = NULL ) )
{
goto return_error ;
}
if ( psb
& & ( miscfunc = = - 1
| | ( SYMBOL_VALUE_ADDRESS ( psb )
> = misc_function_vector [ miscfunc ] . address ) ) )
& & ( msymbol = = NULL | |
( SYMBOL_VALUE_ADDRESS ( psb ) > = SYMBOL_VALUE_ADDRESS ( msymbol ) ) ) )
{
/* This case isn't being cached currently. */
if ( address )
@ -644,23 +658,25 @@ find_pc_partial_function (pc, name, address)
}
}
else
/* Must be in the misc function stuff . */
/* Must be in the minimal symbol table . */
{
miscfunc = find_pc_misc_function ( pc ) ;
if ( miscfunc = = - 1 )
msymbol = lookup_minimal_symbol_by_pc ( pc ) ;
if ( msymbol = = NULL )
goto return_error ;
}
{
if ( misc_function_vector [ miscfunc ] . type = = mf _text )
cache_pc_function_low = misc_function_vector [ miscfunc ] . address ;
if ( msymbol - > type = = mst _text )
cache_pc_function_low = SYMBOL_VALUE_ADDRESS ( msymbol ) ;
else
/* It is a transfer table for Sun shared libraries. */
cache_pc_function_low = pc - FUNCTION_START_OFFSET ;
}
cache_pc_function_name = misc_function_vector [ miscfunc ] . name ;
if ( miscfunc < misc_function_count /* && FIXME mf_text again? */ )
cache_pc_function_high = misc_function_vector [ miscfunc + 1 ] . address ;
cache_pc_function_name = SYMBOL_NAME ( msymbol ) ;
/* FIXME: Deal with bumping into end of minimal symbols for a given
objfile , and what about testing for mst_text again ? */
if ( SYMBOL_NAME ( msymbol + 1 ) ! = NULL )
cache_pc_function_high = SYMBOL_VALUE_ADDRESS ( msymbol + 1 ) ;
else
cache_pc_function_high = cache_pc_function_low + 1 ;
if ( address )
@ -670,53 +686,11 @@ find_pc_partial_function (pc, name, address)
return 1 ;
}
/* Find the misc function whose address is the largest
while being less than PC . Return its index in misc_function_vector .
Returns - 1 if PC is not in suitable range . */
int
find_pc_misc_function ( pc )
register CORE_ADDR pc ;
{
register int lo = 0 ;
register int hi = misc_function_count - 1 ;
register int new ;
/* Note that the last thing in the vector is always _etext. */
/* Actually, "end", now that non-functions
go on the misc_function_vector . */
/* Above statement is not *always* true - fix for case where there are */
/* no misc functions at all (ie no symbol table has been read). */
if ( hi < 0 ) return - 1 ; /* no misc functions recorded */
/* trivial reject range test */
if ( pc < misc_function_vector [ 0 ] . address | |
pc > misc_function_vector [ hi ] . address )
return - 1 ;
/* Note that the following search will not return hi if
pc = = misc_function_vector [ hi ] . address . If " end " points to the
first unused location , this is correct and the above test
simply needs to be changed to
" pc >= misc_function_vector[hi].address " . */
do {
new = ( lo + hi ) > > 1 ;
if ( misc_function_vector [ new ] . address = = pc )
return new ; /* an exact match */
else if ( misc_function_vector [ new ] . address > pc )
hi = new ;
else
lo = new ;
} while ( hi - lo ! = 1 ) ;
/* if here, we had no exact match, so return the lower choice */
return lo ;
}
/* Return the innermost stack frame executing inside of the specified block,
or zero if there is no such frame . */
#if 0 /* Currently unused */
FRAME
block_innermost_frame ( block )
struct block * block ;
@ -738,6 +712,8 @@ block_innermost_frame (block)
}
}
# endif /* 0 */
void
_initialize_blockframe ( )
{