1999-02-19 03:21:36 +03:00
/*
* Copyright ( c ) 1991 , 1992 Paul Kranenburg < pk @ cs . few . eur . nl >
* Copyright ( c ) 1993 Branko Lankester < branko @ hacktic . nl >
* Copyright ( c ) 1993 , 1994 , 1995 , 1996 Rick Sladkey < jrs @ world . std . com >
1999-12-23 17:20:14 +03:00
* Copyright ( c ) 1996 - 1999 Wichert Akkerman < wichert @ cistron . nl >
* Copyright ( c ) 1999 IBM Deutschland Entwicklung GmbH , IBM Corporation
* Linux for s390 port by D . J . Barrow
* < barrow_dj @ mail . yahoo . com , djbarrow @ de . ibm . com >
1999-02-19 03:21:36 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* $ Id $
*/
# include "defs.h"
2003-01-09 09:53:34 +03:00
# include <signal.h>
# include <sys/syscall.h>
1999-02-19 03:21:36 +03:00
# include <sys/user.h>
# include <sys/param.h>
# include <fcntl.h>
2001-07-10 17:48:44 +04:00
# if HAVE_SYS_UIO_H
# include <sys/uio.h>
# endif
1999-02-19 03:21:36 +03:00
# ifdef SUNOS4
# include <machine/reg.h>
# include <a.out.h>
# include <link.h>
# endif /* SUNOS4 */
1999-07-13 19:45:02 +04:00
2000-06-27 21:33:32 +04:00
# if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
1999-02-19 03:21:36 +03:00
# include <linux/ptrace.h>
2002-12-16 23:40:54 +03:00
# endif
1999-07-13 19:45:02 +04:00
2000-02-04 00:58:30 +03:00
# if defined(LINUX) && defined(IA64)
2003-01-09 09:53:34 +03:00
# include <asm / ptrace_offsets.h>
# include <asm / rse.h>
2000-02-04 00:58:30 +03:00
# endif
1999-07-13 19:45:02 +04:00
# ifdef HAVE_SYS_REG_H
# include <sys/reg.h>
# define PTRACE_PEEKUSR PTRACE_PEEKUSER
2000-02-20 02:59:03 +03:00
# elif defined(HAVE_LINUX_PTRACE_H)
# undef PTRACE_SYSCALL
# include <linux/ptrace.h>
1999-05-09 04:29:58 +04:00
# endif
1999-02-19 03:21:36 +03:00
# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
# include <sys/utsname.h>
# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1999-08-30 03:15:07 +04:00
# if defined(LINUX) && defined(SPARC)
2003-01-30 23:15:19 +03:00
# define fpq kernel_fpq
# define fq kernel_fq
# define fpu kernel_fpu
# include <asm / reg.h>
# undef fpq
# undef fq
# undef fpu
1999-08-30 03:15:07 +04:00
# if !defined(__GLIBC__)
1999-02-19 03:21:36 +03:00
# include <linux/unistd.h>
# define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
type5 , arg5 , syscall ) \
type name ( type1 arg1 , type2 arg2 , type3 arg3 , type4 arg4 , type5 arg5 ) \
{ \
long __res ; \
\
__asm__ volatile ( " or %%g0, %1, %%o0 \n \t " \
" or %%g0, %2, %%o1 \n \t " \
" or %%g0, %3, %%o2 \n \t " \
" or %%g0, %4, %%o3 \n \t " \
" or %%g0, %5, %%o4 \n \t " \
" or %%g0, %6, %%g1 \n \t " \
" t 0x10 \n \t " \
" bcc 1f \n \t " \
" or %%g0, %%o0, %0 \n \t " \
" sub %%g0, %%o0, %0 \n \t " \
" 1: \n \t " \
: " =r " ( __res ) \
: " 0 " ( ( long ) ( arg1 ) ) , " 1 " ( ( long ) ( arg2 ) ) , \
" 2 " ( ( long ) ( arg3 ) ) , " 3 " ( ( long ) ( arg4 ) ) , " 4 " ( ( long ) ( arg5 ) ) , \
" i " ( __NR_ # # syscall ) \
: " g1 " , " o0 " , " o1 " , " o2 " , " o3 " , " o4 " ) ; \
if ( __res > = 0 ) \
return ( type ) __res ; \
errno = - __res ; \
return - 1 ; \
}
static _hack_syscall5 ( int , _ptrace , int , __request , int , __pid , int , __addr , int , __data , int , __addr2 , ptrace )
# define _ptrace
# endif
1999-08-30 03:15:07 +04:00
# endif
1999-02-19 03:21:36 +03:00
/* macros */
# ifndef MAX
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
# endif
# ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
# endif
void
tv_tv ( tv , a , b )
struct timeval * tv ;
int a ;
int b ;
{
tv - > tv_sec = a ;
tv - > tv_usec = b ;
}
int
tv_nz ( a )
struct timeval * a ;
{
return a - > tv_sec | | a - > tv_usec ;
}
int
tv_cmp ( a , b )
struct timeval * a , * b ;
{
if ( a - > tv_sec < b - > tv_sec
| | ( a - > tv_sec = = b - > tv_sec & & a - > tv_usec < b - > tv_usec ) )
return - 1 ;
if ( a - > tv_sec > b - > tv_sec
| | ( a - > tv_sec = = b - > tv_sec & & a - > tv_usec > b - > tv_usec ) )
return 1 ;
return 0 ;
}
double
tv_float ( tv )
struct timeval * tv ;
{
return tv - > tv_sec + tv - > tv_usec / 1000000.0 ;
}
void
tv_add ( tv , a , b )
struct timeval * tv , * a , * b ;
{
tv - > tv_sec = a - > tv_sec + b - > tv_sec ;
tv - > tv_usec = a - > tv_usec + b - > tv_usec ;
if ( tv - > tv_usec > 1000000 ) {
tv - > tv_sec + + ;
tv - > tv_usec - = 1000000 ;
}
}
void
tv_sub ( tv , a , b )
struct timeval * tv , * a , * b ;
{
tv - > tv_sec = a - > tv_sec - b - > tv_sec ;
tv - > tv_usec = a - > tv_usec - b - > tv_usec ;
if ( ( ( long ) tv - > tv_usec ) < 0 ) {
tv - > tv_sec - - ;
tv - > tv_usec + = 1000000 ;
}
}
void
tv_div ( tv , a , n )
struct timeval * tv , * a ;
int n ;
{
tv - > tv_usec = ( a - > tv_sec % n * 1000000 + a - > tv_usec + n / 2 ) / n ;
tv - > tv_sec = a - > tv_sec / n + tv - > tv_usec / 1000000 ;
tv - > tv_usec % = 1000000 ;
}
void
tv_mul ( tv , a , n )
struct timeval * tv , * a ;
int n ;
{
tv - > tv_usec = a - > tv_usec * n ;
tv - > tv_sec = a - > tv_sec * n + a - > tv_usec / 1000000 ;
tv - > tv_usec % = 1000000 ;
}
char *
xlookup ( xlat , val )
struct xlat * xlat ;
int val ;
{
for ( ; xlat - > str ! = NULL ; xlat + + )
if ( xlat - > val = = val )
return xlat - > str ;
return NULL ;
}
/*
* Print entry in struct xlat table , if there .
*/
void
printxval ( xlat , val , dflt )
struct xlat * xlat ;
int val ;
char * dflt ;
{
char * str = xlookup ( xlat , val ) ;
if ( str )
tprintf ( " %s " , str ) ;
else
tprintf ( " %#x /* %s */ " , val , dflt ) ;
}
/*
* Interpret ` xlat ' as an array of flags
* print the entries whose bits are on in ` flags '
* return # of flags printed .
*/
int
addflags ( xlat , flags )
struct xlat * xlat ;
int flags ;
{
int n ;
for ( n = 0 ; xlat - > str ; xlat + + ) {
if ( xlat - > val & & ( flags & xlat - > val ) = = xlat - > val ) {
tprintf ( " |%s " , xlat - > str ) ;
flags & = ~ xlat - > val ;
n + + ;
}
}
if ( flags ) {
tprintf ( " |%#x " , flags ) ;
n + + ;
}
return n ;
}
int
printflags ( xlat , flags )
struct xlat * xlat ;
int flags ;
{
int n ;
char * sep ;
if ( flags = = 0 & & xlat - > val = = 0 ) {
tprintf ( " %s " , xlat - > str ) ;
return 1 ;
}
sep = " " ;
for ( n = 0 ; xlat - > str ; xlat + + ) {
if ( xlat - > val & & ( flags & xlat - > val ) = = xlat - > val ) {
tprintf ( " %s%s " , sep , xlat - > str ) ;
flags & = ~ xlat - > val ;
sep = " | " ;
n + + ;
}
}
if ( flags ) {
tprintf ( " %s%#x " , sep , flags ) ;
n + + ;
}
return n ;
}
void
printnum ( tcp , addr , fmt )
struct tcb * tcp ;
long addr ;
char * fmt ;
{
2003-01-14 12:59:00 +03:00
long num ;
1999-02-19 03:21:36 +03:00
if ( ! addr ) {
tprintf ( " NULL " ) ;
return ;
}
if ( umove ( tcp , addr , & num ) < 0 ) {
tprintf ( " %#lx " , addr ) ;
return ;
}
tprintf ( " [ " ) ;
tprintf ( fmt , num ) ;
tprintf ( " ] " ) ;
}
2003-11-14 01:32:27 +03:00
void
printuid ( text , uid )
const char * text ;
unsigned long uid ;
{
tprintf ( " %s " , text ) ;
tprintf ( ( uid = = - 1 ) ? " %ld " : " %lu " , uid ) ;
}
1999-02-19 03:21:36 +03:00
static char path [ MAXPATHLEN + 1 ] ;
void
string_quote ( str )
char * str ;
{
char buf [ 2 * MAXPATHLEN + 1 ] ;
char * s ;
if ( ! strpbrk ( str , " \" \' \\ " ) ) {
tprintf ( " \" %s \" " , str ) ;
return ;
}
for ( s = buf ; * str ; str + + ) {
switch ( * str ) {
case ' \" ' : case ' \' ' : case ' \\ ' :
* s + + = ' \\ ' ; * s + + = * str ; break ;
default :
* s + + = * str ; break ;
}
}
* s = ' \0 ' ;
tprintf ( " \" %s \" " , buf ) ;
}
void
printpath ( tcp , addr )
struct tcb * tcp ;
long addr ;
{
if ( umovestr ( tcp , addr , MAXPATHLEN , path ) < 0 )
tprintf ( " %#lx " , addr ) ;
else
string_quote ( path ) ;
return ;
}
void
printpathn ( tcp , addr , n )
struct tcb * tcp ;
long addr ;
int n ;
{
if ( umovestr ( tcp , addr , n , path ) < 0 )
tprintf ( " %#lx " , addr ) ;
else {
path [ n ] = ' \0 ' ;
string_quote ( path ) ;
}
}
void
printstr ( tcp , addr , len )
struct tcb * tcp ;
long addr ;
int len ;
{
static unsigned char * str = NULL ;
static char * outstr ;
int i , n , c , usehex ;
char * s , * outend ;
if ( ! addr ) {
tprintf ( " NULL " ) ;
return ;
}
if ( ! str ) {
if ( ( str = malloc ( max_strlen ) ) = = NULL
| | ( outstr = malloc ( 2 * max_strlen ) ) = = NULL ) {
fprintf ( stderr , " printstr: no memory \n " ) ;
tprintf ( " %#lx " , addr ) ;
return ;
}
}
1999-05-09 04:29:58 +04:00
outend = outstr + max_strlen * 2 - 10 ;
1999-02-19 03:21:36 +03:00
if ( len < 0 ) {
n = max_strlen ;
if ( umovestr ( tcp , addr , n , ( char * ) str ) < 0 ) {
tprintf ( " %#lx " , addr ) ;
return ;
}
}
else {
n = MIN ( len , max_strlen ) ;
if ( umoven ( tcp , addr , n , ( char * ) str ) < 0 ) {
tprintf ( " %#lx " , addr ) ;
return ;
}
}
usehex = 0 ;
if ( xflag > 1 )
usehex = 1 ;
else if ( xflag ) {
for ( i = 0 ; i < n ; i + + ) {
c = str [ i ] ;
if ( len < 0 & & c = = ' \0 ' )
break ;
if ( ! isprint ( c ) & & ! isspace ( c ) ) {
usehex = 1 ;
break ;
}
}
}
s = outstr ;
* s + + = ' \" ' ;
if ( usehex ) {
for ( i = 0 ; i < n ; i + + ) {
c = str [ i ] ;
if ( len < 0 & & c = = ' \0 ' )
break ;
sprintf ( s , " \\ x%02x " , c ) ;
s + = 4 ;
if ( s > outend )
break ;
}
}
else {
for ( i = 0 ; i < n ; i + + ) {
c = str [ i ] ;
if ( len < 0 & & c = = ' \0 ' )
break ;
switch ( c ) {
case ' \" ' : case ' \' ' : case ' \\ ' :
* s + + = ' \\ ' ; * s + + = c ; break ;
case ' \f ' :
* s + + = ' \\ ' ; * s + + = ' f ' ; break ;
case ' \n ' :
* s + + = ' \\ ' ; * s + + = ' n ' ; break ;
case ' \r ' :
* s + + = ' \\ ' ; * s + + = ' r ' ; break ;
case ' \t ' :
* s + + = ' \\ ' ; * s + + = ' t ' ; break ;
case ' \v ' :
* s + + = ' \\ ' ; * s + + = ' v ' ; break ;
default :
if ( isprint ( c ) )
* s + + = c ;
else if ( i < n - 1 & & isdigit ( str [ i + 1 ] ) ) {
sprintf ( s , " \\ %03o " , c ) ;
s + = 4 ;
}
else {
sprintf ( s , " \\ %o " , c ) ;
s + = strlen ( s ) ;
}
break ;
}
if ( s > outend )
break ;
}
}
* s + + = ' \" ' ;
if ( i < len | | ( len < 0 & & ( i = = n | | s > outend ) ) ) {
* s + + = ' . ' ; * s + + = ' . ' ; * s + + = ' . ' ;
}
* s = ' \0 ' ;
tprintf ( " %s " , outstr ) ;
}
2001-07-10 17:48:44 +04:00
# if HAVE_SYS_UIO_H
void
dumpiov ( tcp , len , addr )
struct tcb * tcp ;
int len ;
long addr ;
{
struct iovec * iov ;
int i ;
2002-12-16 23:40:54 +03:00
2001-07-10 17:48:44 +04:00
if ( ( iov = ( struct iovec * ) malloc ( len * sizeof * iov ) ) = = NULL ) {
fprintf ( stderr , " dump: No memory " ) ;
return ;
}
if ( umoven ( tcp , addr ,
len * sizeof * iov , ( char * ) iov ) > = 0 ) {
2002-12-16 23:40:54 +03:00
2001-07-10 17:48:44 +04:00
for ( i = 0 ; i < len ; i + + ) {
/* include the buffer number to make it easy to
* match up the trace with the source */
tprintf ( " * %lu bytes in buffer %d \n " ,
( unsigned long ) iov [ i ] . iov_len , i ) ;
dumpstr ( tcp , ( long ) iov [ i ] . iov_base ,
iov [ i ] . iov_len ) ;
}
}
free ( ( char * ) iov ) ;
2002-12-16 23:40:54 +03:00
2001-07-10 17:48:44 +04:00
}
# endif
1999-02-19 03:21:36 +03:00
void
dumpstr ( tcp , addr , len )
struct tcb * tcp ;
long addr ;
int len ;
{
static int strsize = - 1 ;
static unsigned char * str ;
static char outstr [ 80 ] ;
char * s ;
int i , j ;
if ( strsize < len ) {
if ( str )
free ( str ) ;
if ( ( str = malloc ( len ) ) = = NULL ) {
fprintf ( stderr , " dump: no memory \n " ) ;
return ;
}
strsize = len ;
}
if ( umoven ( tcp , addr , len , ( char * ) str ) < 0 )
return ;
for ( i = 0 ; i < len ; i + = 16 ) {
s = outstr ;
sprintf ( s , " | %05x " , i ) ;
s + = 9 ;
for ( j = 0 ; j < 16 ; j + + ) {
if ( j = = 8 )
* s + + = ' ' ;
if ( i + j < len ) {
sprintf ( s , " %02x " , str [ i + j ] ) ;
s + = 3 ;
}
else {
* s + + = ' ' ; * s + + = ' ' ; * s + + = ' ' ;
}
}
* s + + = ' ' ; * s + + = ' ' ;
for ( j = 0 ; j < 16 ; j + + ) {
if ( j = = 8 )
* s + + = ' ' ;
if ( i + j < len ) {
if ( isprint ( str [ i + j ] ) )
* s + + = str [ i + j ] ;
else
* s + + = ' . ' ;
}
else
* s + + = ' ' ;
}
tprintf ( " %s | \n " , outstr ) ;
}
}
# define PAGMASK (~(PAGSIZ - 1))
/*
* move ` len ' bytes of data from process ` pid '
* at address ` addr ' to our space at ` laddr '
*/
int
umoven ( tcp , addr , len , laddr )
struct tcb * tcp ;
long addr ;
int len ;
char * laddr ;
{
# ifdef LINUX
int pid = tcp - > pid ;
int n , m ;
1999-03-15 22:49:42 +03:00
int started = 0 ;
1999-02-19 03:21:36 +03:00
union {
long val ;
char x [ sizeof ( long ) ] ;
} u ;
if ( addr & ( sizeof ( long ) - 1 ) ) {
/* addr not a multiple of sizeof(long) */
n = addr - ( addr & - sizeof ( long ) ) ; /* residue */
addr & = - sizeof ( long ) ; /* residue */
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
1999-03-15 22:49:42 +03:00
if ( started & & ( errno = = EPERM | | errno = = EIO ) ) {
1999-02-19 03:21:36 +03:00
/* Ran into 'end of memory' - stupid "printpath" */
return 0 ;
}
1999-03-15 22:49:42 +03:00
/* But if not started, we had a bogus address. */
1999-02-19 03:21:36 +03:00
perror ( " ptrace: umoven " ) ;
return - 1 ;
}
1999-03-15 22:49:42 +03:00
started = 1 ;
1999-02-19 03:21:36 +03:00
memcpy ( laddr , & u . x [ n ] , m = MIN ( sizeof ( long ) - n , len ) ) ;
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
while ( len ) {
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
1999-03-15 22:49:42 +03:00
if ( started & & ( errno = = EPERM | | errno = = EIO ) ) {
1999-02-19 03:21:36 +03:00
/* Ran into 'end of memory' - stupid "printpath" */
return 0 ;
}
2003-01-30 23:15:19 +03:00
if ( addr ! = 0 )
perror ( " ptrace: umoven " ) ;
1999-02-19 03:21:36 +03:00
return - 1 ;
}
1999-03-15 22:49:42 +03:00
started = 1 ;
1999-02-19 03:21:36 +03:00
memcpy ( laddr , u . x , m = MIN ( sizeof ( long ) , len ) ) ;
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
# endif /* LINUX */
# ifdef SUNOS4
int pid = tcp - > pid ;
#if 0
int n , m ;
union {
long val ;
char x [ sizeof ( long ) ] ;
} u ;
if ( addr & ( sizeof ( long ) - 1 ) ) {
/* addr not a multiple of sizeof(long) */
n = addr - ( addr & - sizeof ( long ) ) ; /* residue */
addr & = - sizeof ( long ) ; /* residue */
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
perror ( " umoven " ) ;
return - 1 ;
}
memcpy ( laddr , & u . x [ n ] , m = MIN ( sizeof ( long ) - n , len ) ) ;
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
while ( len ) {
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
perror ( " umoven " ) ;
return - 1 ;
}
memcpy ( laddr , u . x , m = MIN ( sizeof ( long ) , len ) ) ;
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
# else /* !oldway */
int n ;
while ( len ) {
n = MIN ( len , PAGSIZ ) ;
n = MIN ( n , ( ( addr + PAGSIZ ) & PAGMASK ) - addr ) ;
if ( ptrace ( PTRACE_READDATA , pid ,
( char * ) addr , len , laddr ) < 0 ) {
perror ( " umoven: ptrace(PTRACE_READDATA, ...) " ) ;
abort ( ) ;
return - 1 ;
}
len - = n ;
addr + = n ;
laddr + = n ;
}
# endif /* !oldway */
# endif /* SUNOS4 */
2000-09-02 01:03:06 +04:00
# ifdef USE_PROCFS
1999-11-29 18:34:02 +03:00
# ifdef HAVE_MP_PROCFS
2001-05-15 18:53:43 +04:00
int fd = tcp - > pfd_as ;
1999-08-30 03:15:07 +04:00
# else
2001-05-15 18:53:43 +04:00
int fd = tcp - > pfd ;
1999-02-19 03:21:36 +03:00
# endif
2001-05-15 18:53:43 +04:00
lseek ( fd , addr , SEEK_SET ) ;
if ( read ( fd , laddr , len ) = = - 1 )
1999-02-19 03:21:36 +03:00
return - 1 ;
2000-09-02 01:03:06 +04:00
# endif /* USE_PROCFS */
1999-02-19 03:21:36 +03:00
return 0 ;
}
/*
* like ` umove ' but make the additional effort of looking
* for a terminating zero byte .
*/
int
umovestr ( tcp , addr , len , laddr )
struct tcb * tcp ;
long addr ;
int len ;
char * laddr ;
{
2000-09-02 01:03:06 +04:00
# ifdef USE_PROCFS
2001-05-15 18:53:43 +04:00
# ifdef HAVE_MP_PROCFS
int fd = tcp - > pfd_as ;
# else
int fd = tcp - > pfd ;
# endif
/* Some systems (e.g. FreeBSD) can be upset if we read off the
end of valid memory , avoid this by trying to read up
to page boundaries . But we don ' t know what a page is ( and
getpagesize ( 2 ) ( if it exists ) doesn ' t necessarily return
hardware page size ) . Assume all pages > = 1024 ( a - historical
I know ) */
int page = 1024 ; /* How to find this? */
int move = page - ( addr & ( page - 1 ) ) ;
int left = len ;
lseek ( fd , addr , SEEK_SET ) ;
while ( left ) {
if ( move > left ) move = left ;
2001-10-16 14:20:22 +04:00
if ( ( move = read ( fd , laddr , move ) ) < = 0 )
2001-05-15 18:53:43 +04:00
return left ! = len ? 0 : - 1 ;
if ( memchr ( laddr , 0 , move ) ) break ;
left - = move ;
laddr + = move ;
addr + = move ;
move = page ;
}
2000-09-02 01:03:06 +04:00
# else /* !USE_PROCFS */
1999-03-15 22:49:42 +03:00
int started = 0 ;
1999-02-19 03:21:36 +03:00
int pid = tcp - > pid ;
int i , n , m ;
union {
long val ;
char x [ sizeof ( long ) ] ;
} u ;
if ( addr & ( sizeof ( long ) - 1 ) ) {
/* addr not a multiple of sizeof(long) */
n = addr - ( addr & - sizeof ( long ) ) ; /* residue */
addr & = - sizeof ( long ) ; /* residue */
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
1999-03-15 22:49:42 +03:00
if ( started & & ( errno = = EPERM | | errno = = EIO ) ) {
1999-02-19 03:21:36 +03:00
/* Ran into 'end of memory' - stupid "printpath" */
return 0 ;
}
perror ( " umovestr " ) ;
return - 1 ;
}
1999-03-15 22:49:42 +03:00
started = 1 ;
1999-02-19 03:21:36 +03:00
memcpy ( laddr , & u . x [ n ] , m = MIN ( sizeof ( long ) - n , len ) ) ;
while ( n & ( sizeof ( long ) - 1 ) )
if ( u . x [ n + + ] = = ' \0 ' )
return 0 ;
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
while ( len ) {
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
1999-03-15 22:49:42 +03:00
if ( started & & ( errno = = EPERM | | errno = = EIO ) ) {
1999-02-19 03:21:36 +03:00
/* Ran into 'end of memory' - stupid "printpath" */
return 0 ;
}
perror ( " umovestr " ) ;
return - 1 ;
}
1999-03-15 22:49:42 +03:00
started = 1 ;
1999-02-19 03:21:36 +03:00
memcpy ( laddr , u . x , m = MIN ( sizeof ( long ) , len ) ) ;
for ( i = 0 ; i < sizeof ( long ) ; i + + )
if ( u . x [ i ] = = ' \0 ' )
return 0 ;
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
2000-09-02 01:03:06 +04:00
# endif /* !USE_PROCFS */
2001-05-15 18:53:43 +04:00
return 0 ;
1999-02-19 03:21:36 +03:00
}
# ifdef LINUX
# ifndef SPARC
# define PTRACE_WRITETEXT 101
# define PTRACE_WRITEDATA 102
# endif /* !SPARC */
# endif /* LINUX */
# ifdef SUNOS4
static int
uload ( cmd , pid , addr , len , laddr )
int cmd ;
int pid ;
long addr ;
int len ;
char * laddr ;
{
#if 0
int n ;
while ( len ) {
n = MIN ( len , PAGSIZ ) ;
n = MIN ( n , ( ( addr + PAGSIZ ) & PAGMASK ) - addr ) ;
if ( ptrace ( cmd , pid , ( char * ) addr , n , laddr ) < 0 ) {
perror ( " uload: ptrace(PTRACE_WRITE, ...) " ) ;
return - 1 ;
}
len - = n ;
addr + = n ;
laddr + = n ;
}
# else
int peek , poke ;
int n , m ;
union {
long val ;
char x [ sizeof ( long ) ] ;
} u ;
if ( cmd = = PTRACE_WRITETEXT ) {
peek = PTRACE_PEEKTEXT ;
poke = PTRACE_POKETEXT ;
}
else {
peek = PTRACE_PEEKDATA ;
poke = PTRACE_POKEDATA ;
}
if ( addr & ( sizeof ( long ) - 1 ) ) {
/* addr not a multiple of sizeof(long) */
n = addr - ( addr & - sizeof ( long ) ) ; /* residue */
addr & = - sizeof ( long ) ;
errno = 0 ;
u . val = ptrace ( peek , pid , ( char * ) addr , 0 ) ;
if ( errno ) {
perror ( " uload: POKE " ) ;
return - 1 ;
}
memcpy ( & u . x [ n ] , laddr , m = MIN ( sizeof ( long ) - n , len ) ) ;
if ( ptrace ( poke , pid , ( char * ) addr , u . val ) < 0 ) {
perror ( " uload: POKE " ) ;
return - 1 ;
}
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
while ( len ) {
if ( len < sizeof ( long ) )
u . val = ptrace ( peek , pid , ( char * ) addr , 0 ) ;
memcpy ( u . x , laddr , m = MIN ( sizeof ( long ) , len ) ) ;
if ( ptrace ( poke , pid , ( char * ) addr , u . val ) < 0 ) {
perror ( " uload: POKE " ) ;
return - 1 ;
}
addr + = sizeof ( long ) , laddr + = m , len - = m ;
}
# endif
return 0 ;
}
int
tload ( pid , addr , len , laddr )
int pid ;
int addr , len ;
char * laddr ;
{
return uload ( PTRACE_WRITETEXT , pid , addr , len , laddr ) ;
}
int
dload ( pid , addr , len , laddr )
int pid ;
int addr ;
int len ;
char * laddr ;
{
return uload ( PTRACE_WRITEDATA , pid , addr , len , laddr ) ;
}
# endif /* SUNOS4 */
2000-09-02 01:03:06 +04:00
# ifndef USE_PROCFS
1999-02-19 03:21:36 +03:00
int
upeek ( pid , off , res )
int pid ;
long off ;
long * res ;
{
long val ;
# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
{
static int is_sun4m = - 1 ;
struct utsname name ;
/* Round up the usual suspects. */
if ( is_sun4m = = - 1 ) {
if ( uname ( & name ) < 0 ) {
perror ( " upeek: uname? " ) ;
exit ( 1 ) ;
}
is_sun4m = strcmp ( name . machine , " sun4m " ) = = 0 ;
if ( is_sun4m ) {
extern struct xlat struct_user_offsets [ ] ;
struct xlat * x ;
for ( x = struct_user_offsets ; x - > str ; x + + )
x - > val + = 1024 ;
}
}
if ( is_sun4m )
off + = 1024 ;
}
# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
errno = 0 ;
val = ptrace ( PTRACE_PEEKUSER , pid , ( char * ) off , 0 ) ;
if ( val = = - 1 & & errno ) {
2002-12-16 23:40:54 +03:00
char buf [ 60 ] ;
2002-09-23 19:41:01 +04:00
sprintf ( buf , " upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0) " , pid , off ) ;
2002-12-16 23:40:54 +03:00
perror ( buf ) ;
1999-02-19 03:21:36 +03:00
return - 1 ;
}
* res = val ;
return 0 ;
}
2000-09-02 01:03:06 +04:00
# endif /* !USE_PROCFS */
1999-02-19 03:21:36 +03:00
long
getpc ( tcp )
struct tcb * tcp ;
{
# ifdef LINUX
long pc ;
1999-11-01 00:15:38 +03:00
# if defined(I386)
1999-02-19 03:21:36 +03:00
if ( upeek ( tcp - > pid , 4 * EIP , & pc ) < 0 )
return - 1 ;
2002-09-23 19:41:01 +04:00
# elif defined(X86_64)
if ( upeek ( tcp - > pid , 8 * RIP , & pc ) < 0 )
return - 1 ;
2000-02-04 00:58:30 +03:00
# elif defined(IA64)
if ( upeek ( tcp - > pid , PT_B0 , & pc ) < 0 )
return - 1 ;
1999-11-01 00:15:38 +03:00
# elif defined(ARM)
1999-02-19 03:21:36 +03:00
if ( upeek ( tcp - > pid , 4 * 15 , & pc ) < 0 )
return - 1 ;
1999-11-01 00:15:38 +03:00
# elif defined(POWERPC)
2003-01-14 12:59:00 +03:00
if ( upeek ( tcp - > pid , sizeof ( unsigned long ) * PT_NIP , & pc ) < 0 )
1999-02-19 03:21:36 +03:00
return - 1 ;
1999-11-01 00:15:38 +03:00
# elif defined(M68k)
1999-02-19 03:21:36 +03:00
if ( upeek ( tcp - > pid , 4 * PT_PC , & pc ) < 0 )
return - 1 ;
1999-11-01 00:15:38 +03:00
# elif defined(ALPHA)
1999-02-19 03:21:36 +03:00
if ( upeek ( tcp - > pid , REG_PC , & pc ) < 0 )
return - 1 ;
1999-11-01 00:15:38 +03:00
# elif defined(MIPS)
if ( upeek ( tcp - > pid , REG_EPC , & pc ) < 0 )
return - 1 ;
# elif defined(SPARC)
1999-08-30 03:15:07 +04:00
struct regs regs ;
1999-02-19 03:21:36 +03:00
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 )
return - 1 ;
1999-08-30 03:15:07 +04:00
pc = regs . r_pc ;
2002-10-07 18:31:00 +04:00
# elif defined(S390) || defined(S390X)
1999-12-23 17:20:14 +03:00
if ( upeek ( tcp - > pid , PT_PSWADDR , & pc ) < 0 )
2002-10-07 18:31:00 +04:00
return - 1 ;
2001-03-27 16:17:16 +04:00
# elif defined(HPPA)
if ( upeek ( tcp - > pid , PT_IAOQ0 , & pc ) < 0 )
return - 1 ;
2002-05-01 20:39:22 +04:00
# elif defined(SH)
if ( upeek ( tcp - > pid , 4 * REG_PC , & pc ) < 0 )
return - 1 ;
2003-06-27 02:40:42 +04:00
# elif defined(SH64)
2003-06-02 23:18:58 +04:00
if ( upeek ( tcp - > pid , REG_PC , & pc ) < 0 )
return - 1 ;
1999-12-23 18:08:17 +03:00
# endif
1999-02-19 03:21:36 +03:00
return pc ;
# endif /* LINUX */
# ifdef SUNOS4
/*
* Return current program counter for ` pid '
* Assumes PC is never 0xffffffff
*/
struct regs regs ;
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
perror ( " getpc: ptrace(PTRACE_GETREGS, ...) " ) ;
return - 1 ;
}
return regs . r_pc ;
# endif /* SUNOS4 */
# ifdef SVR4
/* XXX */
return 0 ;
# endif /* SVR4 */
2000-09-02 01:03:06 +04:00
# ifdef FREEBSD
struct reg regs ;
pread ( tcp - > pfd_reg , & regs , sizeof ( regs ) , 0 ) ;
return regs . r_eip ;
# endif /* FREEBSD */
1999-02-19 03:21:36 +03:00
}
void
printcall ( tcp )
struct tcb * tcp ;
{
# ifdef LINUX
# ifdef I386
long eip ;
if ( upeek ( tcp - > pid , 4 * EIP , & eip ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , eip ) ;
2002-09-23 19:41:01 +04:00
# elif defined(X86_64)
long rip ;
if ( upeek ( tcp - > pid , 8 * RIP , & rip ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%16lx] " , rip ) ;
2003-06-04 03:28:59 +04:00
# elif defined(IA64)
2000-02-04 00:58:30 +03:00
long ip ;
if ( upeek ( tcp - > pid , PT_B0 , & ip ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , ip ) ;
2000-02-20 02:59:03 +03:00
# elif defined(POWERPC)
1999-02-19 03:21:36 +03:00
long pc ;
2003-01-14 12:59:00 +03:00
if ( upeek ( tcp - > pid , sizeof ( unsigned long ) * PT_NIP , & pc ) < 0 ) {
1999-02-19 03:21:36 +03:00
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2000-02-20 02:59:03 +03:00
# elif defined(M68k)
1999-02-19 03:21:36 +03:00
long pc ;
if ( upeek ( tcp - > pid , 4 * PT_PC , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2000-02-20 02:59:03 +03:00
# elif defined(ALPHA)
1999-02-19 03:21:36 +03:00
long pc ;
if ( upeek ( tcp - > pid , REG_PC , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2000-02-20 02:59:03 +03:00
# elif defined(SPARC)
1999-08-30 03:15:07 +04:00
struct regs regs ;
1999-02-19 03:21:36 +03:00
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
1999-08-30 03:15:07 +04:00
tprintf ( " [%08lx] " , regs . r_pc ) ;
2001-03-27 16:17:16 +04:00
# elif defined(HPPA)
long pc ;
if ( upeek ( tcp - > pid , PT_IAOQ0 , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2001-04-10 14:22:50 +04:00
# elif defined(MIPS)
long pc ;
if ( upeek ( tcp - > pid , REG_EPC , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2002-05-01 20:39:22 +04:00
# elif defined(SH)
long pc ;
if ( upeek ( tcp - > pid , 4 * REG_PC , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2003-06-27 02:40:42 +04:00
# elif defined(SH64)
2003-06-02 23:18:58 +04:00
long pc ;
if ( upeek ( tcp - > pid , REG_PC , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2003-06-04 03:28:59 +04:00
# elif defined(ARM)
long pc ;
2003-06-02 23:18:58 +04:00
2003-06-04 03:28:59 +04:00
if ( upeek ( tcp - > pid , 4 * 15 , & pc ) < 0 ) {
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08lx] " , pc ) ;
2000-02-20 02:59:03 +03:00
# endif /* !architecture */
1999-02-19 03:21:36 +03:00
# endif /* LINUX */
# ifdef SUNOS4
struct regs regs ;
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
perror ( " printcall: ptrace(PTRACE_GETREGS, ...) " ) ;
tprintf ( " [????????] " ) ;
return ;
}
tprintf ( " [%08x] " , regs . r_o7 ) ;
# endif /* SUNOS4 */
# ifdef SVR4
/* XXX */
tprintf ( " [????????] " ) ;
# endif
2000-09-02 01:03:06 +04:00
# ifdef FREEBSD
struct reg regs ;
pread ( tcp - > pfd_reg , & regs , sizeof ( regs ) , 0 ) ;
tprintf ( " [%08x] " , regs . r_eip ) ;
# endif /* FREEBSD */
1999-02-19 03:21:36 +03:00
}
2000-09-02 01:03:06 +04:00
# ifndef USE_PROCFS
1999-02-19 03:21:36 +03:00
2003-01-09 09:53:34 +03:00
# if defined LINUX
# include <sys/syscall.h>
# ifndef CLONE_PTRACE
# define CLONE_PTRACE 0x00002000
# endif
# ifdef IA64
typedef unsigned long * arg_setup_state ;
static int
arg_setup ( struct tcb * tcp , arg_setup_state * state )
{
unsigned long * bsp , cfm , sof , sol ;
if ( upeek ( tcp - > pid , PT_AR_BSP , ( long * ) & bsp ) < 0 )
return - 1 ;
if ( upeek ( tcp - > pid , PT_CFM , ( long * ) & cfm ) < 0 )
return - 1 ;
sof = ( cfm > > 0 ) & 0x7f ;
sol = ( cfm > > 7 ) & 0x7f ;
bsp = ia64_rse_skip_regs ( bsp , - sof + sol ) ;
* state = bsp ;
return 0 ;
}
# define arg_finish_change(tcp, state) 0
# ifdef SYS_fork
static int
get_arg0 ( struct tcb * tcp , arg_setup_state * state , long * valp )
{
return umoven ( tcp , ( unsigned long ) ia64_rse_skip_regs ( * state , 0 ) ,
sizeof ( long ) , ( void * ) valp ) ;
}
static int
get_arg1 ( struct tcb * tcp , arg_setup_state * state , long * valp )
{
return umoven ( tcp , ( unsigned long ) ia64_rse_skip_regs ( * state , 1 ) ,
sizeof ( long ) , ( void * ) valp ) ;
}
# endif
static int
set_arg0 ( struct tcb * tcp , arg_setup_state * state , long val )
{
unsigned long * ap ;
ap = ia64_rse_skip_regs ( * state , 0 ) ;
errno = 0 ;
ptrace ( PTRACE_POKEDATA , tcp - > pid , ( void * ) ap , val ) ;
return errno ? - 1 : 0 ;
}
static int
set_arg1 ( struct tcb * tcp , arg_setup_state * state , long val )
{
unsigned long * ap ;
ap = ia64_rse_skip_regs ( * state , 1 ) ;
errno = 0 ;
ptrace ( PTRACE_POKEDATA , tcp - > pid , ( void * ) ap , val ) ;
return errno ? - 1 : 0 ;
}
# elif defined (SPARC)
typedef struct regs arg_setup_state ;
# define arg_setup(tcp, state) \
( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) ( state ) , 0 ) )
# define arg_finish_change(tcp, state) \
( ptrace ( PTRACE_SETREGS , tcp - > pid , ( char * ) ( state ) , 0 ) )
# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
2003-01-14 12:46:15 +03:00
# define restore_arg0(tcp, state, val) 0
2003-01-09 09:53:34 +03:00
# else
# if defined S390 || defined S390X
2003-01-20 12:04:36 +03:00
/* Note: this is only true for the `clone' system call, which handles
arguments specially . We could as well say that its first two arguments
are swapped relative to other architectures , but that would just be
another # ifdef in the calls . */
# define arg0_offset PT_GPR3
# define arg1_offset PT_ORIGGPR2
# define restore_arg0(tcp, state, val) ((void) (state), 0)
# define restore_arg1(tcp, state, val) ((void) (state), 0)
2003-01-09 09:53:34 +03:00
# elif defined (ALPHA) || defined (MIPS)
# define arg0_offset REG_A0
# define arg1_offset (REG_A0+1)
# elif defined (POWERPC)
2003-01-14 12:59:00 +03:00
# define arg0_offset (sizeof(unsigned long)*PT_R3)
# define arg1_offset (sizeof(unsigned long)*PT_R4)
2003-01-20 12:04:36 +03:00
# define restore_arg0(tcp, state, val) ((void) (state), 0)
2003-01-09 09:53:34 +03:00
# elif defined (HPPA)
# define arg0_offset PT_GR26
# define arg1_offset (PT_GR26-4)
2003-01-10 23:51:00 +03:00
# elif defined (X86_64)
# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
2003-03-31 05:03:33 +04:00
# elif defined (SH)
# define arg0_offset (4*(REG_REG0+4))
# define arg1_offset (4*(REG_REG0+5))
2003-06-27 02:40:42 +04:00
# elif defined (SH64)
2003-06-02 23:18:58 +04:00
/* ABI defines arg0 & 1 in r2 & r3 */
# define arg0_offset (REG_OFFSET+16)
# define arg1_offset (REG_OFFSET+24)
# define restore_arg0(tcp, state, val) 0
2003-01-09 09:53:34 +03:00
# else
# define arg0_offset 0
# define arg1_offset 4
2003-03-31 05:03:33 +04:00
# if defined ARM
2003-01-14 12:46:15 +03:00
# define restore_arg0(tcp, state, val) 0
# endif
2003-01-09 09:53:34 +03:00
# endif
typedef int arg_setup_state ;
# define arg_setup(tcp, state) (0)
# define arg_finish_change(tcp, state) 0
# define get_arg0(tcp, cookie, valp) \
( upeek ( ( tcp ) - > pid , arg0_offset , ( valp ) ) )
# define get_arg1(tcp, cookie, valp) \
( upeek ( ( tcp ) - > pid , arg1_offset , ( valp ) ) )
static int
set_arg0 ( struct tcb * tcp , void * cookie , long val )
{
return ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) arg0_offset , val ) ;
}
static int
set_arg1 ( struct tcb * tcp , void * cookie , long val )
{
return ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) arg1_offset , val ) ;
}
# endif
2003-01-14 12:46:15 +03:00
# ifndef restore_arg0
# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
# endif
# ifndef restore_arg1
# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
# endif
2003-01-09 09:53:34 +03:00
int
setbpt ( tcp )
struct tcb * tcp ;
{
extern int change_syscall ( struct tcb * , int ) ;
arg_setup_state state ;
if ( tcp - > flags & TCB_BPTSET ) {
fprintf ( stderr , " PANIC: TCB already set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
switch ( tcp - > scno ) {
2003-01-18 03:19:31 +03:00
# ifdef SYS_vfork
case SYS_vfork :
# endif
2003-01-09 09:53:34 +03:00
# ifdef SYS_fork
case SYS_fork :
2003-01-18 03:21:51 +03:00
# endif
# if defined SYS_fork || defined SYS_vfork
2003-01-09 09:53:34 +03:00
if ( arg_setup ( tcp , & state ) < 0
| | get_arg0 ( tcp , & state , & tcp - > inst [ 0 ] ) < 0
| | get_arg1 ( tcp , & state , & tcp - > inst [ 1 ] ) < 0
| | change_syscall ( tcp , SYS_clone ) < 0
| | set_arg0 ( tcp , & state , CLONE_PTRACE | SIGCHLD ) < 0
| | set_arg1 ( tcp , & state , 0 ) < 0
| | arg_finish_change ( tcp , & state ) < 0 )
return - 1 ;
tcp - > u_arg [ 0 ] = CLONE_PTRACE | SIGCHLD ;
tcp - > u_arg [ 1 ] = 0 ;
tcp - > flags | = TCB_BPTSET ;
return 0 ;
# endif
case SYS_clone :
# ifdef SYS_clone2
case SYS_clone2 :
# endif
if ( ( tcp - > u_arg [ 0 ] & CLONE_PTRACE ) = = 0
& & ( arg_setup ( tcp , & state ) < 0
| | set_arg0 ( tcp , & state , tcp - > u_arg [ 0 ] | CLONE_PTRACE ) < 0
| | arg_finish_change ( tcp , & state ) < 0 ) )
return - 1 ;
tcp - > flags | = TCB_BPTSET ;
tcp - > inst [ 0 ] = tcp - > u_arg [ 0 ] ;
tcp - > inst [ 1 ] = tcp - > u_arg [ 1 ] ;
return 0 ;
default :
fprintf ( stderr , " PANIC: setbpt for syscall %ld on %u??? \n " ,
tcp - > scno , tcp - > pid ) ;
break ;
}
return - 1 ;
}
int
clearbpt ( tcp )
struct tcb * tcp ;
{
arg_setup_state state ;
if ( arg_setup ( tcp , & state ) < 0
2003-01-14 12:46:15 +03:00
| | restore_arg0 ( tcp , & state , tcp - > inst [ 0 ] ) < 0
| | restore_arg1 ( tcp , & state , tcp - > inst [ 1 ] ) < 0
2003-01-09 09:53:34 +03:00
| | arg_finish_change ( tcp , & state ) )
return - 1 ;
tcp - > flags & = ~ TCB_BPTSET ;
return 0 ;
}
# else
1999-02-19 03:21:36 +03:00
int
setbpt ( tcp )
struct tcb * tcp ;
{
# ifdef LINUX
# ifdef SPARC
/* We simply use the SunOS breakpoint code. */
1999-08-30 03:15:07 +04:00
struct regs regs ;
1999-02-19 03:21:36 +03:00
# define LOOPA 0x30800000 /* ba,a 0 */
if ( tcp - > flags & TCB_BPTSET ) {
fprintf ( stderr , " PANIC: TCB already set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
perror ( " setbpt: ptrace(PTRACE_GETREGS, ...) " ) ;
return - 1 ;
}
1999-08-30 03:15:07 +04:00
tcp - > baddr = regs . r_o7 + 8 ;
1999-02-19 03:21:36 +03:00
errno = 0 ;
tcp - > inst [ 0 ] = ptrace ( PTRACE_PEEKTEXT , tcp - > pid , ( char * ) tcp - > baddr , 0 ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_PEEKTEXT, ...) " ) ;
return - 1 ;
}
/*
* XXX - BRUTAL MODE ON
* We cannot set a real BPT in the child , since it will not be
* traced at the moment it will reach the trap and would probably
* die with a core dump .
* Thus , we are force our way in by taking out two instructions
* and insert an eternal loop instead , in expectance of the SIGSTOP
* generated by out PTRACE_ATTACH .
* Of cause , if we evaporate ourselves in the middle of all this . . .
*/
errno = 0 ;
ptrace ( PTRACE_POKETEXT , tcp - > pid , ( char * ) tcp - > baddr , LOOPA ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags | = TCB_BPTSET ;
# else /* !SPARC */
2000-02-04 00:58:30 +03:00
# ifdef IA64
2001-10-10 03:47:38 +04:00
if ( ia32 ) {
# define LOOP 0x0000feeb
if ( tcp - > flags & TCB_BPTSET ) {
fprintf ( stderr , " PANIC: bpt already set in pid %u \n " ,
tcp - > pid ) ;
return - 1 ;
}
if ( upeek ( tcp - > pid , PT_CR_IIP , & tcp - > baddr ) < 0 )
return - 1 ;
if ( debug )
fprintf ( stderr , " [%d] setting bpt at %lx \n " ,
tcp - > pid , tcp - > baddr ) ;
tcp - > inst [ 0 ] = ptrace ( PTRACE_PEEKTEXT , tcp - > pid ,
( char * ) tcp - > baddr , 0 ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_PEEKTEXT, ...) " ) ;
return - 1 ;
}
ptrace ( PTRACE_POKETEXT , tcp - > pid , ( char * ) tcp - > baddr , LOOP ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags | = TCB_BPTSET ;
} else {
/*
* Our strategy here is to replace the bundle that
* contained the clone ( ) syscall with a bundle of the
* form :
*
* { 1 : br 1 b ; br 1 b ; br 1 b }
*
* This ensures that the newly forked child will loop
* endlessly until we ' ve got a chance to attach to it .
*/
2000-02-04 00:58:30 +03:00
# define LOOP0 0x0000100000000017
# define LOOP1 0x4000000000200000
unsigned long addr , ipsr ;
pid_t pid ;
pid = tcp - > pid ;
if ( upeek ( pid , PT_CR_IPSR , & ipsr ) < 0 )
return - 1 ;
if ( upeek ( pid , PT_CR_IIP , & addr ) < 0 )
return - 1 ;
2001-10-10 03:47:38 +04:00
/* store "ri" in low two bits */
tcp - > baddr = addr | ( ( ipsr > > 41 ) & 0x3 ) ;
2000-02-04 00:58:30 +03:00
errno = 0 ;
2001-10-10 03:47:38 +04:00
tcp - > inst [ 0 ] = ptrace ( PTRACE_PEEKTEXT , pid , ( char * ) addr + 0 ,
0 ) ;
tcp - > inst [ 1 ] = ptrace ( PTRACE_PEEKTEXT , pid , ( char * ) addr + 8 ,
0 ) ;
2000-02-04 00:58:30 +03:00
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_PEEKTEXT, ...) " ) ;
return - 1 ;
}
errno = 0 ;
ptrace ( PTRACE_POKETEXT , pid , ( char * ) addr + 0 , LOOP0 ) ;
ptrace ( PTRACE_POKETEXT , pid , ( char * ) addr + 8 , LOOP1 ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags | = TCB_BPTSET ;
}
# else /* !IA64 */
1999-02-19 03:21:36 +03:00
2002-09-23 19:41:01 +04:00
# if defined (I386) || defined(X86_64)
1999-02-19 03:21:36 +03:00
# define LOOP 0x0000feeb
# elif defined (M68K)
# define LOOP 0x60fe0000
# elif defined (ALPHA)
1999-12-23 17:20:14 +03:00
# define LOOP 0xc3ffffff
1999-02-19 03:21:36 +03:00
# elif defined (POWERPC)
2002-12-16 23:40:54 +03:00
# define LOOP 0x48000000
1999-02-19 03:21:36 +03:00
# elif defined(ARM)
1999-12-25 02:19:31 +03:00
# define LOOP 0xEAFFFFFE
1999-11-01 00:15:38 +03:00
# elif defined(MIPS)
1999-12-23 17:20:14 +03:00
# define LOOP 0x1000ffff
# elif defined(S390)
# define LOOP 0xa7f40000 /* BRC 15,0 */
2002-10-07 18:31:00 +04:00
# elif defined(S390X)
# define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
2001-03-27 16:17:16 +04:00
# elif defined(HPPA)
# define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
2002-05-01 20:39:22 +04:00
# elif defined(SH)
# ifdef __LITTLE_ENDIAN__
# define LOOP 0x0000affe
# else
# define LOOP 0xfeaf0000
# endif
1999-02-19 03:21:36 +03:00
# else
# error unknown architecture
# endif
if ( tcp - > flags & TCB_BPTSET ) {
fprintf ( stderr , " PANIC: bpt already set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
# if defined (I386)
if ( upeek ( tcp - > pid , 4 * EIP , & tcp - > baddr ) < 0 )
return - 1 ;
2002-09-23 19:41:01 +04:00
# elif defined (X86_64)
if ( upeek ( tcp - > pid , 8 * RIP , & tcp - > baddr ) < 0 )
return - 1 ;
1999-02-19 03:21:36 +03:00
# elif defined (M68K)
if ( upeek ( tcp - > pid , 4 * PT_PC , & tcp - > baddr ) < 0 )
return - 1 ;
# elif defined (ALPHA)
return - 1 ;
# elif defined (ARM)
return - 1 ;
1999-11-01 00:15:38 +03:00
# elif defined (MIPS)
return - 1 ; /* FIXME: I do not know what i do - Flo */
1999-02-19 03:21:36 +03:00
# elif defined (POWERPC)
2003-01-14 12:59:00 +03:00
if ( upeek ( tcp - > pid , sizeof ( unsigned long ) * PT_NIP , & tcp - > baddr ) < 0 )
1999-02-19 03:21:36 +03:00
return - 1 ;
2002-10-07 18:31:00 +04:00
# elif defined(S390) || defined(S390X)
1999-12-23 17:20:14 +03:00
if ( upeek ( tcp - > pid , PT_PSWADDR , & tcp - > baddr ) < 0 )
return - 1 ;
2001-03-27 16:17:16 +04:00
# elif defined(HPPA)
if ( upeek ( tcp - > pid , PT_IAOQ0 , & tcp - > baddr ) < 0 )
return - 1 ;
tcp - > baddr & = ~ 0x03 ;
2002-05-01 20:39:22 +04:00
# elif defined(SH)
if ( upeek ( tcp - > pid , 4 * REG_PC , & tcp - > baddr ) < 0 )
return - 1 ;
1999-02-19 03:21:36 +03:00
# else
# error unknown architecture
# endif
if ( debug )
fprintf ( stderr , " [%d] setting bpt at %lx \n " , tcp - > pid , tcp - > baddr ) ;
tcp - > inst [ 0 ] = ptrace ( PTRACE_PEEKTEXT , tcp - > pid , ( char * ) tcp - > baddr , 0 ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_PEEKTEXT, ...) " ) ;
return - 1 ;
}
ptrace ( PTRACE_POKETEXT , tcp - > pid , ( char * ) tcp - > baddr , LOOP ) ;
if ( errno ) {
perror ( " setbpt: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags | = TCB_BPTSET ;
2000-02-04 00:58:30 +03:00
# endif /* !IA64 */
1999-02-19 03:21:36 +03:00
# endif /* SPARC */
# endif /* LINUX */
# ifdef SUNOS4
# ifdef SPARC /* This code is slightly sparc specific */
1999-06-22 19:28:30 +04:00
struct regs regs ;
1999-02-19 03:21:36 +03:00
# define BPT 0x91d02001 /* ta 1 */
# define LOOP 0x10800000 /* ba 0 */
# define LOOPA 0x30800000 /* ba,a 0 */
# define NOP 0x01000000
# if LOOPA
static int loopdeloop [ 1 ] = { LOOPA } ;
# else
static int loopdeloop [ 2 ] = { LOOP , NOP } ;
# endif
if ( tcp - > flags & TCB_BPTSET ) {
fprintf ( stderr , " PANIC: TCB already set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
perror ( " setbpt: ptrace(PTRACE_GETREGS, ...) " ) ;
return - 1 ;
}
tcp - > baddr = regs . r_o7 + 8 ;
if ( ptrace ( PTRACE_READTEXT , tcp - > pid , ( char * ) tcp - > baddr ,
sizeof tcp - > inst , ( char * ) tcp - > inst ) < 0 ) {
perror ( " setbpt: ptrace(PTRACE_READTEXT, ...) " ) ;
return - 1 ;
}
/*
* XXX - BRUTAL MODE ON
* We cannot set a real BPT in the child , since it will not be
* traced at the moment it will reach the trap and would probably
* die with a core dump .
* Thus , we are force our way in by taking out two instructions
* and insert an eternal loop in stead , in expectance of the SIGSTOP
* generated by out PTRACE_ATTACH .
* Of cause , if we evaporate ourselves in the middle of all this . . .
*/
if ( ptrace ( PTRACE_WRITETEXT , tcp - > pid , ( char * ) tcp - > baddr ,
sizeof loopdeloop , ( char * ) loopdeloop ) < 0 ) {
perror ( " setbpt: ptrace(PTRACE_WRITETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags | = TCB_BPTSET ;
# endif /* SPARC */
# endif /* SUNOS4 */
return 0 ;
}
int
clearbpt ( tcp )
struct tcb * tcp ;
{
# ifdef LINUX
2002-09-23 19:41:01 +04:00
# if defined(I386) || defined(X86_64)
1999-02-19 03:21:36 +03:00
long eip ;
2000-02-20 02:59:03 +03:00
# elif defined(POWERPC)
1999-02-19 03:21:36 +03:00
long pc ;
2000-02-20 02:59:03 +03:00
# elif defined(M68K)
1999-02-19 03:21:36 +03:00
long pc ;
2000-02-20 02:59:03 +03:00
# elif defined(ALPHA)
1999-02-19 03:21:36 +03:00
long pc ;
2001-03-27 16:17:16 +04:00
# elif defined(HPPA)
long iaoq ;
2002-05-01 20:39:22 +04:00
# elif defined(SH)
long pc ;
2000-02-20 02:59:03 +03:00
# endif /* architecture */
1999-02-19 03:21:36 +03:00
# ifdef SPARC
/* Again, we borrow the SunOS breakpoint code. */
if ( ! ( tcp - > flags & TCB_BPTSET ) ) {
fprintf ( stderr , " PANIC: TCB not set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
errno = 0 ;
ptrace ( PTRACE_POKETEXT , tcp - > pid , ( char * ) tcp - > baddr , tcp - > inst [ 0 ] ) ;
if ( errno ) {
perror ( " clearbtp: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags & = ~ TCB_BPTSET ;
2000-02-20 02:59:03 +03:00
# elif defined(IA64)
2001-10-10 03:47:38 +04:00
if ( ia32 ) {
unsigned long addr ;
if ( debug )
fprintf ( stderr , " [%d] clearing bpt \n " , tcp - > pid ) ;
if ( ! ( tcp - > flags & TCB_BPTSET ) ) {
fprintf ( stderr , " PANIC: TCB not set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
errno = 0 ;
ptrace ( PTRACE_POKETEXT , tcp - > pid , ( char * ) tcp - > baddr , tcp - > inst [ 0 ] ) ;
if ( errno ) {
perror ( " clearbtp: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags & = ~ TCB_BPTSET ;
if ( upeek ( tcp - > pid , PT_CR_IIP , & addr ) < 0 )
return - 1 ;
if ( addr ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr ,
" NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
addr , tcp - > baddr ) ;
return 0 ;
}
} else {
2000-02-04 00:58:30 +03:00
unsigned long addr , ipsr ;
pid_t pid ;
pid = tcp - > pid ;
if ( upeek ( pid , PT_CR_IPSR , & ipsr ) < 0 )
return - 1 ;
if ( upeek ( pid , PT_CR_IIP , & addr ) < 0 )
return - 1 ;
/* restore original bundle: */
errno = 0 ;
ptrace ( PTRACE_POKETEXT , pid , ( char * ) addr + 0 , tcp - > inst [ 0 ] ) ;
ptrace ( PTRACE_POKETEXT , pid , ( char * ) addr + 8 , tcp - > inst [ 1 ] ) ;
if ( errno ) {
perror ( " clearbpt: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
/* restore original "ri" in ipsr: */
ipsr = ( ipsr & ~ ( 0x3ul < < 41 ) ) | ( ( tcp - > baddr & 0x3 ) < < 41 ) ;
errno = 0 ;
ptrace ( PTRACE_POKEUSER , pid , ( char * ) PT_CR_IPSR , ipsr ) ;
if ( errno ) {
perror ( " clrbpt: ptrace(PTRACE_POKEUSER, ...) " ) ;
return - 1 ;
}
tcp - > flags & = ~ TCB_BPTSET ;
if ( addr ! = ( tcp - > baddr & ~ 0x3 ) ) {
/* the breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr , " NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
addr , tcp - > baddr ) ;
return 0 ;
}
}
2000-02-20 02:59:03 +03:00
# else /* !IA64 && ! SPARC */
1999-02-19 03:21:36 +03:00
if ( debug )
fprintf ( stderr , " [%d] clearing bpt \n " , tcp - > pid ) ;
if ( ! ( tcp - > flags & TCB_BPTSET ) ) {
fprintf ( stderr , " PANIC: TCB not set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
errno = 0 ;
ptrace ( PTRACE_POKETEXT , tcp - > pid , ( char * ) tcp - > baddr , tcp - > inst [ 0 ] ) ;
if ( errno ) {
perror ( " clearbtp: ptrace(PTRACE_POKETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags & = ~ TCB_BPTSET ;
# ifdef I386
if ( upeek ( tcp - > pid , 4 * EIP , & eip ) < 0 )
return - 1 ;
if ( eip ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr ,
" NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
eip , tcp - > baddr ) ;
return 0 ;
}
2002-09-23 19:41:01 +04:00
# elif defined(X86_64)
if ( upeek ( tcp - > pid , 8 * RIP , & eip ) < 0 )
return - 1 ;
if ( eip ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr ,
" NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
eip , tcp - > baddr ) ;
return 0 ;
}
2000-04-11 02:22:31 +04:00
# elif defined(POWERPC)
2003-01-14 12:59:00 +03:00
if ( upeek ( tcp - > pid , sizeof ( unsigned long ) * PT_NIP , & pc ) < 0 )
1999-02-19 03:21:36 +03:00
return - 1 ;
if ( pc ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr , " NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
pc , tcp - > baddr ) ;
return 0 ;
}
2000-02-20 02:59:03 +03:00
# elif defined(M68K)
1999-02-19 03:21:36 +03:00
if ( upeek ( tcp - > pid , 4 * PT_PC , & pc ) < 0 )
return - 1 ;
if ( pc ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr , " NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
pc , tcp - > baddr ) ;
return 0 ;
}
2000-02-20 02:59:03 +03:00
# elif defined(ALPHA)
1999-02-19 03:21:36 +03:00
if ( upeek ( tcp - > pid , REG_PC , & pc ) < 0 )
return - 1 ;
if ( pc ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr , " NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
pc , tcp - > baddr ) ;
return 0 ;
}
2001-03-27 16:17:16 +04:00
# elif defined(HPPA)
if ( upeek ( tcp - > pid , PT_IAOQ0 , & iaoq ) < 0 )
return - 1 ;
iaoq & = ~ 0x03 ;
if ( iaoq ! = tcp - > baddr & & iaoq ! = tcp - > baddr + 4 ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr , " NOTE: PC not at bpt (iaoq %#lx baddr %#lx) \n " ,
iaoq , tcp - > baddr ) ;
return 0 ;
}
iaoq = tcp - > baddr | 3 ;
/* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
* safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
* has no significant effect .
*/
ptrace ( PTRACE_POKEUSER , tcp - > pid , ( void * ) PT_IAOQ0 , iaoq ) ;
ptrace ( PTRACE_POKEUSER , tcp - > pid , ( void * ) PT_IAOQ1 , iaoq ) ;
2002-05-01 20:39:22 +04:00
# elif defined(SH)
if ( upeek ( tcp - > pid , 4 * REG_PC , & pc ) < 0 )
return - 1 ;
if ( pc ! = tcp - > baddr ) {
/* The breakpoint has not been reached yet. */
if ( debug )
fprintf ( stderr , " NOTE: PC not at bpt (pc %#lx baddr %#lx) \n " ,
pc , tcp - > baddr ) ;
return 0 ;
}
2000-02-20 02:59:03 +03:00
# endif /* arch */
# endif /* !SPARC && !IA64 */
1999-02-19 03:21:36 +03:00
# endif /* LINUX */
# ifdef SUNOS4
# ifdef SPARC
# if !LOOPA
1999-06-22 19:28:30 +04:00
struct regs regs ;
1999-02-19 03:21:36 +03:00
# endif
if ( ! ( tcp - > flags & TCB_BPTSET ) ) {
fprintf ( stderr , " PANIC: TCB not set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
if ( ptrace ( PTRACE_WRITETEXT , tcp - > pid , ( char * ) tcp - > baddr ,
sizeof tcp - > inst , ( char * ) tcp - > inst ) < 0 ) {
perror ( " clearbtp: ptrace(PTRACE_WRITETEXT, ...) " ) ;
return - 1 ;
}
tcp - > flags & = ~ TCB_BPTSET ;
# if !LOOPA
/*
* Since we don ' t have a single instruction breakpoint , we may have
* to adjust the program counter after removing the our ` breakpoint ' .
*/
if ( ptrace ( PTRACE_GETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
perror ( " clearbpt: ptrace(PTRACE_GETREGS, ...) " ) ;
return - 1 ;
}
if ( ( regs . r_pc < tcp - > baddr ) | |
( regs . r_pc > tcp - > baddr + 4 ) ) {
/* The breakpoint has not been reached yet */
if ( debug )
fprintf ( stderr ,
" NOTE: PC not at bpt (pc %#x baddr %#x) \n " ,
regs . r_pc , tcp - > parent - > baddr ) ;
return 0 ;
}
if ( regs . r_pc ! = tcp - > baddr )
if ( debug )
fprintf ( stderr , " NOTE: PC adjusted (%#x -> %#x \n " ,
regs . r_pc , tcp - > baddr ) ;
regs . r_pc = tcp - > baddr ;
if ( ptrace ( PTRACE_SETREGS , tcp - > pid , ( char * ) & regs , 0 ) < 0 ) {
perror ( " clearbpt: ptrace(PTRACE_SETREGS, ...) " ) ;
return - 1 ;
}
# endif /* LOOPA */
# endif /* SPARC */
# endif /* SUNOS4 */
return 0 ;
}
2003-01-09 09:53:34 +03:00
# endif
2000-09-02 01:03:06 +04:00
# endif /* !USE_PROCFS */
1999-02-19 03:21:36 +03:00
# ifdef SUNOS4
static int
getex ( pid , hdr )
int pid ;
struct exec * hdr ;
{
int n ;
for ( n = 0 ; n < sizeof * hdr ; n + = 4 ) {
long res ;
if ( upeek ( pid , uoff ( u_exdata ) + n , & res ) < 0 )
return - 1 ;
memcpy ( ( ( char * ) hdr ) + n , & res , 4 ) ;
}
if ( debug ) {
fprintf ( stderr , " [struct exec: magic: %o version %u Mach %o \n " ,
hdr - > a_magic , hdr - > a_toolversion , hdr - > a_machtype ) ;
fprintf ( stderr , " Text %lu Data %lu Bss %lu Syms %lu Entry %#lx] \n " ,
hdr - > a_text , hdr - > a_data , hdr - > a_bss , hdr - > a_syms , hdr - > a_entry ) ;
}
return 0 ;
}
int
fixvfork ( tcp )
struct tcb * tcp ;
{
int pid = tcp - > pid ;
/*
* Change ` vfork ' in a freshly exec ' ed dynamically linked
* executable ' s ( internal ) symbol table to plain old ` fork '
*/
struct exec hdr ;
struct link_dynamic dyn ;
struct link_dynamic_2 ld ;
char * strtab , * cp ;
if ( getex ( pid , & hdr ) < 0 )
return - 1 ;
if ( ! hdr . a_dynamic )
return - 1 ;
if ( umove ( tcp , ( int ) N_DATADDR ( hdr ) , & dyn ) < 0 ) {
fprintf ( stderr , " Cannot read DYNAMIC \n " ) ;
return - 1 ;
}
if ( umove ( tcp , ( int ) dyn . ld_un . ld_2 , & ld ) < 0 ) {
fprintf ( stderr , " Cannot read link_dynamic_2 \n " ) ;
return - 1 ;
}
if ( ( strtab = malloc ( ( unsigned ) ld . ld_symb_size ) ) = = NULL ) {
fprintf ( stderr , " fixvfork: out of memory \n " ) ;
return - 1 ;
}
if ( umoven ( tcp , ( int ) ld . ld_symbols + ( int ) N_TXTADDR ( hdr ) ,
( int ) ld . ld_symb_size , strtab ) < 0 )
goto err ;
#if 0
for ( cp = strtab ; cp < strtab + ld . ld_symb_size ; ) {
fprintf ( stderr , " [symbol: %s] \n " , cp ) ;
cp + = strlen ( cp ) + 1 ;
}
return 0 ;
# endif
for ( cp = strtab ; cp < strtab + ld . ld_symb_size ; ) {
if ( strcmp ( cp , " _vfork " ) = = 0 ) {
if ( debug )
fprintf ( stderr , " fixvfork: FOUND _vfork \n " ) ;
strcpy ( cp , " _fork " ) ;
break ;
}
cp + = strlen ( cp ) + 1 ;
}
if ( cp < strtab + ld . ld_symb_size )
/*
* Write entire symbol table back to avoid
* memory alignment bugs in ptrace
*/
if ( tload ( pid , ( int ) ld . ld_symbols + ( int ) N_TXTADDR ( hdr ) ,
( int ) ld . ld_symb_size , strtab ) < 0 )
goto err ;
free ( strtab ) ;
return 0 ;
err :
free ( strtab ) ;
return - 1 ;
}
# endif /* SUNOS4 */