1999-04-16 01:33:56 +00:00
/* Target-machine dependent code for the AMD 29000
Copyright 1990 , 1991 , 1992 , 1993 , 1994 , 1995
Free Software Foundation , Inc .
Contributed by Cygnus Support . Written by Jim Kingdon .
This file is part of GDB .
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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . */
# include "defs.h"
# include "gdbcore.h"
# include "frame.h"
# include "value.h"
# include "symtab.h"
# include "inferior.h"
# include "gdbcmd.h"
/* If all these bits in an instruction word are zero, it is a "tag word"
which precedes a function entry point and gives stack traceback info .
This used to be defined as 0xff000000 , but that treated 0x00000deb as
a tag word , while it is really used as a breakpoint . */
# define TAGWORD_ZERO_MASK 0xff00f800
extern CORE_ADDR text_start ; /* FIXME, kludge... */
/* The user-settable top of the register stack in virtual memory. We
won ' t attempt to access any stored registers above this address , if set
nonzero . */
static CORE_ADDR rstack_high_address = UINT_MAX ;
/* Should call_function allocate stack space for a struct return? */
/* On the a29k objects over 16 words require the caller to allocate space. */
int
a29k_use_struct_convention ( gcc_p , type )
int gcc_p ;
struct type * type ;
{
return ( TYPE_LENGTH ( type ) > 16 * 4 ) ;
}
/* Structure to hold cached info about function prologues. */
struct prologue_info
{
CORE_ADDR pc ; /* First addr after fn prologue */
unsigned rsize , msize ; /* register stack frame size, mem stack ditto */
unsigned mfp_used : 1 ; /* memory frame pointer used */
unsigned rsize_valid : 1 ; /* Validity bits for the above */
unsigned msize_valid : 1 ;
unsigned mfp_valid : 1 ;
} ;
/* Examine the prologue of a function which starts at PC. Return
the first addess past the prologue . If MSIZE is non - NULL , then
set * MSIZE to the memory stack frame size . If RSIZE is non - NULL ,
then set * RSIZE to the register stack frame size ( not including
incoming arguments and the return address & frame pointer stored
with them ) . If no prologue is found , * RSIZE is set to zero .
If no prologue is found , or a prologue which doesn ' t involve
allocating a memory stack frame , then set * MSIZE to zero .
Note that both msize and rsize are in bytes . This is not consistent
with the _User ' s Manual_ with respect to rsize , but it is much more
convenient .
If MFP_USED is non - NULL , * MFP_USED is set to nonzero if a memory
frame pointer is being used . */
CORE_ADDR
examine_prologue ( pc , rsize , msize , mfp_used )
CORE_ADDR pc ;
unsigned * msize ;
unsigned * rsize ;
int * mfp_used ;
{
long insn ;
CORE_ADDR p = pc ;
struct minimal_symbol * msymbol = lookup_minimal_symbol_by_pc ( pc ) ;
struct prologue_info * mi = 0 ;
if ( msymbol ! = NULL )
mi = ( struct prologue_info * ) msymbol - > info ;
if ( mi ! = 0 )
{
int valid = 1 ;
if ( rsize ! = NULL )
{
* rsize = mi - > rsize ;
valid & = mi - > rsize_valid ;
}
if ( msize ! = NULL )
{
* msize = mi - > msize ;
valid & = mi - > msize_valid ;
}
if ( mfp_used ! = NULL )
{
* mfp_used = mi - > mfp_used ;
valid & = mi - > mfp_valid ;
}
if ( valid )
return mi - > pc ;
}
if ( rsize ! = NULL )
* rsize = 0 ;
if ( msize ! = NULL )
* msize = 0 ;
if ( mfp_used ! = NULL )
* mfp_used = 0 ;
/* Prologue must start with subtracting a constant from gr1.
Normally this is sub gr1 , gr1 , < rsize * 4 > . */
insn = read_memory_integer ( p , 4 ) ;
if ( ( insn & 0xffffff00 ) ! = 0x25010100 )
{
/* If the frame is large, instead of a single instruction it
might be a pair of instructions :
const < reg > , < rsize * 4 >
sub gr1 , gr1 , < reg >
*/
int reg ;
/* Possible value for rsize. */
unsigned int rsize0 ;
if ( ( insn & 0xff000000 ) ! = 0x03000000 )
{
p = pc ;
goto done ;
}
reg = ( insn > > 8 ) & 0xff ;
rsize0 = ( ( ( insn > > 8 ) & 0xff00 ) | ( insn & 0xff ) ) ;
p + = 4 ;
insn = read_memory_integer ( p , 4 ) ;
if ( ( insn & 0xffffff00 ) ! = 0x24010100
| | ( insn & 0xff ) ! = reg )
{
p = pc ;
goto done ;
}
if ( rsize ! = NULL )
* rsize = rsize0 ;
}
else
{
if ( rsize ! = NULL )
* rsize = ( insn & 0xff ) ;
}
p + = 4 ;
/* Next instruction ought to be asgeu V_SPILL,gr1,rab.
* We don ' t check the vector number to allow for kernel debugging . The
* kernel will use a different trap number .
* If this insn is missing , we just keep going ; Metaware R2 .3 u compiler
* generates prologue that intermixes initializations and puts the asgeu
* way down .
*/
insn = read_memory_integer ( p , 4 ) ;
if ( ( insn & 0xff00ffff ) = = ( 0x5e000100 | RAB_HW_REGNUM ) )
{
p + = 4 ;
}
/* Next instruction usually sets the frame pointer (lr1) by adding
< size * 4 > from gr1 . However , this can ( and high C does ) be
deferred until anytime before the first function call . So it is
OK if we don ' t see anything which sets lr1 .
To allow for alternate register sets ( gcc - mkernel - registers ) the msp
register number is a compile time constant . */
/* Normally this is just add lr1,gr1,<size * 4>. */
insn = read_memory_integer ( p , 4 ) ;
if ( ( insn & 0xffffff00 ) = = 0x15810100 )
p + = 4 ;
else
{
/* However, for large frames it can be
const < reg > , < size * 4 >
add lr1 , gr1 , < reg >
*/
int reg ;
CORE_ADDR q ;
if ( ( insn & 0xff000000 ) = = 0x03000000 )
{
reg = ( insn > > 8 ) & 0xff ;
q = p + 4 ;
insn = read_memory_integer ( q , 4 ) ;
if ( ( insn & 0xffffff00 ) = = 0x14810100
& & ( insn & 0xff ) = = reg )
p = q ;
}
}
/* Next comes "add lr{<rsize-1>},msp,0", but only if a memory
frame pointer is in use . We just check for add lr < anything > , msp , 0 ;
we don ' t check this rsize against the first instruction , and
we don ' t check that the trace - back tag indicates a memory frame pointer
is in use .
To allow for alternate register sets ( gcc - mkernel - registers ) the msp
register number is a compile time constant .
The recommended instruction is actually " sll lr<whatever>,msp,0 " .
We check for that , too . Originally Jim Kingdon ' s code seemed
to be looking for a " sub " instruction here , but the mask was set
up to lose all the time . */
insn = read_memory_integer ( p , 4 ) ;
if ( ( ( insn & 0xff80ffff ) = = ( 0x15800000 | ( MSP_HW_REGNUM < < 8 ) ) ) /* add */
| | ( ( insn & 0xff80ffff ) = = ( 0x81800000 | ( MSP_HW_REGNUM < < 8 ) ) ) ) /* sll */
{
p + = 4 ;
if ( mfp_used ! = NULL )
* mfp_used = 1 ;
}
/* Next comes a subtraction from msp to allocate a memory frame,
but only if a memory frame is
being used . We don ' t check msize against the trace - back tag .
To allow for alternate register sets ( gcc - mkernel - registers ) the msp
register number is a compile time constant .
Normally this is just
sub msp , msp , < msize >
*/
insn = read_memory_integer ( p , 4 ) ;
if ( ( insn & 0xffffff00 ) = =
( 0x25000000 | ( MSP_HW_REGNUM < < 16 ) | ( MSP_HW_REGNUM < < 8 ) ) )
{
p + = 4 ;
if ( msize ! = NULL )
* msize = insn & 0xff ;
}
else
{
/* For large frames, instead of a single instruction it might
be
const < reg > , < msize >
consth < reg > , < msize > ; optional
sub msp , msp , < reg >
*/
int reg ;
unsigned msize0 ;
CORE_ADDR q = p ;
if ( ( insn & 0xff000000 ) = = 0x03000000 )
{
reg = ( insn > > 8 ) & 0xff ;
msize0 = ( ( insn > > 8 ) & 0xff00 ) | ( insn & 0xff ) ;
q + = 4 ;
insn = read_memory_integer ( q , 4 ) ;
/* Check for consth. */
if ( ( insn & 0xff000000 ) = = 0x02000000
& & ( insn & 0x0000ff00 ) = = reg )
{
msize0 | = ( insn < < 8 ) & 0xff000000 ;
msize0 | = ( insn < < 16 ) & 0x00ff0000 ;
q + = 4 ;
insn = read_memory_integer ( q , 4 ) ;
}
/* Check for sub msp,msp,<reg>. */
if ( ( insn & 0xffffff00 ) = =
( 0x24000000 | ( MSP_HW_REGNUM < < 16 ) | ( MSP_HW_REGNUM < < 8 ) )
& & ( insn & 0xff ) = = reg )
{
p = q + 4 ;
if ( msize ! = NULL )
* msize = msize0 ;
}
}
}
/* Next instruction might be asgeu V_SPILL,gr1,rab.
* We don ' t check the vector number to allow for kernel debugging . The
* kernel will use a different trap number .
* Metaware R2 .3 u compiler
* generates prologue that intermixes initializations and puts the asgeu
* way down after everything else .
*/
insn = read_memory_integer ( p , 4 ) ;
if ( ( insn & 0xff00ffff ) = = ( 0x5e000100 | RAB_HW_REGNUM ) )
{
p + = 4 ;
}
done :
if ( msymbol ! = NULL )
{
if ( mi = = 0 )
{
/* Add a new cache entry. */
mi = ( struct prologue_info * ) xmalloc ( sizeof ( struct prologue_info ) ) ;
msymbol - > info = ( char * ) mi ;
mi - > rsize_valid = 0 ;
mi - > msize_valid = 0 ;
mi - > mfp_valid = 0 ;
}
/* else, cache entry exists, but info is incomplete. */
mi - > pc = p ;
if ( rsize ! = NULL )
{
mi - > rsize = * rsize ;
mi - > rsize_valid = 1 ;
}
if ( msize ! = NULL )
{
mi - > msize = * msize ;
mi - > msize_valid = 1 ;
}
if ( mfp_used ! = NULL )
{
mi - > mfp_used = * mfp_used ;
mi - > mfp_valid = 1 ;
}
}
return p ;
}
/* Advance PC across any function entry prologue instructions
to reach some " real " code . */
CORE_ADDR
1999-05-05 14:42:03 +00:00
a29k_skip_prologue ( pc )
1999-04-16 01:33:56 +00:00
CORE_ADDR pc ;
{
return examine_prologue ( pc , NULL , NULL , NULL ) ;
}
/*
* Examine the one or two word tag at the beginning of a function .
* The tag word is expect to be at ' p ' , if it is not there , we fail
* by returning 0. The documentation for the tag word was taken from
* page 7 - 15 of the 29050 User ' s Manual . We are assuming that the
* m bit is in bit 22 of the tag word , which seems to be the agreed upon
* convention today ( 1 / 15 / 92 ) .
* msize is return in bytes .
*/
static int /* 0/1 - failure/success of finding the tag word */
examine_tag ( p , is_trans , argcount , msize , mfp_used )
CORE_ADDR p ;
int * is_trans ;
int * argcount ;
unsigned * msize ;
int * mfp_used ;
{
unsigned int tag1 , tag2 ;
tag1 = read_memory_integer ( p , 4 ) ;
if ( ( tag1 & TAGWORD_ZERO_MASK ) ! = 0 ) /* Not a tag word */
return 0 ;
if ( tag1 & ( 1 < < 23 ) ) /* A two word tag */
{
tag2 = read_memory_integer ( p - 4 , 4 ) ;
if ( msize )
* msize = tag2 * 2 ;
}
else /* A one word tag */
{
if ( msize )
* msize = tag1 & 0x7ff ;
}
if ( is_trans )
* is_trans = ( ( tag1 & ( 1 < < 21 ) ) ? 1 : 0 ) ;
/* Note that this includes the frame pointer and the return address
register , so the actual number of registers of arguments is two less .
argcount can be zero , however , sometimes , for strange assembler
routines . */
if ( argcount )
* argcount = ( tag1 > > 16 ) & 0x1f ;
if ( mfp_used )
* mfp_used = ( ( tag1 & ( 1 < < 22 ) ) ? 1 : 0 ) ;
return 1 ;
}
/* Initialize the frame. In addition to setting "extra" frame info,
we also set - > frame because we use it in a nonstandard way , and - > pc
because we need to know it to get the other stuff . See the diagram
of stacks and the frame cache in tm - a29k . h for more detail . */
static void
init_frame_info ( innermost_frame , frame )
int innermost_frame ;
struct frame_info * frame ;
{
CORE_ADDR p ;
long insn ;
unsigned rsize ;
unsigned msize ;
int mfp_used , trans ;
struct symbol * func ;
p = frame - > pc ;
if ( innermost_frame )
frame - > frame = read_register ( GR1_REGNUM ) ;
else
frame - > frame = frame - > next - > frame + frame - > next - > rsize ;
#if 0 /* CALL_DUMMY_LOCATION == ON_STACK */
This wont work ;
# else
if ( PC_IN_CALL_DUMMY ( p , 0 , 0 ) )
# endif
{
frame - > rsize = DUMMY_FRAME_RSIZE ;
/* This doesn't matter since we never try to get locals or args
from a dummy frame . */
frame - > msize = 0 ;
/* Dummy frames always use a memory frame pointer. */
frame - > saved_msp =
read_register_stack_integer ( frame - > frame + DUMMY_FRAME_RSIZE - 4 , 4 ) ;
frame - > flags | = ( TRANSPARENT_FRAME | MFP_USED ) ;
return ;
}
func = find_pc_function ( p ) ;
if ( func ! = NULL )
p = BLOCK_START ( SYMBOL_BLOCK_VALUE ( func ) ) ;
else
{
/* Search backward to find the trace-back tag. However,
do not trace back beyond the start of the text segment
( just as a sanity check to avoid going into never - never land ) . */
# if 1
while ( p > = text_start
& & ( ( insn = read_memory_integer ( p , 4 ) ) & TAGWORD_ZERO_MASK ) ! = 0 )
p - = 4 ;
# else /* 0 */
char pat [ 4 ] = { 0 , 0 , 0 , 0 } ;
char mask [ 4 ] ;
char insn_raw [ 4 ] ;
store_unsigned_integer ( mask , 4 , TAGWORD_ZERO_MASK ) ;
/* Enable this once target_search is enabled and tested. */
target_search ( 4 , pat , mask , p , - 4 , text_start , p + 1 , & p , & insn_raw ) ;
insn = extract_unsigned_integer ( insn_raw , 4 ) ;
# endif /* 0 */
if ( p < text_start )
{
/* Couldn't find the trace-back tag.
Something strange is going on . */
frame - > saved_msp = 0 ;
frame - > rsize = 0 ;
frame - > msize = 0 ;
frame - > flags = TRANSPARENT_FRAME ;
return ;
}
else
/* Advance to the first word of the function, i.e. the word
after the trace - back tag . */
p + = 4 ;
}
/* We've found the start of the function.
Try looking for a tag word that indicates whether there is a
memory frame pointer and what the memory stack allocation is .
If one doesn ' t exist , try using a more exhaustive search of
the prologue . */
if ( examine_tag ( p - 4 , & trans , ( int * ) NULL , & msize , & mfp_used ) ) /* Found good tag */
examine_prologue ( p , & rsize , 0 , 0 ) ;
else /* No tag try prologue */
examine_prologue ( p , & rsize , & msize , & mfp_used ) ;
frame - > rsize = rsize ;
frame - > msize = msize ;
frame - > flags = 0 ;
if ( mfp_used )
frame - > flags | = MFP_USED ;
if ( trans )
frame - > flags | = TRANSPARENT_FRAME ;
if ( innermost_frame )
{
frame - > saved_msp = read_register ( MSP_REGNUM ) + msize ;
}
else
{
if ( mfp_used )
frame - > saved_msp =
read_register_stack_integer ( frame - > frame + rsize - 4 , 4 ) ;
else
frame - > saved_msp = frame - > next - > saved_msp + msize ;
}
}
void
init_extra_frame_info ( frame )
struct frame_info * frame ;
{
if ( frame - > next = = 0 )
/* Assume innermost frame. May produce strange results for "info frame"
but there isn ' t any way to tell the difference . */
init_frame_info ( 1 , frame ) ;
else {
1999-04-26 18:23:13 +00:00
/* We're in get_prev_frame.
1999-04-16 01:33:56 +00:00
Take care of everything in init_frame_pc . */
;
}
}
void
init_frame_pc ( fromleaf , frame )
int fromleaf ;
struct frame_info * frame ;
{
frame - > pc = ( fromleaf ? SAVED_PC_AFTER_CALL ( frame - > next ) :
frame - > next ? FRAME_SAVED_PC ( frame - > next ) : read_pc ( ) ) ;
init_frame_info ( fromleaf , frame ) ;
}
/* Local variables (i.e. LOC_LOCAL) are on the memory stack, with their
offsets being relative to the memory stack pointer ( high C ) or
saved_msp ( gcc ) . */
CORE_ADDR
frame_locals_address ( fi )
struct frame_info * fi ;
{
if ( fi - > flags & MFP_USED )
return fi - > saved_msp ;
else
return fi - > saved_msp - fi - > msize ;
}
/* Routines for reading the register stack. The caller gets to treat
the register stack as a uniform stack in memory , from address $ gr1
straight through $ rfb and beyond . */
/* Analogous to read_memory except the length is understood to be 4.
Also , myaddr can be NULL ( meaning don ' t bother to read ) , and
if actual_mem_addr is non - NULL , store there the address that it
was fetched from ( or if from a register the offset within
registers ) . Set * LVAL to lval_memory or lval_register , depending
on where it came from . The contents written into MYADDR are in
target format . */
void
read_register_stack ( memaddr , myaddr , actual_mem_addr , lval )
CORE_ADDR memaddr ;
char * myaddr ;
CORE_ADDR * actual_mem_addr ;
enum lval_type * lval ;
{
long rfb = read_register ( RFB_REGNUM ) ;
long rsp = read_register ( RSP_REGNUM ) ;
/* If we don't do this 'info register' stops in the middle. */
if ( memaddr > = rstack_high_address )
{
/* a bogus value */
static char val [ ] = { ~ 0 , ~ 0 , ~ 0 , ~ 0 } ;
/* It's in a local register, but off the end of the stack. */
int regnum = ( memaddr - rsp ) / 4 + LR0_REGNUM ;
if ( myaddr ! = NULL )
{
/* Provide bogusness */
memcpy ( myaddr , val , 4 ) ;
}
supply_register ( regnum , val ) ; /* More bogusness */
if ( lval ! = NULL )
* lval = lval_register ;
if ( actual_mem_addr ! = NULL )
* actual_mem_addr = REGISTER_BYTE ( regnum ) ;
}
/* If it's in the part of the register stack that's in real registers,
get the value from the registers . If it ' s anywhere else in memory
( e . g . in another thread ' s saved stack ) , skip this part and get
it from real live memory . */
else if ( memaddr < rfb & & memaddr > = rsp )
{
/* It's in a register. */
int regnum = ( memaddr - rsp ) / 4 + LR0_REGNUM ;
if ( regnum > LR0_REGNUM + 127 )
error ( " Attempt to read register stack out of range. " ) ;
if ( myaddr ! = NULL )
read_register_gen ( regnum , myaddr ) ;
if ( lval ! = NULL )
* lval = lval_register ;
if ( actual_mem_addr ! = NULL )
* actual_mem_addr = REGISTER_BYTE ( regnum ) ;
}
else
{
/* It's in the memory portion of the register stack. */
if ( myaddr ! = NULL )
read_memory ( memaddr , myaddr , 4 ) ;
if ( lval ! = NULL )
* lval = lval_memory ;
if ( actual_mem_addr ! = NULL )
* actual_mem_addr = memaddr ;
}
}
/* Analogous to read_memory_integer
except the length is understood to be 4. */
long
read_register_stack_integer ( memaddr , len )
CORE_ADDR memaddr ;
int len ;
{
char buf [ 4 ] ;
read_register_stack ( memaddr , buf , NULL , NULL ) ;
return extract_signed_integer ( buf , 4 ) ;
}
/* Copy 4 bytes from GDB memory at MYADDR into inferior memory
at MEMADDR and put the actual address written into in
* ACTUAL_MEM_ADDR . */
static void
write_register_stack ( memaddr , myaddr , actual_mem_addr )
CORE_ADDR memaddr ;
char * myaddr ;
CORE_ADDR * actual_mem_addr ;
{
long rfb = read_register ( RFB_REGNUM ) ;
long rsp = read_register ( RSP_REGNUM ) ;
/* If we don't do this 'info register' stops in the middle. */
if ( memaddr > = rstack_high_address )
{
/* It's in a register, but off the end of the stack. */
if ( actual_mem_addr ! = NULL )
* actual_mem_addr = 0 ;
}
else if ( memaddr < rfb )
{
/* It's in a register. */
int regnum = ( memaddr - rsp ) / 4 + LR0_REGNUM ;
if ( regnum < LR0_REGNUM | | regnum > LR0_REGNUM + 127 )
error ( " Attempt to read register stack out of range. " ) ;
if ( myaddr ! = NULL )
write_register ( regnum , * ( long * ) myaddr ) ;
if ( actual_mem_addr ! = NULL )
* actual_mem_addr = 0 ;
}
else
{
/* It's in the memory portion of the register stack. */
if ( myaddr ! = NULL )
write_memory ( memaddr , myaddr , 4 ) ;
if ( actual_mem_addr ! = NULL )
* actual_mem_addr = memaddr ;
}
}
/* Find register number REGNUM relative to FRAME and put its
( raw ) contents in * RAW_BUFFER . Set * OPTIMIZED if the variable
was optimized out ( and thus can ' t be fetched ) . If the variable
was fetched from memory , set * ADDRP to where it was fetched from ,
otherwise it was fetched from a register .
The argument RAW_BUFFER must point to aligned memory . */
void
1999-04-26 18:23:13 +00:00
a29k_get_saved_register ( raw_buffer , optimized , addrp , frame , regnum , lvalp )
1999-04-16 01:33:56 +00:00
char * raw_buffer ;
int * optimized ;
CORE_ADDR * addrp ;
struct frame_info * frame ;
int regnum ;
enum lval_type * lvalp ;
{
struct frame_info * fi ;
CORE_ADDR addr ;
enum lval_type lval ;
if ( ! target_has_registers )
error ( " No registers. " ) ;
/* Probably now redundant with the target_has_registers check. */
if ( frame = = 0 )
return ;
/* Once something has a register number, it doesn't get optimized out. */
if ( optimized ! = NULL )
* optimized = 0 ;
if ( regnum = = RSP_REGNUM )
{
if ( raw_buffer ! = NULL )
{
store_address ( raw_buffer , REGISTER_RAW_SIZE ( regnum ) , frame - > frame ) ;
}
if ( lvalp ! = NULL )
* lvalp = not_lval ;
return ;
}
else if ( regnum = = PC_REGNUM & & frame - > next ! = NULL )
{
if ( raw_buffer ! = NULL )
{
store_address ( raw_buffer , REGISTER_RAW_SIZE ( regnum ) , frame - > pc ) ;
}
/* Not sure we have to do this. */
if ( lvalp ! = NULL )
* lvalp = not_lval ;
return ;
}
else if ( regnum = = MSP_REGNUM )
{
if ( raw_buffer ! = NULL )
{
if ( frame - > next ! = NULL )
{
store_address ( raw_buffer , REGISTER_RAW_SIZE ( regnum ) ,
frame - > next - > saved_msp ) ;
}
else
read_register_gen ( MSP_REGNUM , raw_buffer ) ;
}
/* The value may have been computed, not fetched. */
if ( lvalp ! = NULL )
* lvalp = not_lval ;
return ;
}
else if ( regnum < LR0_REGNUM | | regnum > = LR0_REGNUM + 128 )
{
/* These registers are not saved over procedure calls,
so just print out the current values . */
if ( raw_buffer ! = NULL )
read_register_gen ( regnum , raw_buffer ) ;
if ( lvalp ! = NULL )
* lvalp = lval_register ;
if ( addrp ! = NULL )
* addrp = REGISTER_BYTE ( regnum ) ;
return ;
}
addr = frame - > frame + ( regnum - LR0_REGNUM ) * 4 ;
if ( raw_buffer ! = NULL )
read_register_stack ( addr , raw_buffer , & addr , & lval ) ;
if ( lvalp ! = NULL )
* lvalp = lval ;
if ( addrp ! = NULL )
* addrp = addr ;
}
/* Discard from the stack the innermost frame,
restoring all saved registers . */
void
pop_frame ( )
{
struct frame_info * frame = get_current_frame ( ) ;
CORE_ADDR rfb = read_register ( RFB_REGNUM ) ;
CORE_ADDR gr1 = frame - > frame + frame - > rsize ;
CORE_ADDR lr1 ;
CORE_ADDR original_lr0 ;
int must_fix_lr0 = 0 ;
int i ;
/* If popping a dummy frame, need to restore registers. */
if ( PC_IN_CALL_DUMMY ( read_register ( PC_REGNUM ) ,
read_register ( SP_REGNUM ) ,
FRAME_FP ( frame ) ) )
{
int lrnum = LR0_REGNUM + DUMMY_ARG / 4 ;
for ( i = 0 ; i < DUMMY_SAVE_SR128 ; + + i )
write_register ( SR_REGNUM ( i + 128 ) , read_register ( lrnum + + ) ) ;
for ( i = 0 ; i < DUMMY_SAVE_SR160 ; + + i )
write_register ( SR_REGNUM ( i + 160 ) , read_register ( lrnum + + ) ) ;
for ( i = 0 ; i < DUMMY_SAVE_GREGS ; + + i )
write_register ( RETURN_REGNUM + i , read_register ( lrnum + + ) ) ;
/* Restore the PCs and prepare to restore LR0. */
write_register ( PC_REGNUM , read_register ( lrnum + + ) ) ;
write_register ( NPC_REGNUM , read_register ( lrnum + + ) ) ;
write_register ( PC2_REGNUM , read_register ( lrnum + + ) ) ;
original_lr0 = read_register ( lrnum + + ) ;
must_fix_lr0 = 1 ;
}
/* Restore the memory stack pointer. */
write_register ( MSP_REGNUM , frame - > saved_msp ) ;
/* Restore the register stack pointer. */
write_register ( GR1_REGNUM , gr1 ) ;
/* If we popped a dummy frame, restore lr0 now that gr1 has been restored. */
if ( must_fix_lr0 )
write_register ( LR0_REGNUM , original_lr0 ) ;
/* Check whether we need to fill registers. */
lr1 = read_register ( LR0_REGNUM + 1 ) ;
if ( lr1 > rfb )
{
/* Fill. */
int num_bytes = lr1 - rfb ;
int i ;
long word ;
write_register ( RAB_REGNUM , read_register ( RAB_REGNUM ) + num_bytes ) ;
write_register ( RFB_REGNUM , lr1 ) ;
for ( i = 0 ; i < num_bytes ; i + = 4 )
{
/* Note: word is in host byte order. */
word = read_memory_integer ( rfb + i , 4 ) ;
write_register ( LR0_REGNUM + ( ( rfb - gr1 ) % 0x80 ) + i / 4 , word ) ;
}
}
flush_cached_frames ( ) ;
}
/* Push an empty stack frame, to record the current PC, etc. */
void
push_dummy_frame ( )
{
long w ;
CORE_ADDR rab , gr1 ;
CORE_ADDR msp = read_register ( MSP_REGNUM ) ;
int lrnum , i ;
CORE_ADDR original_lr0 ;
/* Read original lr0 before changing gr1. This order isn't really needed
since GDB happens to have a snapshot of all the regs and doesn ' t toss
it when gr1 is changed . But it ' s The Right Thing To Do . */
original_lr0 = read_register ( LR0_REGNUM ) ;
/* Allocate the new frame. */
gr1 = read_register ( GR1_REGNUM ) - DUMMY_FRAME_RSIZE ;
write_register ( GR1_REGNUM , gr1 ) ;
# ifdef VXWORKS_TARGET
/* We force re-reading all registers to get the new local registers set
after gr1 has been modified . This fix is due to the lack of single
register read / write operation in the RPC interface between VxGDB and
VxWorks . This really must be changed ! */
vx_read_register ( - 1 ) ;
# endif /* VXWORK_TARGET */
rab = read_register ( RAB_REGNUM ) ;
if ( gr1 < rab )
{
/* We need to spill registers. */
int num_bytes = rab - gr1 ;
CORE_ADDR rfb = read_register ( RFB_REGNUM ) ;
int i ;
long word ;
write_register ( RFB_REGNUM , rfb - num_bytes ) ;
write_register ( RAB_REGNUM , gr1 ) ;
for ( i = 0 ; i < num_bytes ; i + = 4 )
{
/* Note: word is in target byte order. */
read_register_gen ( LR0_REGNUM + i / 4 , ( char * ) & word ) ;
write_memory ( rfb - num_bytes + i , ( char * ) & word , 4 ) ;
}
}
/* There are no arguments in to the dummy frame, so we don't need
more than rsize plus the return address and lr1 . */
write_register ( LR0_REGNUM + 1 , gr1 + DUMMY_FRAME_RSIZE + 2 * 4 ) ;
/* Set the memory frame pointer. */
write_register ( LR0_REGNUM + DUMMY_FRAME_RSIZE / 4 - 1 , msp ) ;
/* Allocate arg_slop. */
write_register ( MSP_REGNUM , msp - 16 * 4 ) ;
/* Save registers. */
lrnum = LR0_REGNUM + DUMMY_ARG / 4 ;
for ( i = 0 ; i < DUMMY_SAVE_SR128 ; + + i )
write_register ( lrnum + + , read_register ( SR_REGNUM ( i + 128 ) ) ) ;
for ( i = 0 ; i < DUMMY_SAVE_SR160 ; + + i )
write_register ( lrnum + + , read_register ( SR_REGNUM ( i + 160 ) ) ) ;
for ( i = 0 ; i < DUMMY_SAVE_GREGS ; + + i )
write_register ( lrnum + + , read_register ( RETURN_REGNUM + i ) ) ;
/* Save the PCs and LR0. */
write_register ( lrnum + + , read_register ( PC_REGNUM ) ) ;
write_register ( lrnum + + , read_register ( NPC_REGNUM ) ) ;
write_register ( lrnum + + , read_register ( PC2_REGNUM ) ) ;
/* Why are we saving LR0? What would clobber it? (the dummy frame should
be below it on the register stack , no ? ) . */
write_register ( lrnum + + , original_lr0 ) ;
}
/*
This routine takes three arguments and makes the cached frames look
as if these arguments defined a frame on the cache . This allows the
rest of ` info frame ' to extract the important arguments without much
difficulty . Since an individual frame on the 29 K is determined by
three values ( FP , PC , and MSP ) , we really need all three to do a
good job . */
struct frame_info *
setup_arbitrary_frame ( argc , argv )
int argc ;
CORE_ADDR * argv ;
{
struct frame_info * frame ;
if ( argc ! = 3 )
error ( " AMD 29k frame specifications require three arguments: rsp pc msp " ) ;
frame = create_new_frame ( argv [ 0 ] , argv [ 1 ] ) ;
if ( ! frame )
fatal ( " internal: create_new_frame returned invalid frame id " ) ;
/* Creating a new frame munges the `frame' value from the current
GR1 , so we restore it again here . FIXME , untangle all this
29 K frame stuff . . . */
frame - > frame = argv [ 0 ] ;
/* Our MSP is in argv[2]. It'd be intelligent if we could just
save this value in the FRAME . But the way it ' s set up ( FIXME ) ,
we must save our caller ' s MSP . We compute that by adding our
memory stack frame size to our MSP . */
frame - > saved_msp = argv [ 2 ] + frame - > msize ;
return frame ;
}
int
gdb_print_insn_a29k ( memaddr , info )
bfd_vma memaddr ;
disassemble_info * info ;
{
if ( TARGET_BYTE_ORDER = = BIG_ENDIAN )
return print_insn_big_a29k ( memaddr , info ) ;
else
return print_insn_little_a29k ( memaddr , info ) ;
}
enum a29k_processor_types processor_type = a29k_unknown ;
void
a29k_get_processor_type ( )
{
unsigned int cfg_reg = ( unsigned int ) read_register ( CFG_REGNUM ) ;
/* Most of these don't have freeze mode. */
processor_type = a29k_no_freeze_mode ;
switch ( ( cfg_reg > > 28 ) & 0xf )
{
case 0 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am29000 " ) ;
break ;
case 1 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am29005 " ) ;
break ;
case 2 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am29050 " ) ;
processor_type = a29k_freeze_mode ;
break ;
case 3 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am29035 " ) ;
break ;
case 4 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am29030 " ) ;
break ;
case 5 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am2920* " ) ;
break ;
case 6 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am2924* " ) ;
break ;
case 7 :
fprintf_filtered ( gdb_stderr , " Remote debugging an Am29040 " ) ;
break ;
default :
fprintf_filtered ( gdb_stderr , " Remote debugging an unknown Am29k \n " ) ;
/* Don't bother to print the revision. */
return ;
}
fprintf_filtered ( gdb_stderr , " revision %c \n " , ' A ' + ( ( cfg_reg > > 24 ) & 0x0f ) ) ;
}
# ifdef GET_LONGJMP_TARGET
/* Figure out where the longjmp will land. We expect that we have just entered
longjmp and haven ' t yet setup the stack frame , so the args are still in the
output regs . lr2 ( LR2_REGNUM ) points at the jmp_buf structure from which we
extract the pc ( JB_PC ) that we will land at . The pc is copied into ADDR .
This routine returns true on success */
int
get_longjmp_target ( pc )
CORE_ADDR * pc ;
{
CORE_ADDR jb_addr ;
char buf [ sizeof ( CORE_ADDR ) ] ;
jb_addr = read_register ( LR2_REGNUM ) ;
if ( target_read_memory ( jb_addr + JB_PC * JB_ELEMENT_SIZE , ( char * ) buf ,
sizeof ( CORE_ADDR ) ) )
return 0 ;
* pc = extract_address ( ( PTR ) buf , sizeof ( CORE_ADDR ) ) ;
return 1 ;
}
# endif /* GET_LONGJMP_TARGET */
void
_initialize_a29k_tdep ( )
{
extern CORE_ADDR text_end ;
tm_print_insn = gdb_print_insn_a29k ;
/* FIXME, there should be a way to make a CORE_ADDR variable settable. */
add_show_from_set
( add_set_cmd ( " rstack_high_address " , class_support , var_uinteger ,
( char * ) & rstack_high_address ,
" Set top address in memory of the register stack. \n \
Attempts to access registers saved above this address will be ignored \ n \
or will produce the value - 1. " , &setlist),
& showlist ) ;
/* FIXME, there should be a way to make a CORE_ADDR variable settable. */
add_show_from_set
( add_set_cmd ( " call_scratch_address " , class_support , var_uinteger ,
( char * ) & text_end ,
" Set address in memory where small amounts of RAM can be used \n \
when making function calls into the inferior . " , &setlist),
& showlist ) ;
}