1999-04-16 01:33:56 +00:00
/* Target-machine dependent code for the Intel 960
Copyright 1991 , 1992 , 1993 , 1994 , 1995 Free Software Foundation , Inc .
Contributed by Intel Corporation .
examine_prologue and other parts contributed by Wind River Systems .
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 "symtab.h"
# include "value.h"
# include "frame.h"
# include "floatformat.h"
# include "target.h"
# include "gdbcore.h"
static CORE_ADDR next_insn PARAMS ( ( CORE_ADDR memaddr ,
unsigned int * pword1 ,
unsigned int * pword2 ) ) ;
/* Does the specified function use the "struct returning" convention
or the " value returning " convention ? The " value returning " convention
almost invariably returns the entire value in registers . The
" struct returning " convention often returns the entire value in
memory , and passes a pointer ( out of or into the function ) saying
where the value ( is or should go ) .
Since this sometimes depends on whether it was compiled with GCC ,
this is also an argument . This is used in call_function to build a
stack , and in value_being_returned to print return values .
On i960 , a structure is returned in registers g0 - g3 , if it will fit .
If it ' s more than 16 bytes long , g13 pointed to it on entry . */
int
i960_use_struct_convention ( gcc_p , type )
int gcc_p ;
struct type * type ;
{
return ( TYPE_LENGTH ( type ) > 16 ) ;
}
/* gdb960 is always running on a non-960 host. Check its characteristics.
This routine must be called as part of gdb initialization . */
static void
check_host ( )
{
int i ;
static struct typestruct {
int hostsize ; /* Size of type on host */
int i960size ; /* Size of type on i960 */
char * typename ; /* Name of type, for error msg */
} types [ ] = {
{ sizeof ( short ) , 2 , " short " } ,
{ sizeof ( int ) , 4 , " int " } ,
{ sizeof ( long ) , 4 , " long " } ,
{ sizeof ( float ) , 4 , " float " } ,
{ sizeof ( double ) , 8 , " double " } ,
{ sizeof ( char * ) , 4 , " pointer " } ,
} ;
# define TYPELEN (sizeof(types) / sizeof(struct typestruct))
/* Make sure that host type sizes are same as i960
*/
for ( i = 0 ; i < TYPELEN ; i + + ) {
if ( types [ i ] . hostsize ! = types [ i ] . i960size ) {
printf_unfiltered ( " sizeof(%s) != %d: PROCEED AT YOUR OWN RISK! \n " ,
types [ i ] . typename , types [ i ] . i960size ) ;
}
}
}
/* Examine an i960 function prologue, recording the addresses at which
registers are saved explicitly by the prologue code , and returning
the address of the first instruction after the prologue ( but not
after the instruction at address LIMIT , as explained below ) .
LIMIT places an upper bound on addresses of the instructions to be
examined . If the prologue code scan reaches LIMIT , the scan is
aborted and LIMIT is returned . This is used , when examining the
prologue for the current frame , to keep examine_prologue ( ) from
claiming that a given register has been saved when in fact the
instruction that saves it has not yet been executed . LIMIT is used
at other times to stop the scan when we hit code after the true
function prologue ( e . g . for the first source line ) which might
otherwise be mistaken for function prologue .
The format of the function prologue matched by this routine is
derived from examination of the source to gcc960 1.21 , particularly
the routine i960_function_prologue ( ) . A " regular expression " for
the function prologue is given below :
( lda LRn , g14
mov g14 , g [ 0 - 7 ]
( mov 0 , g14 ) | ( lda 0 , g14 ) ) ?
( mov [ qtl ] ? g [ 0 - 15 ] , r [ 4 - 15 ] ) *
( ( addo [ 1 - 31 ] , sp , sp ) | ( lda n ( sp ) , sp ) ) ?
( st [ qtl ] ? g [ 0 - 15 ] , n ( fp ) ) *
( cmpobne 0 , g14 , LFn
mov sp , g14
lda 0x30 ( sp ) , sp
LFn : stq g0 , ( g14 )
stq g4 , 0x10 ( g14 )
stq g8 , 0x20 ( g14 ) ) ?
( st g14 , n ( fp ) ) ?
( mov g13 , r [ 4 - 15 ] ) ?
*/
/* Macros for extracting fields from i960 instructions. */
# define BITMASK(pos, width) (((0x1 << (width)) - 1) << (pos))
# define EXTRACT_FIELD(val, pos, width) ((val) >> (pos) & BITMASK (0, width))
# define REG_SRC1(insn) EXTRACT_FIELD (insn, 0, 5)
# define REG_SRC2(insn) EXTRACT_FIELD (insn, 14, 5)
# define REG_SRCDST(insn) EXTRACT_FIELD (insn, 19, 5)
# define MEM_SRCDST(insn) EXTRACT_FIELD (insn, 19, 5)
# define MEMA_OFFSET(insn) EXTRACT_FIELD (insn, 0, 12)
/* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or
is not the address of a valid instruction , the address of the next
instruction beyond ADDR otherwise . * PWORD1 receives the first word
of the instruction , and ( for two - word instructions ) , * PWORD2 receives
the second . */
# define NEXT_PROLOGUE_INSN(addr, lim, pword1, pword2) \
( ( ( addr ) < ( lim ) ) ? next_insn ( addr , pword1 , pword2 ) : 0 )
static CORE_ADDR
examine_prologue ( ip , limit , frame_addr , fsr )
register CORE_ADDR ip ;
register CORE_ADDR limit ;
CORE_ADDR frame_addr ;
struct frame_saved_regs * fsr ;
{
register CORE_ADDR next_ip ;
register int src , dst ;
register unsigned int * pcode ;
unsigned int insn1 , insn2 ;
int size ;
int within_leaf_prologue ;
CORE_ADDR save_addr ;
static unsigned int varargs_prologue_code [ ] =
{
0x3507a00c , /* cmpobne 0x0, g14, LFn */
0x5cf01601 , /* mov sp, g14 */
0x8c086030 , /* lda 0x30(sp), sp */
0xb2879000 , /* LFn: stq g0, (g14) */
0xb2a7a010 , /* stq g4, 0x10(g14) */
0xb2c7a020 /* stq g8, 0x20(g14) */
} ;
/* Accept a leaf procedure prologue code fragment if present.
Note that ip might point to either the leaf or non - leaf
entry point ; we look for the non - leaf entry point first : */
within_leaf_prologue = 0 ;
if ( ( next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) )
& & ( ( insn1 & 0xfffff000 ) = = 0x8cf00000 /* lda LRx, g14 (MEMA) */
| | ( insn1 & 0xfffffc60 ) = = 0x8cf03000 ) ) /* lda LRx, g14 (MEMB) */
{
within_leaf_prologue = 1 ;
next_ip = NEXT_PROLOGUE_INSN ( next_ip , limit , & insn1 , & insn2 ) ;
}
/* Now look for the prologue code at a leaf entry point: */
if ( next_ip
& & ( insn1 & 0xff87ffff ) = = 0x5c80161e /* mov g14, gx */
& & REG_SRCDST ( insn1 ) < = G0_REGNUM + 7 )
{
within_leaf_prologue = 1 ;
if ( ( next_ip = NEXT_PROLOGUE_INSN ( next_ip , limit , & insn1 , & insn2 ) )
& & ( insn1 = = 0x8cf00000 /* lda 0, g14 */
| | insn1 = = 0x5cf01e00 ) ) /* mov 0, g14 */
{
ip = next_ip ;
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
within_leaf_prologue = 0 ;
}
}
/* If something that looks like the beginning of a leaf prologue
has been seen , but the remainder of the prologue is missing , bail .
We don ' t know what we ' ve got . */
if ( within_leaf_prologue )
return ( ip ) ;
/* Accept zero or more instances of "mov[qtl]? gx, ry", where y >= 4.
This may cause us to mistake the moving of a register
parameter to a local register for the saving of a callee - saved
register , but that can ' t be helped , since with the
" -fcall-saved " flag , any register can be made callee - saved . */
while ( next_ip
& & ( insn1 & 0xfc802fb0 ) = = 0x5c000610
& & ( dst = REG_SRCDST ( insn1 ) ) > = ( R0_REGNUM + 4 ) )
{
src = REG_SRC1 ( insn1 ) ;
size = EXTRACT_FIELD ( insn1 , 24 , 2 ) + 1 ;
save_addr = frame_addr + ( ( dst - R0_REGNUM ) * 4 ) ;
while ( size - - )
{
fsr - > regs [ src + + ] = save_addr ;
save_addr + = 4 ;
}
ip = next_ip ;
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
}
/* Accept an optional "addo n, sp, sp" or "lda n(sp), sp". */
if ( next_ip & &
( ( insn1 & 0xffffffe0 ) = = 0x59084800 /* addo n, sp, sp */
| | ( insn1 & 0xfffff000 ) = = 0x8c086000 /* lda n(sp), sp (MEMA) */
| | ( insn1 & 0xfffffc60 ) = = 0x8c087400 ) ) /* lda n(sp), sp (MEMB) */
{
ip = next_ip ;
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
}
/* Accept zero or more instances of "st[qtl]? gx, n(fp)".
This may cause us to mistake the copying of a register
parameter to the frame for the saving of a callee - saved
register , but that can ' t be helped , since with the
" -fcall-saved " flag , any register can be made callee - saved .
We can , however , refuse to accept a save of register g14 ,
since that is matched explicitly below . */
while ( next_ip & &
( ( insn1 & 0xf787f000 ) = = 0x9287e000 /* stl? gx, n(fp) (MEMA) */
| | ( insn1 & 0xf787fc60 ) = = 0x9287f400 /* stl? gx, n(fp) (MEMB) */
| | ( insn1 & 0xef87f000 ) = = 0xa287e000 /* st[tq] gx, n(fp) (MEMA) */
| | ( insn1 & 0xef87fc60 ) = = 0xa287f400 ) /* st[tq] gx, n(fp) (MEMB) */
& & ( ( src = MEM_SRCDST ( insn1 ) ) ! = G14_REGNUM ) )
{
save_addr = frame_addr + ( ( insn1 & BITMASK ( 12 , 1 ) )
? insn2 : MEMA_OFFSET ( insn1 ) ) ;
size = ( insn1 & BITMASK ( 29 , 1 ) ) ? ( ( insn1 & BITMASK ( 28 , 1 ) ) ? 4 : 3 )
: ( ( insn1 & BITMASK ( 27 , 1 ) ) ? 2 : 1 ) ;
while ( size - - )
{
fsr - > regs [ src + + ] = save_addr ;
save_addr + = 4 ;
}
ip = next_ip ;
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
}
/* Accept the varargs prologue code if present. */
size = sizeof ( varargs_prologue_code ) / sizeof ( int ) ;
pcode = varargs_prologue_code ;
while ( size - - & & next_ip & & * pcode + + = = insn1 )
{
ip = next_ip ;
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
}
/* Accept an optional "st g14, n(fp)". */
if ( next_ip & &
( ( insn1 & 0xfffff000 ) = = 0x92f7e000 /* st g14, n(fp) (MEMA) */
| | ( insn1 & 0xfffffc60 ) = = 0x92f7f400 ) ) /* st g14, n(fp) (MEMB) */
{
fsr - > regs [ G14_REGNUM ] = frame_addr + ( ( insn1 & BITMASK ( 12 , 1 ) )
? insn2 : MEMA_OFFSET ( insn1 ) ) ;
ip = next_ip ;
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
}
/* Accept zero or one instance of "mov g13, ry", where y >= 4.
This is saving the address where a struct should be returned . */
if ( next_ip
& & ( insn1 & 0xff802fbf ) = = 0x5c00061d
& & ( dst = REG_SRCDST ( insn1 ) ) > = ( R0_REGNUM + 4 ) )
{
save_addr = frame_addr + ( ( dst - R0_REGNUM ) * 4 ) ;
fsr - > regs [ G0_REGNUM + 13 ] = save_addr ;
ip = next_ip ;
#if 0 /* We'll need this once there is a subsequent instruction examined. */
next_ip = NEXT_PROLOGUE_INSN ( ip , limit , & insn1 , & insn2 ) ;
# endif
}
return ( ip ) ;
}
/* Given an ip value corresponding to the start of a function,
return the ip of the first instruction after the function
prologue . */
CORE_ADDR
1999-05-05 14:42:03 +00:00
i960_skip_prologue ( ip )
1999-04-16 01:33:56 +00:00
CORE_ADDR ( ip ) ;
{
struct frame_saved_regs saved_regs_dummy ;
struct symtab_and_line sal ;
CORE_ADDR limit ;
sal = find_pc_line ( ip , 0 ) ;
limit = ( sal . end ) ? sal . end : 0xffffffff ;
return ( examine_prologue ( ip , limit , ( CORE_ADDR ) 0 , & saved_regs_dummy ) ) ;
}
/* Put here the code to store, into a struct frame_saved_regs,
the addresses of the saved registers of frame described by FRAME_INFO .
This includes special registers such as pc and fp saved in special
ways in the stack frame . sp is even more special :
the address we return for it IS the sp for the next frame .
We cache the result of doing this in the frame_obstack , since it is
fairly expensive . */
void
frame_find_saved_regs ( fi , fsr )
struct frame_info * fi ;
struct frame_saved_regs * fsr ;
{
register CORE_ADDR next_addr ;
register CORE_ADDR * saved_regs ;
register int regnum ;
register struct frame_saved_regs * cache_fsr ;
CORE_ADDR ip ;
struct symtab_and_line sal ;
CORE_ADDR limit ;
if ( ! fi - > fsr )
{
cache_fsr = ( struct frame_saved_regs * )
frame_obstack_alloc ( sizeof ( struct frame_saved_regs ) ) ;
memset ( cache_fsr , ' \0 ' , sizeof ( struct frame_saved_regs ) ) ;
fi - > fsr = cache_fsr ;
/* Find the start and end of the function prologue. If the PC
is in the function prologue , we only consider the part that
has executed already . */
ip = get_pc_function_start ( fi - > pc ) ;
sal = find_pc_line ( ip , 0 ) ;
limit = ( sal . end & & sal . end < fi - > pc ) ? sal . end : fi - > pc ;
examine_prologue ( ip , limit , fi - > frame , cache_fsr ) ;
/* Record the addresses at which the local registers are saved.
Strictly speaking , we should only do this for non - leaf procedures ,
but no one will ever look at these values if it is a leaf procedure ,
since local registers are always caller - saved . */
next_addr = ( CORE_ADDR ) fi - > frame ;
saved_regs = cache_fsr - > regs ;
for ( regnum = R0_REGNUM ; regnum < = R15_REGNUM ; regnum + + )
{
* saved_regs + + = next_addr ;
next_addr + = 4 ;
}
cache_fsr - > regs [ FP_REGNUM ] = cache_fsr - > regs [ PFP_REGNUM ] ;
}
* fsr = * fi - > fsr ;
/* Fetch the value of the sp from memory every time, since it
is conceivable that it has changed since the cache was flushed .
This unfortunately undoes much of the savings from caching the
saved register values . I suggest adding an argument to
get_frame_saved_regs ( ) specifying the register number we ' re
interested in ( or - 1 for all registers ) . This would be passed
through to FRAME_FIND_SAVED_REGS ( ) , permitting more efficient
computation of saved register addresses ( e . g . , on the i960 ,
we don ' t have to examine the prologue to find local registers ) .
- - markf @ wrs . com
FIXME , we don ' t need to refetch this , since the cache is cleared
every time the child process is restarted . If GDB itself
modifies SP , it has to clear the cache by hand ( does it ? ) . - gnu */
fsr - > regs [ SP_REGNUM ] = read_memory_integer ( fsr - > regs [ SP_REGNUM ] , 4 ) ;
}
/* Return the address of the argument block for the frame
described by FI . Returns 0 if the address is unknown . */
CORE_ADDR
frame_args_address ( fi , must_be_correct )
struct frame_info * fi ;
{
struct frame_saved_regs fsr ;
CORE_ADDR ap ;
/* If g14 was saved in the frame by the function prologue code, return
the saved value . If the frame is current and we are being sloppy ,
return the value of g14 . Otherwise , return zero . */
get_frame_saved_regs ( fi , & fsr ) ;
if ( fsr . regs [ G14_REGNUM ] )
ap = read_memory_integer ( fsr . regs [ G14_REGNUM ] , 4 ) ;
else
{
if ( must_be_correct )
return 0 ; /* Don't cache this result */
if ( get_next_frame ( fi ) )
ap = 0 ;
else
ap = read_register ( G14_REGNUM ) ;
if ( ap = = 0 )
ap = fi - > frame ;
}
fi - > arg_pointer = ap ; /* Cache it for next time */
return ap ;
}
/* Return the address of the return struct for the frame
described by FI . Returns 0 if the address is unknown . */
CORE_ADDR
frame_struct_result_address ( fi )
struct frame_info * fi ;
{
struct frame_saved_regs fsr ;
CORE_ADDR ap ;
/* If the frame is non-current, check to see if g14 was saved in the
frame by the function prologue code ; return the saved value if so ,
zero otherwise . If the frame is current , return the value of g14 .
FIXME , shouldn ' t this use the saved value as long as we are past
the function prologue , and only use the current value if we have
no saved value and are at TOS ? - - gnu @ cygnus . com */
if ( get_next_frame ( fi ) )
{
get_frame_saved_regs ( fi , & fsr ) ;
if ( fsr . regs [ G13_REGNUM ] )
ap = read_memory_integer ( fsr . regs [ G13_REGNUM ] , 4 ) ;
else
ap = 0 ;
}
else
ap = read_register ( G13_REGNUM ) ;
return ap ;
}
/* Return address to which the currently executing leafproc will return,
or 0 if ip is not in a leafproc ( or if we can ' t tell if it is ) .
Do this by finding the starting address of the routine in which ip lies .
If the instruction there is " mov g14, gx " ( where x is in [ 0 , 7 ] ) , this
is a leafproc and the return address is in register gx . Well , this is
true unless the return address points at a RET instruction in the current
procedure , which indicates that we have a ' dual entry ' routine that
has been entered through the CALL entry point . */
CORE_ADDR
leafproc_return ( ip )
CORE_ADDR ip ; /* ip from currently executing function */
{
register struct minimal_symbol * msymbol ;
char * p ;
int dst ;
unsigned int insn1 , insn2 ;
CORE_ADDR return_addr ;
if ( ( msymbol = lookup_minimal_symbol_by_pc ( ip ) ) ! = NULL )
{
if ( ( p = strchr ( SYMBOL_NAME ( msymbol ) , ' . ' ) ) & & STREQ ( p , " .lf " ) )
{
if ( next_insn ( SYMBOL_VALUE_ADDRESS ( msymbol ) , & insn1 , & insn2 )
& & ( insn1 & 0xff87ffff ) = = 0x5c80161e /* mov g14, gx */
& & ( dst = REG_SRCDST ( insn1 ) ) < = G0_REGNUM + 7 )
{
/* Get the return address. If the "mov g14, gx"
instruction hasn ' t been executed yet , read
the return address from g14 ; otherwise , read it
from the register into which g14 was moved . */
return_addr =
read_register ( ( ip = = SYMBOL_VALUE_ADDRESS ( msymbol ) )
? G14_REGNUM : dst ) ;
/* We know we are in a leaf procedure, but we don't know
whether the caller actually did a " bal " to the " .lf "
entry point , or a normal " call " to the non - leaf entry
point one instruction before . In the latter case , the
return address will be the address of a " ret "
instruction within the procedure itself . We test for
this below . */
if ( ! next_insn ( return_addr , & insn1 , & insn2 )
| | ( insn1 & 0xff000000 ) ! = 0xa000000 /* ret */
| | lookup_minimal_symbol_by_pc ( return_addr ) ! = msymbol )
return ( return_addr ) ;
}
}
}
return ( 0 ) ;
}
/* Immediately after a function call, return the saved pc.
Can ' t go through the frames for this because on some machines
the new frame is not set up until the new function executes
some instructions .
On the i960 , the frame * is * set up immediately after the call ,
unless the function is a leaf procedure . */
CORE_ADDR
saved_pc_after_call ( frame )
struct frame_info * frame ;
{
CORE_ADDR saved_pc ;
saved_pc = leafproc_return ( get_frame_pc ( frame ) ) ;
if ( ! saved_pc )
saved_pc = FRAME_SAVED_PC ( frame ) ;
return saved_pc ;
}
/* Discard from the stack the innermost frame,
restoring all saved registers . */
void
pop_frame ( )
{
register struct frame_info * current_fi , * prev_fi ;
register int i ;
CORE_ADDR save_addr ;
CORE_ADDR leaf_return_addr ;
struct frame_saved_regs fsr ;
char local_regs_buf [ 16 * 4 ] ;
current_fi = get_current_frame ( ) ;
/* First, undo what the hardware does when we return.
If this is a non - leaf procedure , restore local registers from
the save area in the calling frame . Otherwise , load the return
address obtained from leafproc_return ( ) into the rip . */
leaf_return_addr = leafproc_return ( current_fi - > pc ) ;
if ( ! leaf_return_addr )
{
/* Non-leaf procedure. Restore local registers, incl IP. */
prev_fi = get_prev_frame ( current_fi ) ;
read_memory ( prev_fi - > frame , local_regs_buf , sizeof ( local_regs_buf ) ) ;
write_register_bytes ( REGISTER_BYTE ( R0_REGNUM ) , local_regs_buf ,
sizeof ( local_regs_buf ) ) ;
/* Restore frame pointer. */
write_register ( FP_REGNUM , prev_fi - > frame ) ;
}
else
{
/* Leaf procedure. Just restore the return address into the IP. */
write_register ( RIP_REGNUM , leaf_return_addr ) ;
}
/* Now restore any global regs that the current function had saved. */
get_frame_saved_regs ( current_fi , & fsr ) ;
for ( i = G0_REGNUM ; i < G14_REGNUM ; i + + )
{
1999-04-26 18:23:13 +00:00
save_addr = fsr . regs [ i ] ;
if ( save_addr ! = 0 )
1999-04-16 01:33:56 +00:00
write_register ( i , read_memory_integer ( save_addr , 4 ) ) ;
}
/* Flush the frame cache, create a frame for the new innermost frame,
and make it the current frame . */
flush_cached_frames ( ) ;
}
/* Given a 960 stop code (fault or trace), return the signal which
corresponds . */
enum target_signal
i960_fault_to_signal ( fault )
int fault ;
{
switch ( fault )
{
case 0 : return TARGET_SIGNAL_BUS ; /* parallel fault */
case 1 : return TARGET_SIGNAL_UNKNOWN ;
case 2 : return TARGET_SIGNAL_ILL ; /* operation fault */
case 3 : return TARGET_SIGNAL_FPE ; /* arithmetic fault */
case 4 : return TARGET_SIGNAL_FPE ; /* floating point fault */
/* constraint fault. This appears not to distinguish between
a range constraint fault ( which should be SIGFPE ) and a privileged
fault ( which should be SIGILL ) . */
case 5 : return TARGET_SIGNAL_ILL ;
case 6 : return TARGET_SIGNAL_SEGV ; /* virtual memory fault */
/* protection fault. This is for an out-of-range argument to
" calls " . I guess it also could be SIGILL . */
case 7 : return TARGET_SIGNAL_SEGV ;
case 8 : return TARGET_SIGNAL_BUS ; /* machine fault */
case 9 : return TARGET_SIGNAL_BUS ; /* structural fault */
case 0xa : return TARGET_SIGNAL_ILL ; /* type fault */
case 0xb : return TARGET_SIGNAL_UNKNOWN ; /* reserved fault */
case 0xc : return TARGET_SIGNAL_BUS ; /* process fault */
case 0xd : return TARGET_SIGNAL_SEGV ; /* descriptor fault */
case 0xe : return TARGET_SIGNAL_BUS ; /* event fault */
case 0xf : return TARGET_SIGNAL_UNKNOWN ; /* reserved fault */
case 0x10 : return TARGET_SIGNAL_TRAP ; /* single-step trace */
case 0x11 : return TARGET_SIGNAL_TRAP ; /* branch trace */
case 0x12 : return TARGET_SIGNAL_TRAP ; /* call trace */
case 0x13 : return TARGET_SIGNAL_TRAP ; /* return trace */
case 0x14 : return TARGET_SIGNAL_TRAP ; /* pre-return trace */
case 0x15 : return TARGET_SIGNAL_TRAP ; /* supervisor call trace */
case 0x16 : return TARGET_SIGNAL_TRAP ; /* breakpoint trace */
default : return TARGET_SIGNAL_UNKNOWN ;
}
}
/****************************************/
/* MEM format */
/****************************************/
struct tabent {
char * name ;
char numops ;
} ;
static int /* returns instruction length: 4 or 8 */
mem ( memaddr , word1 , word2 , noprint )
unsigned long memaddr ;
unsigned long word1 , word2 ;
int noprint ; /* If TRUE, return instruction length, but
don ' t output any text . */
{
int i , j ;
int len ;
int mode ;
int offset ;
const char * reg1 , * reg2 , * reg3 ;
/* This lookup table is too sparse to make it worth typing in, but not
* so large as to make a sparse array necessary . We allocate the
* table at runtime , initialize all entries to empty , and copy the
* real ones in from an initialization table .
*
* NOTE : In this table , the meaning of ' numops ' is :
* 1 : single operand
* 2 : 2 operands , load instruction
* - 2 : 2 operands , store instruction
*/
static struct tabent * mem_tab = NULL ;
/* Opcodes of 0x8X, 9X, aX, bX, and cX must be in the table. */
# define MEM_MIN 0x80
# define MEM_MAX 0xcf
# define MEM_SIZ ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent))
static struct { int opcode ; char * name ; char numops ; } mem_init [ ] = {
0x80 , " ldob " , 2 ,
0x82 , " stob " , - 2 ,
0x84 , " bx " , 1 ,
0x85 , " balx " , 2 ,
0x86 , " callx " , 1 ,
0x88 , " ldos " , 2 ,
0x8a , " stos " , - 2 ,
0x8c , " lda " , 2 ,
0x90 , " ld " , 2 ,
0x92 , " st " , - 2 ,
0x98 , " ldl " , 2 ,
0x9a , " stl " , - 2 ,
0xa0 , " ldt " , 2 ,
0xa2 , " stt " , - 2 ,
0xb0 , " ldq " , 2 ,
0xb2 , " stq " , - 2 ,
0xc0 , " ldib " , 2 ,
0xc2 , " stib " , - 2 ,
0xc8 , " ldis " , 2 ,
0xca , " stis " , - 2 ,
0 , NULL , 0
} ;
if ( mem_tab = = NULL ) {
mem_tab = ( struct tabent * ) xmalloc ( MEM_SIZ ) ;
memset ( mem_tab , ' \0 ' , MEM_SIZ ) ;
for ( i = 0 ; mem_init [ i ] . opcode ! = 0 ; i + + ) {
j = mem_init [ i ] . opcode - MEM_MIN ;
mem_tab [ j ] . name = mem_init [ i ] . name ;
mem_tab [ j ] . numops = mem_init [ i ] . numops ;
}
}
i = ( ( word1 > > 24 ) & 0xff ) - MEM_MIN ;
mode = ( word1 > > 10 ) & 0xf ;
if ( ( mem_tab [ i ] . name ! = NULL ) /* Valid instruction */
& & ( ( mode = = 5 ) | | ( mode > = 12 ) ) ) { /* With 32-bit displacement */
len = 8 ;
} else {
len = 4 ;
}
if ( noprint ) {
return len ;
}
abort ( ) ;
}
/* Read the i960 instruction at 'memaddr' and return the address of
the next instruction after that , or 0 if ' memaddr ' is not the
address of a valid instruction . The first word of the instruction
is stored at ' pword1 ' , and the second word , if any , is stored at
' pword2 ' . */
static CORE_ADDR
next_insn ( memaddr , pword1 , pword2 )
unsigned int * pword1 , * pword2 ;
CORE_ADDR memaddr ;
{
int len ;
char buf [ 8 ] ;
/* Read the two (potential) words of the instruction at once,
to eliminate the overhead of two calls to read_memory ( ) .
FIXME : Loses if the first one is readable but the second is not
( e . g . last word of the segment ) . */
read_memory ( memaddr , buf , 8 ) ;
* pword1 = extract_unsigned_integer ( buf , 4 ) ;
* pword2 = extract_unsigned_integer ( buf + 4 , 4 ) ;
/* Divide instruction set into classes based on high 4 bits of opcode*/
switch ( ( * pword1 > > 28 ) & 0xf )
{
case 0x0 :
case 0x1 : /* ctrl */
case 0x2 :
case 0x3 : /* cobr */
case 0x5 :
case 0x6 :
case 0x7 : /* reg */
len = 4 ;
break ;
case 0x8 :
case 0x9 :
case 0xa :
case 0xb :
case 0xc :
len = mem ( memaddr , * pword1 , * pword2 , 1 ) ;
break ;
default : /* invalid instruction */
len = 0 ;
break ;
}
if ( len )
return memaddr + len ;
else
return 0 ;
}
/* 'start_frame' is a variable in the MON960 runtime startup routine
that contains the frame pointer of the ' start ' routine ( the routine
that calls ' main ' ) . By reading its contents out of remote memory ,
we can tell where the frame chain ends : backtraces should halt before
they display this frame . */
int
mon960_frame_chain_valid ( chain , curframe )
CORE_ADDR chain ;
struct frame_info * curframe ;
{
struct symbol * sym ;
struct minimal_symbol * msymbol ;
/* crtmon960.o is an assembler module that is assumed to be linked
* first in an i80960 executable . It contains the true entry point ;
* it performs startup up initialization and then calls ' main ' .
*
* ' sf ' is the name of a variable in crtmon960 . o that is set
* during startup to the address of the first frame .
*
* ' a ' is the address of that variable in 80960 memory .
*/
static char sf [ ] = " start_frame " ;
CORE_ADDR a ;
chain & = ~ 0x3f ; /* Zero low 6 bits because previous frame pointers
contain return status info in them . */
if ( chain = = 0 ) {
return 0 ;
}
sym = lookup_symbol ( sf , 0 , VAR_NAMESPACE , ( int * ) NULL ,
( struct symtab * * ) NULL ) ;
if ( sym ! = 0 ) {
a = SYMBOL_VALUE ( sym ) ;
} else {
msymbol = lookup_minimal_symbol ( sf , NULL , NULL ) ;
if ( msymbol = = NULL )
return 0 ;
a = SYMBOL_VALUE_ADDRESS ( msymbol ) ;
}
return ( chain ! = read_memory_integer ( a , 4 ) ) ;
}
void
_initialize_i960_tdep ( )
{
check_host ( ) ;
tm_print_insn = print_insn_i960 ;
}