407 lines
14 KiB
C
407 lines
14 KiB
C
|
/*
|
|||
|
* Alpha register context support
|
|||
|
*
|
|||
|
* Copyright (C) 2004 Vincent B<EFBFBD>ron
|
|||
|
*
|
|||
|
* This library is free software; you can redistribute it and/or
|
|||
|
* modify it under the terms of the GNU Lesser General Public
|
|||
|
* License as published by the Free Software Foundation; either
|
|||
|
* version 2.1 of the License, or (at your option) any later version.
|
|||
|
*
|
|||
|
* This library 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
|
|||
|
* Lesser General Public License for more details.
|
|||
|
*
|
|||
|
* You should have received a copy of the GNU Lesser General Public
|
|||
|
* License along with this library; if not, write to the Free Software
|
|||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
*/
|
|||
|
|
|||
|
#include "config.h"
|
|||
|
|
|||
|
#ifdef __ALPHA__
|
|||
|
|
|||
|
#include <assert.h>
|
|||
|
#include <errno.h>
|
|||
|
#ifdef HAVE_SYS_REG_H
|
|||
|
# include <sys/reg.h>
|
|||
|
#endif
|
|||
|
#include <stdarg.h>
|
|||
|
#include <unistd.h>
|
|||
|
#ifdef HAVE_SYS_PTRACE_H
|
|||
|
# include <sys/ptrace.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include "file.h"
|
|||
|
#include "thread.h"
|
|||
|
#include "request.h"
|
|||
|
|
|||
|
#ifdef HAVE_SYS_USER_H
|
|||
|
# include <sys/user.h>
|
|||
|
#endif
|
|||
|
|
|||
|
/* user definitions from asm/user.h */
|
|||
|
struct kernel_user_struct
|
|||
|
{
|
|||
|
unsigned long regs[EF_SIZE/8+32];
|
|||
|
size_t u_tsize;
|
|||
|
size_t u_dsize;
|
|||
|
size_t u_ssize;
|
|||
|
unsigned long start_code;
|
|||
|
unsigned long start_data;
|
|||
|
unsigned long start_stack;
|
|||
|
long int signal;
|
|||
|
struct regs * u_ar0;
|
|||
|
unsigned long magic;
|
|||
|
char u_comm[32];
|
|||
|
};
|
|||
|
|
|||
|
/* get thread context */
|
|||
|
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
|
|||
|
{
|
|||
|
int pid = get_ptrace_pid(thread);
|
|||
|
if (flags & CONTEXT_FULL)
|
|||
|
{
|
|||
|
struct kernel_user_struct regs;
|
|||
|
if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
|
|||
|
if (flags & CONTEXT_INTEGER)
|
|||
|
{
|
|||
|
context->IntV0 = regs.regs[EF_V0];
|
|||
|
context->IntT0 = regs.regs[EF_T0];
|
|||
|
context->IntT1 = regs.regs[EF_T1];
|
|||
|
context->IntT2 = regs.regs[EF_T2];
|
|||
|
context->IntT3 = regs.regs[EF_T3];
|
|||
|
context->IntT4 = regs.regs[EF_T4];
|
|||
|
context->IntT5 = regs.regs[EF_T5];
|
|||
|
context->IntT6 = regs.regs[EF_T6];
|
|||
|
context->IntT7 = regs.regs[EF_T7];
|
|||
|
context->IntS0 = regs.regs[EF_S0];
|
|||
|
context->IntS1 = regs.regs[EF_S1];
|
|||
|
context->IntS2 = regs.regs[EF_S2];
|
|||
|
context->IntS3 = regs.regs[EF_S3];
|
|||
|
context->IntS4 = regs.regs[EF_S4];
|
|||
|
context->IntS5 = regs.regs[EF_S5];
|
|||
|
context->IntFp = regs.regs[EF_S6];
|
|||
|
context->IntA0 = regs.regs[EF_A0];
|
|||
|
context->IntA1 = regs.regs[EF_A1];
|
|||
|
context->IntA2 = regs.regs[EF_A2];
|
|||
|
context->IntA3 = regs.regs[EF_A3];
|
|||
|
context->IntA4 = regs.regs[EF_A4];
|
|||
|
context->IntA5 = regs.regs[EF_A5];
|
|||
|
context->IntT8 = regs.regs[EF_T8];
|
|||
|
context->IntT9 = regs.regs[EF_T9];
|
|||
|
context->IntT10 = regs.regs[EF_T10];
|
|||
|
context->IntT11 = regs.regs[EF_T11];
|
|||
|
context->IntT12 = regs.regs[EF_T12];
|
|||
|
context->IntAt = regs.regs[EF_AT];
|
|||
|
context->IntZero = 0;
|
|||
|
}
|
|||
|
if (flags & CONTEXT_CONTROL)
|
|||
|
{
|
|||
|
context->IntRa = regs.regs[EF_RA];
|
|||
|
context->IntGp = regs.regs[EF_GP];
|
|||
|
context->IntSp = regs.regs[EF_SP];
|
|||
|
context->Fir = regs.regs[EF_PC];
|
|||
|
context->Psr = regs.regs[EF_PS];
|
|||
|
}
|
|||
|
if (flags & CONTEXT_FLOATING_POINT)
|
|||
|
{
|
|||
|
context->FltF0 = regs.regs[EF_SIZE/8+0];
|
|||
|
context->FltF1 = regs.regs[EF_SIZE/8+1];
|
|||
|
context->FltF2 = regs.regs[EF_SIZE/8+2];
|
|||
|
context->FltF3 = regs.regs[EF_SIZE/8+3];
|
|||
|
context->FltF4 = regs.regs[EF_SIZE/8+4];
|
|||
|
context->FltF5 = regs.regs[EF_SIZE/8+5];
|
|||
|
context->FltF6 = regs.regs[EF_SIZE/8+6];
|
|||
|
context->FltF7 = regs.regs[EF_SIZE/8+7];
|
|||
|
context->FltF8 = regs.regs[EF_SIZE/8+8];
|
|||
|
context->FltF9 = regs.regs[EF_SIZE/8+9];
|
|||
|
context->FltF10 = regs.regs[EF_SIZE/8+10];
|
|||
|
context->FltF11 = regs.regs[EF_SIZE/8+11];
|
|||
|
context->FltF12 = regs.regs[EF_SIZE/8+12];
|
|||
|
context->FltF13 = regs.regs[EF_SIZE/8+13];
|
|||
|
context->FltF14 = regs.regs[EF_SIZE/8+14];
|
|||
|
context->FltF15 = regs.regs[EF_SIZE/8+15];
|
|||
|
context->FltF16 = regs.regs[EF_SIZE/8+16];
|
|||
|
context->FltF17 = regs.regs[EF_SIZE/8+17];
|
|||
|
context->FltF18 = regs.regs[EF_SIZE/8+18];
|
|||
|
context->FltF19 = regs.regs[EF_SIZE/8+19];
|
|||
|
context->FltF20 = regs.regs[EF_SIZE/8+20];
|
|||
|
context->FltF21 = regs.regs[EF_SIZE/8+21];
|
|||
|
context->FltF22 = regs.regs[EF_SIZE/8+22];
|
|||
|
context->FltF23 = regs.regs[EF_SIZE/8+23];
|
|||
|
context->FltF24 = regs.regs[EF_SIZE/8+24];
|
|||
|
context->FltF25 = regs.regs[EF_SIZE/8+25];
|
|||
|
context->FltF26 = regs.regs[EF_SIZE/8+26];
|
|||
|
context->FltF27 = regs.regs[EF_SIZE/8+27];
|
|||
|
context->FltF28 = regs.regs[EF_SIZE/8+28];
|
|||
|
context->FltF29 = regs.regs[EF_SIZE/8+29];
|
|||
|
context->FltF30 = regs.regs[EF_SIZE/8+30];
|
|||
|
context->FltF31 = 0;
|
|||
|
context->Fpcr = regs.regs[EF_SIZE/8+31];
|
|||
|
context->SoftFpcr = 0; /* FIXME */
|
|||
|
}
|
|||
|
if (ptrace( PTRACE_SETREGS, pid, 0, ®s ) == -1) goto error;
|
|||
|
}
|
|||
|
return;
|
|||
|
error:
|
|||
|
file_set_error();
|
|||
|
}
|
|||
|
|
|||
|
/* set a thread context */
|
|||
|
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
|
|||
|
{
|
|||
|
int pid = get_ptrace_pid(thread);
|
|||
|
if (flags & CONTEXT_FULL)
|
|||
|
{
|
|||
|
struct kernel_user_struct regs;
|
|||
|
if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
|
|||
|
if (flags & CONTEXT_INTEGER)
|
|||
|
{
|
|||
|
regs.regs[EF_V0] = context->IntV0;
|
|||
|
regs.regs[EF_T0] = context->IntT0;
|
|||
|
regs.regs[EF_T1] = context->IntT1;
|
|||
|
regs.regs[EF_T2] = context->IntT2;
|
|||
|
regs.regs[EF_T3] = context->IntT3;
|
|||
|
regs.regs[EF_T4] = context->IntT4;
|
|||
|
regs.regs[EF_T5] = context->IntT5;
|
|||
|
regs.regs[EF_T6] = context->IntT6;
|
|||
|
regs.regs[EF_T7] = context->IntT7;
|
|||
|
regs.regs[EF_S0] = context->IntS0;
|
|||
|
regs.regs[EF_S1] = context->IntS1;
|
|||
|
regs.regs[EF_S2] = context->IntS2;
|
|||
|
regs.regs[EF_S3] = context->IntS3;
|
|||
|
regs.regs[EF_S4] = context->IntS4;
|
|||
|
regs.regs[EF_S5] = context->IntS5;
|
|||
|
regs.regs[EF_S6] = context->IntFp;
|
|||
|
regs.regs[EF_A0] = context->IntA0;
|
|||
|
regs.regs[EF_A1] = context->IntA1;
|
|||
|
regs.regs[EF_A2] = context->IntA2;
|
|||
|
regs.regs[EF_A3] = context->IntA3;
|
|||
|
regs.regs[EF_A4] = context->IntA4;
|
|||
|
regs.regs[EF_A5] = context->IntA5;
|
|||
|
regs.regs[EF_T8] = context->IntT8;
|
|||
|
regs.regs[EF_T9] = context->IntT9;
|
|||
|
regs.regs[EF_T10] = context->IntT10;
|
|||
|
regs.regs[EF_T11] = context->IntT11;
|
|||
|
regs.regs[EF_T12] = context->IntT12;
|
|||
|
regs.regs[EF_AT] = context->IntAt;
|
|||
|
}
|
|||
|
if (flags & CONTEXT_CONTROL)
|
|||
|
{
|
|||
|
regs.regs[EF_RA] = context->IntRa;
|
|||
|
regs.regs[EF_GP] = context->IntGp;
|
|||
|
regs.regs[EF_SP] = context->IntSp;
|
|||
|
regs.regs[EF_PC] = context->Fir;
|
|||
|
regs.regs[EF_PS] = context->Psr;
|
|||
|
}
|
|||
|
if (flags & CONTEXT_FLOATING_POINT)
|
|||
|
{
|
|||
|
regs.regs[EF_SIZE/8+0] = context->FltF0;
|
|||
|
regs.regs[EF_SIZE/8+1] = context->FltF1;
|
|||
|
regs.regs[EF_SIZE/8+2] = context->FltF2;
|
|||
|
regs.regs[EF_SIZE/8+3] = context->FltF3;
|
|||
|
regs.regs[EF_SIZE/8+4] = context->FltF4;
|
|||
|
regs.regs[EF_SIZE/8+5] = context->FltF5;
|
|||
|
regs.regs[EF_SIZE/8+6] = context->FltF6;
|
|||
|
regs.regs[EF_SIZE/8+7] = context->FltF7;
|
|||
|
regs.regs[EF_SIZE/8+8] = context->FltF8;
|
|||
|
regs.regs[EF_SIZE/8+9] = context->FltF9;
|
|||
|
regs.regs[EF_SIZE/8+10] = context->FltF10;
|
|||
|
regs.regs[EF_SIZE/8+11] = context->FltF11;
|
|||
|
regs.regs[EF_SIZE/8+12] = context->FltF12;
|
|||
|
regs.regs[EF_SIZE/8+13] = context->FltF13;
|
|||
|
regs.regs[EF_SIZE/8+14] = context->FltF14;
|
|||
|
regs.regs[EF_SIZE/8+15] = context->FltF15;
|
|||
|
regs.regs[EF_SIZE/8+16] = context->FltF16;
|
|||
|
regs.regs[EF_SIZE/8+17] = context->FltF17;
|
|||
|
regs.regs[EF_SIZE/8+18] = context->FltF18;
|
|||
|
regs.regs[EF_SIZE/8+19] = context->FltF19;
|
|||
|
regs.regs[EF_SIZE/8+20] = context->FltF20;
|
|||
|
regs.regs[EF_SIZE/8+21] = context->FltF21;
|
|||
|
regs.regs[EF_SIZE/8+22] = context->FltF22;
|
|||
|
regs.regs[EF_SIZE/8+23] = context->FltF23;
|
|||
|
regs.regs[EF_SIZE/8+24] = context->FltF24;
|
|||
|
regs.regs[EF_SIZE/8+25] = context->FltF25;
|
|||
|
regs.regs[EF_SIZE/8+26] = context->FltF26;
|
|||
|
regs.regs[EF_SIZE/8+27] = context->FltF27;
|
|||
|
regs.regs[EF_SIZE/8+28] = context->FltF28;
|
|||
|
regs.regs[EF_SIZE/8+29] = context->FltF29;
|
|||
|
regs.regs[EF_SIZE/8+30] = context->FltF30;
|
|||
|
regs.regs[EF_SIZE/8+31] = context->Fpcr;
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
error:
|
|||
|
file_set_error();
|
|||
|
}
|
|||
|
|
|||
|
/* copy a context structure according to the flags */
|
|||
|
static void copy_context( CONTEXT *to, const CONTEXT *from, int flags )
|
|||
|
{
|
|||
|
if (flags & CONTEXT_CONTROL)
|
|||
|
{
|
|||
|
to->IntRa = from->IntRa;
|
|||
|
to->IntGp = from->IntGp;
|
|||
|
to->IntSp = from->IntSp;
|
|||
|
to->Fir = from->Fir;
|
|||
|
to->Psr = from->Psr;
|
|||
|
}
|
|||
|
if (flags & CONTEXT_INTEGER)
|
|||
|
{
|
|||
|
to->IntV0 = from->IntV0;
|
|||
|
to->IntT0 = from->IntT0;
|
|||
|
to->IntT1 = from->IntT1;
|
|||
|
to->IntT2 = from->IntT2;
|
|||
|
to->IntT3 = from->IntT3;
|
|||
|
to->IntT4 = from->IntT4;
|
|||
|
to->IntT5 = from->IntT5;
|
|||
|
to->IntT6 = from->IntT6;
|
|||
|
to->IntT7 = from->IntT7;
|
|||
|
to->IntS0 = from->IntS0;
|
|||
|
to->IntS1 = from->IntS1;
|
|||
|
to->IntS2 = from->IntS2;
|
|||
|
to->IntS3 = from->IntS3;
|
|||
|
to->IntS4 = from->IntS4;
|
|||
|
to->IntS5 = from->IntS5;
|
|||
|
to->IntFp = from->IntFp;
|
|||
|
to->IntA0 = from->IntA0;
|
|||
|
to->IntA1 = from->IntA1;
|
|||
|
to->IntA2 = from->IntA2;
|
|||
|
to->IntA3 = from->IntA3;
|
|||
|
to->IntA4 = from->IntA4;
|
|||
|
to->IntA5 = from->IntA5;
|
|||
|
to->IntT8 = from->IntT8;
|
|||
|
to->IntT9 = from->IntT9;
|
|||
|
to->IntT10 = from->IntT10;
|
|||
|
to->IntT11 = from->IntT11;
|
|||
|
to->IntT12 = from->IntT12;
|
|||
|
to->IntAt = from->IntAt;
|
|||
|
to->IntZero = from->IntZero;
|
|||
|
}
|
|||
|
if (flags & CONTEXT_FLOATING_POINT)
|
|||
|
{
|
|||
|
to->FltF0 = from->FltF0;
|
|||
|
to->FltF1 = from->FltF1;
|
|||
|
to->FltF2 = from->FltF2;
|
|||
|
to->FltF3 = from->FltF3;
|
|||
|
to->FltF4 = from->FltF4;
|
|||
|
to->FltF5 = from->FltF5;
|
|||
|
to->FltF6 = from->FltF6;
|
|||
|
to->FltF7 = from->FltF7;
|
|||
|
to->FltF8 = from->FltF8;
|
|||
|
to->FltF9 = from->FltF9;
|
|||
|
to->FltF10 = from->FltF10;
|
|||
|
to->FltF11 = from->FltF11;
|
|||
|
to->FltF12 = from->FltF12;
|
|||
|
to->FltF13 = from->FltF13;
|
|||
|
to->FltF14 = from->FltF14;
|
|||
|
to->FltF15 = from->FltF15;
|
|||
|
to->FltF16 = from->FltF16;
|
|||
|
to->FltF17 = from->FltF17;
|
|||
|
to->FltF18 = from->FltF18;
|
|||
|
to->FltF19 = from->FltF19;
|
|||
|
to->FltF20 = from->FltF20;
|
|||
|
to->FltF21 = from->FltF21;
|
|||
|
to->FltF22 = from->FltF22;
|
|||
|
to->FltF23 = from->FltF23;
|
|||
|
to->FltF24 = from->FltF24;
|
|||
|
to->FltF25 = from->FltF25;
|
|||
|
to->FltF26 = from->FltF26;
|
|||
|
to->FltF27 = from->FltF27;
|
|||
|
to->FltF28 = from->FltF28;
|
|||
|
to->FltF29 = from->FltF29;
|
|||
|
to->FltF30 = from->FltF30;
|
|||
|
to->FltF31 = from->FltF31;
|
|||
|
to->Fpcr = from->Fpcr;
|
|||
|
to->SoftFpcr = from->SoftFpcr;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* retrieve the current instruction pointer of a thread */
|
|||
|
void *get_thread_ip( struct thread *thread )
|
|||
|
{
|
|||
|
CONTEXT context;
|
|||
|
context.Fir = 0;
|
|||
|
if (suspend_for_ptrace( thread ))
|
|||
|
{
|
|||
|
get_thread_context( thread, CONTEXT_CONTROL, &context );
|
|||
|
resume_after_ptrace( thread );
|
|||
|
}
|
|||
|
return (void *)context.Fir;
|
|||
|
}
|
|||
|
|
|||
|
/* determine if we should continue the thread in single-step mode */
|
|||
|
int get_thread_single_step( struct thread *thread )
|
|||
|
{
|
|||
|
return 0; /* FIXME */
|
|||
|
}
|
|||
|
|
|||
|
/* send a signal to a specific thread */
|
|||
|
int tkill( int pid, int sig )
|
|||
|
{
|
|||
|
/* FIXME: should do something here */
|
|||
|
errno = ENOSYS;
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
/* retrieve the current context of a thread */
|
|||
|
DECL_HANDLER(get_thread_context)
|
|||
|
{
|
|||
|
struct thread *thread;
|
|||
|
void *data;
|
|||
|
int flags = req->flags & ~CONTEXT_ALPHA; /* get rid of CPU id */
|
|||
|
|
|||
|
if (get_reply_max_size() < sizeof(CONTEXT))
|
|||
|
{
|
|||
|
set_error( STATUS_INVALID_PARAMETER );
|
|||
|
return;
|
|||
|
}
|
|||
|
if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
|
|||
|
|
|||
|
if ((data = set_reply_data_size( sizeof(CONTEXT) )))
|
|||
|
{
|
|||
|
if (thread->context) /* thread is inside an exception event */
|
|||
|
{
|
|||
|
copy_context( data, thread->context, flags );
|
|||
|
flags = 0;
|
|||
|
}
|
|||
|
if (flags && suspend_for_ptrace( thread ))
|
|||
|
{
|
|||
|
get_thread_context( thread, flags, data );
|
|||
|
resume_after_ptrace( thread );
|
|||
|
}
|
|||
|
}
|
|||
|
release_object( thread );
|
|||
|
}
|
|||
|
|
|||
|
/* set the current context of a thread */
|
|||
|
DECL_HANDLER(set_thread_context)
|
|||
|
{
|
|||
|
struct thread *thread;
|
|||
|
int flags = req->flags & ~CONTEXT_ALPHA; /* get rid of CPU id */
|
|||
|
|
|||
|
if (get_req_data_size() < sizeof(CONTEXT))
|
|||
|
{
|
|||
|
set_error( STATUS_INVALID_PARAMETER );
|
|||
|
return;
|
|||
|
}
|
|||
|
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
|
|||
|
{
|
|||
|
if (thread->context) /* thread is inside an exception event */
|
|||
|
{
|
|||
|
copy_context( thread->context, get_req_data(), flags );
|
|||
|
flags = 0;
|
|||
|
}
|
|||
|
if (flags && suspend_for_ptrace( thread ))
|
|||
|
{
|
|||
|
set_thread_context( thread, flags, get_req_data() );
|
|||
|
resume_after_ptrace( thread );
|
|||
|
}
|
|||
|
release_object( thread );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif /* __ALPHA__ */
|