@ -21,8 +21,16 @@
# include "server.h"
# include "linux-low.h"
# include <elf.h>
# include <asm/ptrace.h>
/* These are in <asm/cputable.h> in current kernels. */
# define PPC_FEATURE_HAS_ALTIVEC 0x10000000
# define PPC_FEATURE_HAS_SPE 0x00800000
static unsigned long ppc_hwcap ;
/* Defined in auto-generated file reg-ppc.c. */
void init_registers_ppc ( void ) ;
/* Defined in auto-generated file powerpc-32.c. */
@ -69,16 +77,6 @@ static int ppc_regmap[] =
PT_R20 * 4 , PT_R21 * 4 , PT_R22 * 4 , PT_R23 * 4 ,
PT_R24 * 4 , PT_R25 * 4 , PT_R26 * 4 , PT_R27 * 4 ,
PT_R28 * 4 , PT_R29 * 4 , PT_R30 * 4 , PT_R31 * 4 ,
# ifdef __SPE__
- 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 ,
# else
PT_FPR0 * 4 , PT_FPR0 * 4 + 8 , PT_FPR0 * 4 + 16 , PT_FPR0 * 4 + 24 ,
PT_FPR0 * 4 + 32 , PT_FPR0 * 4 + 40 , PT_FPR0 * 4 + 48 , PT_FPR0 * 4 + 56 ,
PT_FPR0 * 4 + 64 , PT_FPR0 * 4 + 72 , PT_FPR0 * 4 + 80 , PT_FPR0 * 4 + 88 ,
@ -87,22 +85,38 @@ static int ppc_regmap[] =
PT_FPR0 * 4 + 160 , PT_FPR0 * 4 + 168 , PT_FPR0 * 4 + 176 , PT_FPR0 * 4 + 184 ,
PT_FPR0 * 4 + 192 , PT_FPR0 * 4 + 200 , PT_FPR0 * 4 + 208 , PT_FPR0 * 4 + 216 ,
PT_FPR0 * 4 + 224 , PT_FPR0 * 4 + 232 , PT_FPR0 * 4 + 240 , PT_FPR0 * 4 + 248 ,
# endif
PT_NIP * 4 , PT_MSR * 4 , PT_CCR * 4 , PT_LNK * 4 ,
# ifdef __SPE__
PT_CTR * 4 , PT_XER * 4 , - 1
# else
PT_CTR * 4 , PT_XER * 4 , PT_FPSCR * 4
# endif
} ;
static int ppc_regmap_e500 [ ] =
{ PT_R0 * 4 , PT_R1 * 4 , PT_R2 * 4 , PT_R3 * 4 ,
PT_R4 * 4 , PT_R5 * 4 , PT_R6 * 4 , PT_R7 * 4 ,
PT_R8 * 4 , PT_R9 * 4 , PT_R10 * 4 , PT_R11 * 4 ,
PT_R12 * 4 , PT_R13 * 4 , PT_R14 * 4 , PT_R15 * 4 ,
PT_R16 * 4 , PT_R17 * 4 , PT_R18 * 4 , PT_R19 * 4 ,
PT_R20 * 4 , PT_R21 * 4 , PT_R22 * 4 , PT_R23 * 4 ,
PT_R24 * 4 , PT_R25 * 4 , PT_R26 * 4 , PT_R27 * 4 ,
PT_R28 * 4 , PT_R29 * 4 , PT_R30 * 4 , PT_R31 * 4 ,
- 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 ,
PT_NIP * 4 , PT_MSR * 4 , PT_CCR * 4 , PT_LNK * 4 ,
PT_CTR * 4 , PT_XER * 4 , - 1
} ;
# endif
static int
ppc_cannot_store_register ( int regno )
{
# if !defined (__powerpc64__) && !defined (__SPE__)
# ifndef __powerpc64__
/* Some kernels do not allow us to store fpscr. */
if ( regno = = find_regno ( " fpscr " ) )
if ( ! ( ppc_hwcap & PPC_FEATURE_HAS_SPE ) & & regno = = find_regno ( " fpscr " ) )
return 2 ;
# endif
@ -167,6 +181,42 @@ ppc_set_pc (CORE_ADDR pc)
}
}
static int
ppc_get_hwcap ( unsigned long * valp )
{
int wordsize = register_size ( 0 ) ;
unsigned char * data = alloca ( 2 * wordsize ) ;
int offset = 0 ;
while ( ( * the_target - > read_auxv ) ( offset , data , 2 * wordsize ) = = 2 * wordsize )
{
if ( wordsize = = 4 )
{
unsigned int * data_p = ( unsigned int * ) data ;
if ( data_p [ 0 ] = = AT_HWCAP )
{
* valp = data_p [ 1 ] ;
return 1 ;
}
}
else
{
unsigned long * data_p = ( unsigned long * ) data ;
if ( data_p [ 0 ] = = AT_HWCAP )
{
* valp = data_p [ 1 ] ;
return 1 ;
}
}
offset + = 2 * wordsize ;
}
* valp = 0 ;
return 0 ;
}
static void
ppc_arch_setup ( void )
{
@ -174,28 +224,37 @@ ppc_arch_setup (void)
long msr ;
/* On a 64-bit host, assume 64-bit inferior process. */
# ifdef __ALTIVEC__
init_registers_powerpc_64 ( ) ;
# else
init_registers_ppc64 ( ) ;
# endif
/* Only if the high bit of the MSR is set, we actually have
a 64 - bit inferior . */
collect_register_by_name ( " msr " , & msr ) ;
if ( msr < 0 )
return ;
{
ppc_get_hwcap ( & ppc_hwcap ) ;
if ( ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC )
init_registers_powerpc_64 ( ) ;
return ;
}
# endif
/* OK, we have a 32-bit inferior. */
# ifdef __ALTIVEC__
init_registers_powerpc_32 ( ) ;
# else
# ifdef __SPE__
init_registers_powerpc_e500 ( ) ;
# else
init_registers_ppc ( ) ;
# endif
ppc_get_hwcap ( & ppc_hwcap ) ;
if ( ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC )
init_registers_powerpc_32 ( ) ;
/* On 32-bit machines, check for SPE registers.
Set the low target ' s regmap field as appropriately . */
# ifndef __powerpc64__
the_low_target . regmap = ppc_regmap ;
if ( ppc_hwcap & PPC_FEATURE_HAS_SPE )
{
init_registers_powerpc_e500 ( ) ;
the_low_target . regmap = ppc_regmap_e500 ;
}
# endif
}
@ -232,8 +291,6 @@ static void ppc_fill_gregset (void *buf)
ppc_collect_ptrace_register ( i , ( char * ) buf + ppc_regmap [ i ] ) ;
}
# ifdef __ALTIVEC__
# ifndef PTRACE_GETVRREGS
# define PTRACE_GETVRREGS 18
# define PTRACE_SETVRREGS 19
@ -247,6 +304,9 @@ ppc_fill_vrregset (void *buf)
int i , base ;
char * regset = buf ;
if ( ! ( ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC ) )
return ;
base = find_regno ( " vr0 " ) ;
for ( i = 0 ; i < 32 ; i + + )
collect_register ( base + i , & regset [ i * 16 ] ) ;
@ -261,6 +321,9 @@ ppc_store_vrregset (const void *buf)
int i , base ;
const char * regset = buf ;
if ( ! ( ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC ) )
return ;
base = find_regno ( " vr0 " ) ;
for ( i = 0 ; i < 32 ; i + + )
supply_register ( base + i , & regset [ i * 16 ] ) ;
@ -269,10 +332,6 @@ ppc_store_vrregset (const void *buf)
supply_register_by_name ( " vrsave " , & regset [ 33 * 16 ] ) ;
}
# endif /* __ALTIVEC__ */
# ifdef __SPE__
# ifndef PTRACE_GETEVRREGS
# define PTRACE_GETEVRREGS 20
# define PTRACE_SETEVRREGS 21
@ -291,6 +350,9 @@ ppc_fill_evrregset (void *buf)
int i , ev0 ;
struct gdb_evrregset_t * regset = buf ;
if ( ! ( ppc_hwcap & PPC_FEATURE_HAS_SPE ) )
return ;
ev0 = find_regno ( " ev0h " ) ;
for ( i = 0 ; i < 32 ; i + + )
collect_register ( ev0 + i , & regset - > evr [ i ] ) ;
@ -305,6 +367,9 @@ ppc_store_evrregset (const void *buf)
int i , ev0 ;
const struct gdb_evrregset_t * regset = buf ;
if ( ! ( ppc_hwcap & PPC_FEATURE_HAS_SPE ) )
return ;
ev0 = find_regno ( " ev0h " ) ;
for ( i = 0 ; i < 32 ; i + + )
supply_register ( ev0 + i , & regset - > evr [ i ] ) ;
@ -312,21 +377,16 @@ ppc_store_evrregset (const void *buf)
supply_register_by_name ( " acc " , & regset - > acc ) ;
supply_register_by_name ( " spefscr " , & regset - > spefscr ) ;
}
# endif /* __SPE__ */
struct regset_info target_regsets [ ] = {
/* List the extra register sets before GENERAL_REGS. That way we will
fetch them every time , but still fall back to PTRACE_PEEKUSER for the
general registers . Some kernels support these , but not the newer
PPC_PTRACE_GETREGS . */
# ifdef __ALTIVEC__
{ PTRACE_GETVRREGS , PTRACE_SETVRREGS , SIZEOF_VRREGS , EXTENDED_REGS ,
ppc_fill_vrregset , ppc_store_vrregset } ,
# endif
# ifdef __SPE__
{ PTRACE_GETEVRREGS , PTRACE_SETEVRREGS , 32 * 4 + 8 + 4 , EXTENDED_REGS ,
ppc_fill_evrregset , ppc_store_evrregset } ,
# endif
{ 0 , 0 , 0 , GENERAL_REGS , ppc_fill_gregset , NULL } ,
{ 0 , 0 , - 1 , - 1 , NULL , NULL }
} ;