1999-04-16 01:33:56 +00:00
/* Convex stuff for GDB.
Copyright ( C ) 1990 , 1991 , 1996 Free Software Foundation , Inc .
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 "command.h"
# include "symtab.h"
# include "value.h"
# include "frame.h"
# include "inferior.h"
# include "wait.h"
# include <signal.h>
# include <fcntl.h>
# include "gdbcore.h"
# include <sys/param.h>
# include <sys/dir.h>
# include <sys/user.h>
# include <sys/ioctl.h>
# include <sys/pcntl.h>
# include <sys/thread.h>
# include <sys/proc.h>
# include <sys/file.h>
# include "gdb_stat.h"
# include <sys/mman.h>
# include "gdbcmd.h"
1999-05-05 14:42:03 +00:00
CORE_ADDR
convex_skip_prologue ( pc )
CORE_ADDR pc ;
{
int op , ix ;
op = read_memory_integer ( pc , 2 ) ;
if ( ( op & 0xffc7 ) = = 0x5ac0 )
pc + = 2 ;
else if ( op = = 0x1580 )
pc + = 4 ;
else if ( op = = 0x15c0 )
pc + = 6 ;
if ( ( read_memory_integer ( pc , 2 ) & 0xfff8 ) = = 0x7c40
& & ( read_memory_integer ( pc + 2 , 2 ) & 0xfff8 ) = = 0x1240
& & ( read_memory_integer ( pc + 8 , 2 ) & 0xfff8 ) = = 0x7c48 )
pc + = 10 ;
if ( read_memory_integer ( pc , 2 ) = = 0x1240 )
pc + = 6 ;
for ( ; ; )
{
op = read_memory_integer ( pc , 2 ) ;
ix = ( op > > 3 ) & 7 ;
if ( ix ! = 6 )
break ;
if ( ( op & 0xfcc0 ) = = 0x3000 )
pc + = 4 ;
else if ( ( op & 0xfcc0 ) = = 0x3040 )
pc + = 6 ;
else if ( ( op & 0xfcc0 ) = = 0x2800 )
pc + = 4 ;
else if ( ( op & 0xfcc0 ) = = 0x2840 )
pc + = 6 ;
else
break ;
}
return pc ;
}
1999-04-16 01:33:56 +00:00
exec_file_command ( filename , from_tty )
char * filename ;
int from_tty ;
{
int val ;
int n ;
struct stat st_exec ;
/* Eliminate all traces of old exec file.
Mark text segment as empty . */
if ( execfile )
free ( execfile ) ;
execfile = 0 ;
data_start = 0 ;
data_end = 0 ;
text_start = 0 ;
text_end = 0 ;
exec_data_start = 0 ;
exec_data_end = 0 ;
if ( execchan > = 0 )
close ( execchan ) ;
execchan = - 1 ;
n_exec = 0 ;
/* Now open and digest the file the user requested, if any. */
if ( filename )
{
filename = tilde_expand ( filename ) ;
make_cleanup ( free , filename ) ;
execchan = openp ( getenv ( " PATH " ) , 1 , filename , O_RDONLY , 0 ,
& execfile ) ;
if ( execchan < 0 )
perror_with_name ( filename ) ;
if ( myread ( execchan , & filehdr , sizeof filehdr ) < 0 )
perror_with_name ( filename ) ;
if ( ! IS_SOFF_MAGIC ( filehdr . h_magic ) )
error ( " %s: not an executable file. " , filename ) ;
if ( myread ( execchan , & opthdr , filehdr . h_opthdr ) < = 0 )
perror_with_name ( filename ) ;
/* Read through the section headers.
For text , data , etc , record an entry in the exec file map .
Record text_start and text_end . */
lseek ( execchan , ( long ) filehdr . h_scnptr , 0 ) ;
for ( n = 0 ; n < filehdr . h_nscns ; n + + )
{
if ( myread ( execchan , & scnhdr , sizeof scnhdr ) < 0 )
perror_with_name ( filename ) ;
if ( ( scnhdr . s_flags & S_TYPMASK ) > = S_TEXT
& & ( scnhdr . s_flags & S_TYPMASK ) < = S_COMON )
{
exec_map [ n_exec ] . mem_addr = scnhdr . s_vaddr ;
exec_map [ n_exec ] . mem_end = scnhdr . s_vaddr + scnhdr . s_size ;
exec_map [ n_exec ] . file_addr = scnhdr . s_scnptr ;
exec_map [ n_exec ] . type = scnhdr . s_flags & S_TYPMASK ;
n_exec + + ;
if ( ( scnhdr . s_flags & S_TYPMASK ) = = S_TEXT )
{
text_start = scnhdr . s_vaddr ;
text_end = scnhdr . s_vaddr + scnhdr . s_size ;
}
}
}
fstat ( execchan , & st_exec ) ;
exec_mtime = st_exec . st_mtime ;
validate_files ( ) ;
}
else if ( from_tty )
printf_filtered ( " No executable file now. \n " ) ;
/* Tell display code (if any) about the changed file name. */
if ( exec_file_display_hook )
( * exec_file_display_hook ) ( filename ) ;
}
#if 0
/* Read data from SOFF exec or core file.
Return 0 on success , EIO if address out of bounds . */
int
xfer_core_file ( memaddr , myaddr , len )
CORE_ADDR memaddr ;
char * myaddr ;
int len ;
{
register int i ;
register int n ;
register int val ;
int xferchan ;
char * * xferfile ;
int fileptr ;
int returnval = 0 ;
while ( len > 0 )
{
xferfile = 0 ;
xferchan = 0 ;
/* Determine which file the next bunch of addresses reside in,
and where in the file . Set the file ' s read / write pointer
to point at the proper place for the desired address
and set xferfile and xferchan for the correct file .
If desired address is nonexistent , leave them zero .
i is set to the number of bytes that can be handled
along with the next address . */
i = len ;
for ( n = 0 ; n < n_core ; n + + )
{
if ( memaddr > = core_map [ n ] . mem_addr & & memaddr < core_map [ n ] . mem_end
& & ( core_map [ n ] . thread = = - 1
| | core_map [ n ] . thread = = inferior_thread ) )
{
i = min ( len , core_map [ n ] . mem_end - memaddr ) ;
fileptr = core_map [ n ] . file_addr + memaddr - core_map [ n ] . mem_addr ;
if ( core_map [ n ] . file_addr )
{
xferfile = & corefile ;
xferchan = corechan ;
}
break ;
}
else if ( core_map [ n ] . mem_addr > = memaddr
& & core_map [ n ] . mem_addr < memaddr + i )
i = core_map [ n ] . mem_addr - memaddr ;
}
if ( ! xferfile )
for ( n = 0 ; n < n_exec ; n + + )
{
if ( memaddr > = exec_map [ n ] . mem_addr
& & memaddr < exec_map [ n ] . mem_end )
{
i = min ( len , exec_map [ n ] . mem_end - memaddr ) ;
fileptr = exec_map [ n ] . file_addr + memaddr
- exec_map [ n ] . mem_addr ;
if ( exec_map [ n ] . file_addr )
{
xferfile = & execfile ;
xferchan = execchan ;
}
break ;
}
else if ( exec_map [ n ] . mem_addr > = memaddr
& & exec_map [ n ] . mem_addr < memaddr + i )
i = exec_map [ n ] . mem_addr - memaddr ;
}
/* Now we know which file to use.
Set up its pointer and transfer the data . */
if ( xferfile )
{
if ( * xferfile = = 0 )
if ( xferfile = = & execfile )
error ( " No program file to examine. " ) ;
else
error ( " No core dump file or running program to examine. " ) ;
val = lseek ( xferchan , fileptr , 0 ) ;
if ( val < 0 )
perror_with_name ( * xferfile ) ;
val = myread ( xferchan , myaddr , i ) ;
if ( val < 0 )
perror_with_name ( * xferfile ) ;
}
/* If this address is for nonexistent memory,
read zeros if reading , or do nothing if writing . */
else
{
memset ( myaddr , ' \0 ' , i ) ;
returnval = EIO ;
}
memaddr + = i ;
myaddr + = i ;
len - = i ;
}
return returnval ;
}
# endif
/* Here from info files command to print an address map. */
print_maps ( )
{
struct pmap ptrs [ 200 ] ;
int n ;
/* ID strings for core and executable file sections */
static char * idstr [ ] =
{
" 0 " , " text " , " data " , " tdata " , " bss " , " tbss " ,
" common " , " ttext " , " ctx " , " tctx " , " 10 " , " 11 " , " 12 " ,
} ;
for ( n = 0 ; n < n_core ; n + + )
{
core_map [ n ] . which = 0 ;
ptrs [ n ] = core_map [ n ] ;
}
for ( n = 0 ; n < n_exec ; n + + )
{
exec_map [ n ] . which = 1 ;
ptrs [ n_core + n ] = exec_map [ n ] ;
}
qsort ( ptrs , n_core + n_exec , sizeof * ptrs , ptr_cmp ) ;
for ( n = 0 ; n < n_core + n_exec ; n + + )
{
struct pmap * p = & ptrs [ n ] ;
if ( n > 0 )
{
if ( p - > mem_addr < ptrs [ n - 1 ] . mem_end )
p - > mem_addr = ptrs [ n - 1 ] . mem_end ;
if ( p - > mem_addr > = p - > mem_end )
continue ;
}
printf_filtered ( " %08x .. %08x %-6s %s \n " ,
p - > mem_addr , p - > mem_end , idstr [ p - > type ] ,
p - > which ? execfile : corefile ) ;
}
}
/* Compare routine to put file sections in order.
Sort into increasing order on address , and put core file sections
before exec file sections if both files contain the same addresses . */
static ptr_cmp ( a , b )
struct pmap * a , * b ;
{
if ( a - > mem_addr ! = b - > mem_addr ) return a - > mem_addr - b - > mem_addr ;
return a - > which - b - > which ;
}
/* Trapped internal variables are used to handle special registers.
A trapped i . v . calls a hook here every time it is dereferenced ,
to provide a new value for the variable , and it calls a hook here
when a new value is assigned , to do something with the value .
The vector registers are $ vl , $ vs , $ vm , $ vN , $ VN ( N in 0. .7 ) .
The communication registers are $ cN , $ CN ( N in 0. .63 ) .
They not handled as regular registers because it ' s expensive to
read them , and their size varies , and they have too many names . */
/* Return 1 if NAME is a trapped internal variable, else 0. */
int
is_trapped_internalvar ( name )
char * name ;
{
if ( ( name [ 0 ] = = ' c ' | | name [ 0 ] = = ' C ' )
& & name [ 1 ] > = ' 0 ' & & name [ 1 ] < = ' 9 '
& & ( name [ 2 ] = = ' \0 '
| | ( name [ 2 ] > = ' 0 ' & & name [ 2 ] < = ' 9 '
& & name [ 3 ] = = ' \0 ' & & name [ 1 ] ! = ' 0 ' ) )
& & atoi ( & name [ 1 ] ) < 64 ) return 1 ;
if ( ( name [ 0 ] = = ' v ' | | name [ 0 ] = = ' V ' )
& & ( ( ( name [ 1 ] & - 8 ) = = ' 0 ' & & name [ 2 ] = = ' \0 ' )
| | STREQ ( name , " vl " )
| | STREQ ( name , " vs " )
| | STREQ ( name , " vm " ) ) )
return 1 ;
else return 0 ;
}
/* Return the value of trapped internal variable VAR */
value
value_of_trapped_internalvar ( var )
struct internalvar * var ;
{
char * name = var - > name ;
value val ;
struct type * type ;
struct type * range_type ;
long len = * read_vector_register ( VL_REGNUM ) ;
if ( len < = 0 | | len > 128 ) len = 128 ;
if ( STREQ ( name , " vl " ) )
{
val = value_from_longest ( builtin_type_int ,
( LONGEST ) * read_vector_register_1 ( VL_REGNUM ) ) ;
}
else if ( STREQ ( name , " vs " ) )
{
val = value_from_longest ( builtin_type_int ,
( LONGEST ) * read_vector_register_1 ( VS_REGNUM ) ) ;
}
else if ( STREQ ( name , " vm " ) )
{
long vm [ 4 ] ;
long i , * p ;
memcpy ( vm , read_vector_register_1 ( VM_REGNUM ) , sizeof vm ) ;
range_type =
create_range_type ( ( struct type * ) NULL , builtin_type_int , 0 , len - 1 ) ;
type =
create_array_type ( ( struct type * ) NULL , builtin_type_int , range_type ) ;
val = allocate_value ( type ) ;
p = ( long * ) VALUE_CONTENTS ( val ) ;
for ( i = 0 ; i < len ; i + + )
* p + + = ! ! ( vm [ 3 - ( i > > 5 ) ] & ( 1 < < ( i & 037 ) ) ) ;
}
else if ( name [ 0 ] = = ' V ' )
{
range_type =
create_range_type ( ( struct type * ) NULL , builtin_type_int 0 , len - 1 ) ;
type =
create_array_type ( ( struct type * ) NULL , builtin_type_long_long ,
range_type ) ;
val = allocate_value ( type ) ;
memcpy ( VALUE_CONTENTS ( val ) ,
read_vector_register_1 ( name [ 1 ] - ' 0 ' ) ,
TYPE_LENGTH ( type ) ) ;
}
else if ( name [ 0 ] = = ' v ' )
{
long * p1 , * p2 ;
range_type =
create_range_type ( ( struct type * ) NULL , builtin_type_int 0 , len - 1 ) ;
type =
create_array_type ( ( struct type * ) NULL , builtin_type_long ,
range_type ) ;
val = allocate_value ( type ) ;
p1 = read_vector_register_1 ( name [ 1 ] - ' 0 ' ) ;
p2 = ( long * ) VALUE_CONTENTS ( val ) ;
while ( - - len > = 0 ) { p1 + + ; * p2 + + = * p1 + + ; }
}
else if ( name [ 0 ] = = ' c ' )
val = value_from_longest ( builtin_type_int ,
read_comm_register ( atoi ( & name [ 1 ] ) ) ) ;
else if ( name [ 0 ] = = ' C ' )
val = value_from_longest ( builtin_type_long_long ,
read_comm_register ( atoi ( & name [ 1 ] ) ) ) ;
VALUE_LVAL ( val ) = lval_internalvar ;
VALUE_INTERNALVAR ( val ) = var ;
return val ;
}
/* Handle a new value assigned to a trapped internal variable */
void
set_trapped_internalvar ( var , val , bitpos , bitsize , offset )
struct internalvar * var ;
value val ;
int bitpos , bitsize , offset ;
{
char * name = var - > name ;
long long newval = value_as_long ( val ) ;
if ( STREQ ( name , " vl " ) )
write_vector_register ( VL_REGNUM , 0 , newval ) ;
else if ( STREQ ( name , " vs " ) )
write_vector_register ( VS_REGNUM , 0 , newval ) ;
else if ( name [ 0 ] = = ' c ' | | name [ 0 ] = = ' C ' )
write_comm_register ( atoi ( & name [ 1 ] ) , newval ) ;
else if ( STREQ ( name , " vm " ) )
error ( " can't assign to $vm " ) ;
else
{
offset / = bitsize / 8 ;
write_vector_register ( name [ 1 ] - ' 0 ' , offset , newval ) ;
}
}
/* Print an integer value when no format was specified. gdb normally
prints these values in decimal , but the the leading 0x80000000 of
pointers produces intolerable 10 - digit negative numbers .
If it looks like an address , print it in hex instead . */
decout ( stream , type , val )
GDB_FILE * stream ;
struct type * type ;
LONGEST val ;
{
long lv = val ;
switch ( output_radix )
{
case 0 :
if ( ( lv = = val | | ( unsigned ) lv = = val )
& & ( ( lv & 0xf0000000 ) = = 0x80000000
| | ( ( lv & 0xf0000000 ) = = 0xf0000000 & & lv < STACK_END_ADDR ) ) )
{
print_longest ( stream , " x " , 0 , val ) ;
return ;
}
case 10 :
print_longest ( stream , TYPE_UNSIGNED ( type ) ? " u " : " d " , 0 , val ) ;
return ;
case 8 :
print_longest ( stream , " o " , 0 , val ) ;
return ;
case 16 :
print_longest ( stream , " x " , 0 , val ) ;
return ;
}
}
/* Change the default output radix to 10 or 16, or set it to 0 (heuristic).
This command is mostly obsolete now that the print command allows
formats to apply to aggregates , but is still handy occasionally . */
static void
set_base_command ( arg )
char * arg ;
{
int new_radix ;
if ( ! arg )
output_radix = 0 ;
else
{
new_radix = atoi ( arg ) ;
if ( new_radix ! = 10 & & new_radix ! = 16 & & new_radix ! = 8 )
error ( " base must be 8, 10 or 16, or null " ) ;
else output_radix = new_radix ;
}
}
/* Turn pipelining on or off in the inferior. */
static void
set_pipelining_command ( arg )
char * arg ;
{
if ( ! arg )
{
sequential = ! sequential ;
printf_filtered ( " %s \n " , sequential ? " off " : " on " ) ;
}
else if ( STREQ ( arg , " on " ) )
sequential = 0 ;
else if ( STREQ ( arg , " off " ) )
sequential = 1 ;
else error ( " valid args are `on', to allow instructions to overlap, or \n \
` off ' , to prevent it and thereby pinpoint exceptions . " );
}
/* Enable, disable, or force parallel execution in the inferior. */
static void
set_parallel_command ( arg )
char * arg ;
{
struct rlimit rl ;
int prevparallel = parallel ;
if ( ! strncmp ( arg , " fixed " , strlen ( arg ) ) )
parallel = 2 ;
else if ( STREQ ( arg , " on " ) )
parallel = 1 ;
else if ( STREQ ( arg , " off " ) )
parallel = 0 ;
else error ( " valid args are `on', to allow multiple threads, or \n \
` fixed ' , to force multiple threads , or \ n \
` off ' , to run with one thread only . " );
if ( ( prevparallel = = 0 ) ! = ( parallel = = 0 ) & & inferior_pid )
printf_filtered ( " will take effect at next run. \n " ) ;
getrlimit ( RLIMIT_CONCUR , & rl ) ;
rl . rlim_cur = parallel ? rl . rlim_max : 1 ;
setrlimit ( RLIMIT_CONCUR , & rl ) ;
if ( inferior_pid )
set_fixed_scheduling ( inferior_pid , parallel = = 2 ) ;
}
/* Add a new name for an existing command. */
static void
alias_command ( arg )
char * arg ;
{
static char * aliaserr = " usage is `alias NEW OLD', no args allowed " ;
char * newname = arg ;
struct cmd_list_element * new , * old ;
if ( ! arg )
error_no_arg ( " newname oldname " ) ;
new = lookup_cmd ( & arg , cmdlist , " " , - 1 ) ;
if ( new & & ! strncmp ( newname , new - > name , strlen ( new - > name ) ) )
{
newname = new - > name ;
if ( ! ( * arg = = ' - '
| | ( * arg > = ' a ' & & * arg < = ' z ' )
| | ( * arg > = ' A ' & & * arg < = ' Z ' )
| | ( * arg > = ' 0 ' & & * arg < = ' 9 ' ) ) )
error ( aliaserr ) ;
}
else
{
arg = newname ;
while ( * arg = = ' - '
| | ( * arg > = ' a ' & & * arg < = ' z ' )
| | ( * arg > = ' A ' & & * arg < = ' Z ' )
| | ( * arg > = ' 0 ' & & * arg < = ' 9 ' ) )
arg + + ;
if ( * arg ! = ' ' & & * arg ! = ' \t ' )
error ( aliaserr ) ;
* arg = ' \0 ' ;
arg + + ;
}
old = lookup_cmd ( & arg , cmdlist , " " , 0 ) ;
if ( * arg ! = ' \0 ' )
error ( aliaserr ) ;
if ( new & & ! strncmp ( newname , new - > name , strlen ( new - > name ) ) )
{
char * tem ;
if ( new - > class = = ( int ) class_user | | new - > class = = ( int ) class_alias )
tem = " Redefine command \" %s \" ? " ;
else
tem = " Really redefine built-in command \" %s \" ? " ;
if ( ! query ( tem , new - > name ) )
error ( " Command \" %s \" not redefined. " , new - > name ) ;
}
add_com ( newname , class_alias , old - > function , old - > doc ) ;
}
/* Print the current thread number, and any threads with signals in the
queue . */
thread_info ( )
{
struct threadpid * p ;
if ( have_inferior_p ( ) )
{
ps . pi_buffer = ( char * ) & comm_registers ;
ps . pi_nbytes = sizeof comm_registers ;
ps . pi_offset = 0 ;
ps . pi_thread = inferior_thread ;
ioctl ( inferior_fd , PIXRDCREGS , & ps ) ;
}
/* FIXME: stop_signal is from target.h but stop_sigcode is a
convex - specific thing . */
printf_filtered ( " Current thread %d stopped with signal %d.%d (%s). \n " ,
inferior_thread , stop_signal , stop_sigcode ,
subsig_name ( stop_signal , stop_sigcode ) ) ;
for ( p = signal_stack ; p - > pid ; p - - )
printf_filtered ( " Thread %d stopped with signal %d.%d (%s). \n " ,
p - > thread , p - > signo , p - > subsig ,
subsig_name ( p - > signo , p - > subsig ) ) ;
if ( iscrlbit ( comm_registers . crctl . lbits . cc , 64 + 13 ) )
printf_filtered ( " New thread start pc %#x \n " ,
( long ) ( comm_registers . crreg . pcpsw > > 32 ) ) ;
}
/* Return string describing a signal.subcode number */
static char *
subsig_name ( signo , subcode )
int signo , subcode ;
{
static char * subsig4 [ ] = {
" error exit " , " privileged instruction " , " unknown " ,
" unknown " , " undefined opcode " ,
0 } ;
static char * subsig5 [ ] = { 0 ,
" breakpoint " , " single step " , " fork trap " , " exec trap " , " pfork trap " ,
" join trap " , " idle trap " , " last thread " , " wfork trap " ,
" process breakpoint " , " trap instruction " ,
0 } ;
static char * subsig8 [ ] = { 0 ,
" int overflow " , " int divide check " , " float overflow " ,
" float divide check " , " float underflow " , " reserved operand " ,
" sqrt error " , " exp error " , " ln error " , " sin error " , " cos error " ,
0 } ;
static char * subsig10 [ ] = { 0 ,
" invalid inward ring address " , " invalid outward ring call " ,
" invalid inward ring return " , " invalid syscall gate " ,
" invalid rtn frame length " , " invalid comm reg address " ,
" invalid trap gate " ,
0 } ;
static char * subsig11 [ ] = { 0 ,
" read access denied " , " write access denied " , " execute access denied " ,
" segment descriptor fault " , " page table fault " , " data reference fault " ,
" i/o access denied " , " levt pte invalid " ,
0 } ;
static char * * subsig_list [ ] =
{ 0 , 0 , 0 , 0 , subsig4 , subsig5 , 0 , 0 , subsig8 , 0 , subsig10 , subsig11 , 0 } ;
int i ;
char * p ;
if ( ( p = strsignal ( signo ) ) = = NULL )
p = " unknown " ;
if ( signo > = ( sizeof subsig_list / sizeof * subsig_list )
| | ! subsig_list [ signo ] )
return p ;
for ( i = 1 ; subsig_list [ signo ] [ i ] ; i + + )
if ( i = = subcode )
return subsig_list [ signo ] [ subcode ] ;
return p ;
}
/* Print a compact display of thread status, essentially x/i $pc
for all active threads . */
static void
threadstat ( )
{
int t ;
for ( t = 0 ; t < n_threads ; t + + )
if ( thread_state [ t ] = = PI_TALIVE )
{
printf_filtered ( " %d%c %08x%c %d.%d " , t ,
( t = = inferior_thread ? ' * ' : ' ' ) , thread_pc [ t ] ,
( thread_is_in_kernel [ t ] ? ' # ' : ' ' ) ,
thread_signal [ t ] , thread_sigcode [ t ] ) ;
print_insn ( thread_pc [ t ] , stdout ) ;
printf_filtered ( " \n " ) ;
}
}
/* Change the current thread to ARG. */
set_thread_command ( arg )
char * arg ;
{
int thread ;
if ( ! arg )
{
threadstat ( ) ;
return ;
}
thread = parse_and_eval_address ( arg ) ;
if ( thread < 0 | | thread > n_threads | | thread_state [ thread ] ! = PI_TALIVE )
error ( " no such thread. " ) ;
select_thread ( thread ) ;
stop_pc = read_pc ( ) ;
flush_cached_frames ( ) ;
select_frame ( get_current_frame ( ) , 0 ) ;
print_stack_frame ( selected_frame , selected_frame_level , - 1 ) ;
}
/* Here on CONT command; gdb's dispatch address is changed to come here.
Set global variable ALL_CONTINUE to tell resume ( ) that it should
start up all threads , and that a thread switch will not blow gdb ' s
mind . */
static void
convex_cont_command ( proc_count_exp , from_tty )
char * proc_count_exp ;
int from_tty ;
{
all_continue = 1 ;
cont_command ( proc_count_exp , from_tty ) ;
}
/* Here on 1CONT command. Resume only the current thread. */
one_cont_command ( proc_count_exp , from_tty )
char * proc_count_exp ;
int from_tty ;
{
cont_command ( proc_count_exp , from_tty ) ;
}
/* Print the contents and lock bits of all communication registers,
or just register ARG if ARG is a communication register ,
or the 3 - word resource structure in memory at address ARG . */
comm_registers_info ( arg )
char * arg ;
{
int i , regnum ;
if ( arg )
{
if ( sscanf ( arg , " $c%d " , & regnum ) = = 1 ) {
;
} else if ( sscanf ( arg , " $C%d " , & regnum ) = = 1 ) {
;
} else {
regnum = parse_and_eval_address ( arg ) ;
if ( regnum > 0 )
regnum & = ~ 0x8000 ;
}
if ( regnum > = 64 )
error ( " %s: invalid register name. " , arg ) ;
/* if we got a (user) address, examine the resource struct there */
if ( regnum < 0 )
{
static int buf [ 3 ] ;
read_memory ( regnum , buf , sizeof buf ) ;
printf_filtered ( " %08x %08x%08x%s \n " , regnum , buf [ 1 ] , buf [ 2 ] ,
buf [ 0 ] & 0xff ? " locked " : " " ) ;
return ;
}
}
ps . pi_buffer = ( char * ) & comm_registers ;
ps . pi_nbytes = sizeof comm_registers ;
ps . pi_offset = 0 ;
ps . pi_thread = inferior_thread ;
ioctl ( inferior_fd , PIXRDCREGS , & ps ) ;
for ( i = 0 ; i < 64 ; i + + )
if ( ! arg | | i = = regnum )
printf_filtered ( " %2d 0x8%03x %016llx%s \n " , i , i ,
comm_registers . crreg . r4 [ i ] ,
( iscrlbit ( comm_registers . crctl . lbits . cc , i )
? " locked " : " " ) ) ;
}
/* Print the psw */
static void
psw_info ( arg )
char * arg ;
{
struct pswbit
{
int bit ;
int pos ;
char * text ;
} ;
static struct pswbit pswbit [ ] =
{
{ 0x80000000 , - 1 , " A carry " } ,
{ 0x40000000 , - 1 , " A integer overflow " } ,
{ 0x20000000 , - 1 , " A zero divide " } ,
{ 0x10000000 , - 1 , " Integer overflow enable " } ,
{ 0x08000000 , - 1 , " Trace " } ,
{ 0x06000000 , 25 , " Frame length " } ,
{ 0x01000000 , - 1 , " Sequential " } ,
{ 0x00800000 , - 1 , " S carry " } ,
{ 0x00400000 , - 1 , " S integer overflow " } ,
{ 0x00200000 , - 1 , " S zero divide " } ,
{ 0x00100000 , - 1 , " Zero divide enable " } ,
{ 0x00080000 , - 1 , " Floating underflow " } ,
{ 0x00040000 , - 1 , " Floating overflow " } ,
{ 0x00020000 , - 1 , " Floating reserved operand " } ,
{ 0x00010000 , - 1 , " Floating zero divide " } ,
{ 0x00008000 , - 1 , " Floating error enable " } ,
{ 0x00004000 , - 1 , " Floating underflow enable " } ,
{ 0x00002000 , - 1 , " IEEE " } ,
{ 0x00001000 , - 1 , " Sequential stores " } ,
{ 0x00000800 , - 1 , " Intrinsic error " } ,
{ 0x00000400 , - 1 , " Intrinsic error enable " } ,
{ 0x00000200 , - 1 , " Trace thread creates " } ,
{ 0x00000100 , - 1 , " Thread init trap " } ,
{ 0x000000e0 , 5 , " Reserved " } ,
{ 0x0000001f , 0 , " Intrinsic error code " } ,
{ 0 , 0 , 0 } ,
} ;
long psw ;
struct pswbit * p ;
if ( arg )
psw = parse_and_eval_address ( arg ) ;
else
psw = read_register ( PS_REGNUM ) ;
for ( p = pswbit ; p - > bit ; p + + )
{
if ( p - > pos < 0 )
printf_filtered ( " %08x %s %s \n " , p - > bit ,
( psw & p - > bit ) ? " yes " : " no " , p - > text ) ;
else
printf_filtered ( " %08x %3d %s \n " , p - > bit ,
( psw & p - > bit ) > > p - > pos , p - > text ) ;
}
}
# include "symtab.h"
/* reg (fmt_field, inst_field) --
the { first , second , third } operand of instruction as fmt_field = [ ijk ]
gets the value of the field from the [ ijk ] position of the instruction */
# define reg(a,b) ((char (*)[3])(op[fmt->a]))[inst.f0.b]
/* lit (fmt_field) -- field [ijk] is a literal (PSW, VL, eg) */
# define lit(i) op[fmt->i]
/* aj[j] -- name for A register j */
# define aj ((char (*)[3])(op[A]))
union inst {
struct {
unsigned : 7 ;
unsigned i : 3 ;
unsigned j : 3 ;
unsigned k : 3 ;
unsigned : 16 ;
unsigned : 32 ;
} f0 ;
struct {
unsigned : 8 ;
unsigned indir : 1 ;
unsigned len : 1 ;
unsigned j : 3 ;
unsigned k : 3 ;
unsigned : 16 ;
unsigned : 32 ;
} f1 ;
unsigned char byte [ 8 ] ;
unsigned short half [ 4 ] ;
char signed_byte [ 8 ] ;
short signed_half [ 4 ] ;
} ;
struct opform {
int mask ; /* opcode mask */
int shift ; /* opcode align */
struct formstr * formstr [ 3 ] ; /* ST, E0, E1 */
} ;
struct formstr {
unsigned lop : 8 , rop : 5 ; /* opcode */
unsigned fmt : 5 ; /* inst format */
unsigned i : 5 , j : 5 , k : 2 ; /* operand formats */
} ;
# include "opcode/convex.h"
CONST unsigned char formdecode [ ] = {
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ,
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ,
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 5 , 5 , 5 , 5 , 6 , 6 , 7 , 8 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
} ;
CONST struct opform opdecode [ ] = {
0x7e00 , 9 , format0 , e0_format0 , e1_format0 ,
0x3f00 , 8 , format1 , e0_format1 , e1_format1 ,
0x1fc0 , 6 , format2 , e0_format2 , e1_format2 ,
0x0fc0 , 6 , format3 , e0_format3 , e1_format3 ,
0x0700 , 8 , format4 , e0_format4 , e1_format4 ,
0x03c0 , 6 , format5 , e0_format5 , e1_format5 ,
0x01f8 , 3 , format6 , e0_format6 , e1_format6 ,
0x00f8 , 3 , format7 , e0_format7 , e1_format7 ,
0x0000 , 0 , formatx , formatx , formatx ,
0x0f80 , 7 , formatx , formatx , formatx ,
0x0f80 , 7 , formatx , formatx , formatx ,
} ;
/* Print the instruction at address MEMADDR in debugged memory,
on STREAM . Returns length of the instruction , in bytes . */
int
convex_print_insn ( memaddr , stream )
CORE_ADDR memaddr ;
FILE * stream ;
{
union inst inst ;
struct formstr * fmt ;
register int format , op1 , pfx ;
int l ;
read_memory ( memaddr , & inst , sizeof inst ) ;
/* Remove and note prefix, if present */
pfx = inst . half [ 0 ] ;
if ( ( pfx & 0xfff0 ) = = 0x7ef0 )
{
pfx = ( ( pfx > > 3 ) & 1 ) + 1 ;
* ( long long * ) & inst = * ( long long * ) & inst . half [ 1 ] ;
}
else pfx = 0 ;
/* Split opcode into format.op1 and look up in appropriate table */
format = formdecode [ inst . byte [ 0 ] ] ;
op1 = ( inst . half [ 0 ] & opdecode [ format ] . mask ) > > opdecode [ format ] . shift ;
if ( format = = 9 )
{
if ( pfx )
fmt = formatx ;
else if ( inst . f1 . j = = 0 )
fmt = & format1a [ op1 ] ;
else if ( inst . f1 . j = = 1 )
fmt = & format1b [ op1 ] ;
else
fmt = formatx ;
}
else
fmt = & opdecode [ format ] . formstr [ pfx ] [ op1 ] ;
/* Print it */
if ( fmt - > fmt = = xxx )
{
/* noninstruction */
fprintf ( stream , " 0x%04x " , pfx ? pfx : inst . half [ 0 ] ) ;
return 2 ;
}
if ( pfx )
pfx = 2 ;
fprintf ( stream , " %s%s%s " , lop [ fmt - > lop ] , rop [ fmt - > rop ] ,
& " " [ strlen ( lop [ fmt - > lop ] ) + strlen ( rop [ fmt - > rop ] ) ] ) ;
switch ( fmt - > fmt )
{
case rrr : /* three register */
fprintf ( stream , " %s,%s,%s " , reg ( i , i ) , reg ( j , j ) , reg ( k , k ) ) ;
return pfx + 2 ;
case rr : /* two register */
fprintf ( stream , " %s,%s " , reg ( i , j ) , reg ( j , k ) ) ;
return pfx + 2 ;
case rxr : /* two register, reversed i and j fields */
fprintf ( stream , " %s,%s " , reg ( i , k ) , reg ( j , j ) ) ;
return pfx + 2 ;
case r : /* one register */
fprintf ( stream , " %s " , reg ( i , k ) ) ;
return pfx + 2 ;
case nops : /* no operands */
return pfx + 2 ;
case nr : /* short immediate, one register */
fprintf ( stream , " #%d,%s " , inst . f0 . j , reg ( i , k ) ) ;
return pfx + 2 ;
case pcrel : /* pc relative */
print_address ( memaddr + 2 * inst . signed_byte [ 1 ] , stream ) ;
return pfx + 2 ;
case lr : /* literal, one register */
fprintf ( stream , " %s,%s " , lit ( i ) , reg ( j , k ) ) ;
return pfx + 2 ;
case rxl : /* one register, literal */
fprintf ( stream , " %s,%s " , reg ( i , k ) , lit ( j ) ) ;
return pfx + 2 ;
case rlr : /* register, literal, register */
fprintf ( stream , " %s,%s,%s " , reg ( i , j ) , lit ( j ) , reg ( k , k ) ) ;
return pfx + 2 ;
case rrl : /* register, register, literal */
fprintf ( stream , " %s,%s,%s " , reg ( i , j ) , reg ( j , k ) , lit ( k ) ) ;
return pfx + 2 ;
case iml : /* immediate, literal */
if ( inst . f1 . len )
{
fprintf ( stream , " #%#x,%s " ,
( inst . signed_half [ 1 ] < < 16 ) + inst . half [ 2 ] , lit ( i ) ) ;
return pfx + 6 ;
}
else
{
fprintf ( stream , " #%d,%s " , inst . signed_half [ 1 ] , lit ( i ) ) ;
return pfx + 4 ;
}
case imr : /* immediate, register */
if ( inst . f1 . len )
{
fprintf ( stream , " #%#x,%s " ,
( inst . signed_half [ 1 ] < < 16 ) + inst . half [ 2 ] , reg ( i , k ) ) ;
return pfx + 6 ;
}
else
{
fprintf ( stream , " #%d,%s " , inst . signed_half [ 1 ] , reg ( i , k ) ) ;
return pfx + 4 ;
}
case a1r : /* memory, register */
l = print_effa ( inst , stream ) ;
fprintf ( stream , " ,%s " , reg ( i , k ) ) ;
return pfx + l ;
case a1l : /* memory, literal */
l = print_effa ( inst , stream ) ;
fprintf ( stream , " ,%s " , lit ( i ) ) ;
return pfx + l ;
case a2r : /* register, memory */
fprintf ( stream , " %s, " , reg ( i , k ) ) ;
return pfx + print_effa ( inst , stream ) ;
case a2l : /* literal, memory */
fprintf ( stream , " %s, " , lit ( i ) ) ;
return pfx + print_effa ( inst , stream ) ;
case a3 : /* memory */
return pfx + print_effa ( inst , stream ) ;
case a4 : /* system call */
l = 29 ; goto a4a5 ;
case a5 : /* trap */
l = 27 ;
a4a5 :
if ( inst . f1 . len )
{
unsigned int m = ( inst . signed_half [ 1 ] < < 16 ) + inst . half [ 2 ] ;
fprintf ( stream , " #%d,#%d " , m > > l , m & ( - 1 > > ( 32 - l ) ) ) ;
return pfx + 6 ;
}
else
{
unsigned int m = inst . signed_half [ 1 ] ;
fprintf ( stream , " #%d,#%d " , m > > l , m & ( - 1 > > ( 32 - l ) ) ) ;
return pfx + 4 ;
}
}
}
/* print effective address @nnn(aj), return instruction length */
int print_effa ( inst , stream )
union inst inst ;
FILE * stream ;
{
int n , l ;
if ( inst . f1 . len )
{
n = ( inst . signed_half [ 1 ] < < 16 ) + inst . half [ 2 ] ;
l = 6 ;
}
else
{
n = inst . signed_half [ 1 ] ;
l = 4 ;
}
if ( inst . f1 . indir )
printf ( " @ " ) ;
if ( ! inst . f1 . j )
{
print_address ( n , stream ) ;
return l ;
}
fprintf ( stream , ( n & 0xf0000000 ) = = 0x80000000 ? " %#x(%s) " : " %d(%s) " ,
n , aj [ inst . f1 . j ] ) ;
return l ;
}
void
_initialize_convex_dep ( )
{
add_com ( " alias " , class_support , alias_command ,
" Add a new name for an existing command. " ) ;
add_cmd ( " base " , class_vars , set_base_command ,
" Change the integer output radix to 8, 10 or 16 \n \
or use just ` set base ' with no args to return to the ad - hoc default , \ n \
which is 16 for integers that look like addresses , 10 otherwise . " ,
& setlist ) ;
add_cmd ( " pipeline " , class_run , set_pipelining_command ,
" Enable or disable overlapped execution of instructions. \n \
With ` set pipe off ' , exceptions are reported with \ n \
$ pc pointing at the instruction after the faulting one . \ n \
The default is ` set pipe on ' , which runs faster . " ,
& setlist ) ;
add_cmd ( " parallel " , class_run , set_parallel_command ,
" Enable or disable multi-threaded execution of parallel code. \n \
` set parallel off ' means run the program on a single CPU . \ n \
` set parallel fixed ' means run the program with all CPUs assigned to it . \ n \
` set parallel on ' means run the program on any CPUs that are available . " ,
& setlist ) ;
add_com ( " 1cont " , class_run , one_cont_command ,
" Continue the program, activating only the current thread. \n \
Args are the same as the ` cont ' command . " );
add_com ( " thread " , class_run , set_thread_command ,
" Change the current thread, the one under scrutiny and control. \n \
With no arg , show the active threads , the current one marked with * . " );
add_info ( " threads " , thread_info ,
" List status of active threads. " ) ;
add_info ( " comm-registers " , comm_registers_info ,
" List communication registers and their contents. \n \
A communication register name as argument means describe only that register . \ n \
An address as argument means describe the resource structure at that address . \ n \
` Locked ' means that the register has been sent to but not yet received from . " );
add_info ( " psw " , psw_info ,
" Display $ps, the processor status word, bit by bit. \n \
An argument means display that value ' s interpretation as a psw . " );
add_cmd ( " convex " , no_class , 0 , " Convex-specific commands. \n \
32 - bit registers $ pc $ ps $ sp $ ap $ fp $ a1 - 5 $ s0 - 7 $ v0 - 7 $ vl $ vs $ vm $ c0 - 63 \ n \
64 - bit registers $ S0 - 7 $ V0 - 7 $ C0 - 63 \ n \
\ n \
info threads display info on stopped threads waiting to signal \ n \
thread display list of active threads \ n \
thread N select thread N ( its registers , stack , memory , etc . ) \ n \
step , next , etc step selected thread only \ n \
1 cont continue selected thread only \ n \
cont continue all threads \ n \
info comm - registers display contents of comm register ( s ) or a resource struct \ n \
info psw display processor status word $ ps \ n \
set base N change integer radix used by ` print ' without a format \ n \
set pipeline off exceptions are precise , $ pc points after the faulting insn \ n \
set pipeline on normal mode , $ pc is somewhere ahead of faulting insn \ n \
set parallel off program runs on a single CPU \ n \
set parallel fixed all CPUs are assigned to the program \ n \
set parallel on normal mode , parallel execution on random available CPUs \ n \
" ,
& cmdlist ) ;
}