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 .
*/
# include "defs.h"
# include <sys/user.h>
# include <sys/param.h>
# include <fcntl.h>
2014-11-22 13:03:33 +03:00
# if HAVE_SYS_XATTR_H
# include <sys / xattr.h>
# endif
2014-11-21 23:46:16 +03:00
# include <sys/uio.h>
1999-07-13 19:45:02 +04:00
2012-02-25 05:38:52 +04:00
# if 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
2012-02-25 05:38:52 +04:00
# include <sys / reg.h>
2014-10-20 03:02:48 +04:00
# endif
# ifdef HAVE_LINUX_PTRACE_H
2012-02-25 05:38:52 +04:00
# undef PTRACE_SYSCALL
2004-03-02 00:29:22 +03:00
# ifdef HAVE_STRUCT_IA64_FPREG
# define ia64_fpreg XXX_ia64_fpreg
# endif
# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
# define pt_all_user_regs XXX_pt_all_user_regs
# endif
2013-09-24 21:04:32 +04:00
# ifdef HAVE_STRUCT_PTRACE_PEEKSIGINFO_ARGS
# define ptrace_peeksiginfo_args XXX_ptrace_peeksiginfo_args
# endif
2012-02-25 05:38:52 +04:00
# include <linux / ptrace.h>
2013-09-24 21:04:32 +04:00
# undef ptrace_peeksiginfo_args
2004-03-02 00:29:22 +03:00
# undef ia64_fpreg
# undef pt_all_user_regs
1999-05-09 04:29:58 +04:00
# endif
2012-03-26 01:49:48 +04:00
int
string_to_uint ( const char * str )
{
char * error ;
long value ;
if ( ! * str )
return - 1 ;
errno = 0 ;
value = strtol ( str , & error , 10 ) ;
if ( errno | | * error | | value < 0 | | ( long ) ( int ) value ! = value )
return - 1 ;
return ( int ) value ;
}
1999-02-19 03:21:36 +03:00
int
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_nz ( const struct timeval * a )
1999-02-19 03:21:36 +03:00
{
return a - > tv_sec | | a - > tv_usec ;
}
int
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_cmp ( const struct timeval * a , const struct timeval * b )
1999-02-19 03:21:36 +03:00
{
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
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_float ( const struct timeval * tv )
1999-02-19 03:21:36 +03:00
{
return tv - > tv_sec + tv - > tv_usec / 1000000.0 ;
}
void
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_add ( struct timeval * tv , const struct timeval * a , const struct timeval * b )
1999-02-19 03:21:36 +03:00
{
tv - > tv_sec = a - > tv_sec + b - > tv_sec ;
tv - > tv_usec = a - > tv_usec + b - > tv_usec ;
2007-07-24 05:38:22 +04:00
if ( tv - > tv_usec > = 1000000 ) {
1999-02-19 03:21:36 +03:00
tv - > tv_sec + + ;
tv - > tv_usec - = 1000000 ;
}
}
void
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_sub ( struct timeval * tv , const struct timeval * a , const struct timeval * b )
1999-02-19 03:21:36 +03:00
{
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
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_div ( struct timeval * tv , const struct timeval * a , int n )
1999-02-19 03:21:36 +03:00
{
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
Constify tv_* functions
* defs.h (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div): Add
const qualifier to read only arguments.
* util.c (tv_nz, tv_cmp, tv_float, tv_add, tv_sub, tv_mul, tv_div):
Likewise.
2014-05-29 21:59:01 +04:00
tv_mul ( struct timeval * tv , const struct timeval * a , int n )
1999-02-19 03:21:36 +03:00
{
tv - > tv_usec = a - > tv_usec * n ;
2007-06-30 01:25:56 +04:00
tv - > tv_sec = a - > tv_sec * n + tv - > tv_usec / 1000000 ;
1999-02-19 03:21:36 +03:00
tv - > tv_usec % = 1000000 ;
}
2007-01-12 01:05:04 +03:00
const char *
2014-09-10 17:46:04 +04:00
xlookup ( const struct xlat * xlat , const unsigned int val )
1999-02-19 03:21:36 +03:00
{
for ( ; xlat - > str ! = NULL ; xlat + + )
if ( xlat - > val = = val )
return xlat - > str ;
return NULL ;
}
2014-09-22 02:42:45 +04:00
static int
xlat_bsearch_compare ( const void * a , const void * b )
{
const unsigned int val1 = ( const unsigned long ) a ;
const unsigned int val2 = ( ( const struct xlat * ) b ) - > val ;
return ( val1 > val2 ) ? 1 : ( val1 < val2 ) ? - 1 : 0 ;
}
const char *
xlat_search ( const struct xlat * xlat , const size_t nmemb , const unsigned int val )
{
const struct xlat * e =
bsearch ( ( const void * ) ( const unsigned long ) val ,
xlat , nmemb , sizeof ( * xlat ) , xlat_bsearch_compare ) ;
return e ? e - > str : NULL ;
}
2011-09-01 18:31:48 +04:00
# if !defined HAVE_STPCPY
2011-08-31 14:07:38 +04:00
char *
stpcpy ( char * dst , const char * src )
{
while ( ( * dst = * src + + ) ! = ' \0 ' )
dst + + ;
return dst ;
}
2011-09-01 18:31:48 +04:00
# endif
2011-08-31 14:07:38 +04:00
2013-11-09 23:40:31 +04:00
/* Find a next bit which is set.
* Starts testing at cur_bit .
* Returns - 1 if no more bits are set .
*
* We never touch bytes we don ' t need to .
* On big - endian , array is assumed to consist of
* current_wordsize wide words : for example , is current_wordsize is 4 ,
* the bytes are walked in 3 , 2 , 1 , 0 , 7 , 6 , 5 , 4 , 11 , 10 , 9 , 8 . . . sequence .
* On little - endian machines , word size is immaterial .
*/
int
next_set_bit ( const void * bit_array , unsigned cur_bit , unsigned size_bits )
{
const unsigned endian = 1 ;
int little_endian = * ( char * ) & endian ;
const uint8_t * array = bit_array ;
unsigned pos = cur_bit / 8 ;
unsigned pos_xor_mask = little_endian ? 0 : current_wordsize - 1 ;
for ( ; ; ) {
uint8_t bitmask ;
uint8_t cur_byte ;
if ( cur_bit > = size_bits )
return - 1 ;
cur_byte = array [ pos ^ pos_xor_mask ] ;
if ( cur_byte = = 0 ) {
cur_bit = ( cur_bit + 8 ) & ( - 8 ) ;
pos + + ;
continue ;
}
bitmask = 1 < < ( cur_bit & 7 ) ;
for ( ; ; ) {
if ( cur_byte & bitmask )
return cur_bit ;
cur_bit + + ;
if ( cur_bit > = size_bits )
return - 1 ;
bitmask < < = 1 ;
/* This check *can't be* optimized out: */
if ( bitmask = = 0 )
break ;
}
pos + + ;
}
}
1999-02-19 03:21:36 +03:00
/*
* Print entry in struct xlat table , if there .
*/
void
2014-09-10 17:46:04 +04:00
printxval ( const struct xlat * xlat , const unsigned int val , const char * dflt )
1999-02-19 03:21:36 +03:00
{
2007-01-12 01:05:04 +03:00
const char * str = xlookup ( xlat , val ) ;
1999-02-19 03:21:36 +03:00
if ( str )
2011-09-01 11:55:05 +04:00
tprints ( str ) ;
1999-02-19 03:21:36 +03:00
else
tprintf ( " %#x /* %s */ " , val , dflt ) ;
}
2009-11-04 19:08:34 +03:00
/*
2015-01-10 03:08:58 +03:00
* Fetch 64 bit argument at position arg_no and
* return the index of the next argument .
2009-11-04 19:08:34 +03:00
*/
int
2015-01-10 03:08:58 +03:00
getllval ( struct tcb * tcp , unsigned long long * val , int arg_no )
2009-11-04 19:08:34 +03:00
{
2013-05-04 23:51:57 +04:00
# if SIZEOF_LONG > 4 && SIZEOF_LONG == SIZEOF_LONG_LONG
# if SUPPORTED_PERSONALITIES > 1
if ( current_wordsize > 4 ) {
# endif
2015-01-10 03:08:58 +03:00
* val = tcp - > u_arg [ arg_no ] ;
2013-03-01 13:41:02 +04:00
arg_no + + ;
2013-05-04 23:51:57 +04:00
# if SUPPORTED_PERSONALITIES > 1
2009-11-04 19:08:34 +03:00
} else {
2013-05-04 23:51:57 +04:00
# if defined(AARCH64) || defined(POWERPC64)
Fix preadv/pwritev offset decoding on bigendian architectures
This partially reverts commit 7845a42b39e59e904d01e75e21f7bc7eb6462560.
* util.c (printllval): Remove align argument.
* defs.h (printllval): Update prototype.
(printllval_aligned, printllval_unaligned): Remove.
* file.c (sys_readahead, sys_truncate64, sys_ftruncate64, sys_fadvise64,
sys_fadvise64_64, sys_sync_file_range, sys_sync_file_range2,
sys_fallocate): Replace printllval_aligned call with printllval.
* io.c (sys_pread, sys_pwrite): Likewise.
(print_llu_from_low_high_val): New function.
(sys_preadv, sys_pwritev): Use it instead of printllval_unaligned.
2014-08-07 04:07:28 +04:00
/* Align arg_no to the next even number. */
arg_no = ( arg_no + 1 ) & 0xe ;
2015-01-10 03:08:58 +03:00
# endif /* AARCH64 || POWERPC64 */
* val = LONG_LONG ( tcp - > u_arg [ arg_no ] , tcp - > u_arg [ arg_no + 1 ] ) ;
2013-03-01 13:41:02 +04:00
arg_no + = 2 ;
2009-11-04 19:08:34 +03:00
}
2015-01-10 03:08:58 +03:00
# endif /* SUPPORTED_PERSONALITIES > 1 */
2013-05-04 23:51:57 +04:00
# elif SIZEOF_LONG > 4
# error Unsupported configuration: SIZEOF_LONG > 4 && SIZEOF_LONG_LONG > SIZEOF_LONG
# elif defined LINUX_MIPSN32
2015-01-10 03:08:58 +03:00
* val = tcp - > ext_arg [ arg_no ] ;
2013-03-01 13:41:02 +04:00
arg_no + + ;
2013-05-02 12:41:27 +04:00
# elif defined X32
if ( current_personality = = 0 ) {
2015-01-10 03:08:58 +03:00
* val = tcp - > ext_arg [ arg_no ] ;
2013-05-02 12:41:27 +04:00
arg_no + + ;
} else {
2015-01-10 03:08:58 +03:00
* val = LONG_LONG ( tcp - > u_arg [ arg_no ] , tcp - > u_arg [ arg_no + 1 ] ) ;
2013-05-02 12:41:27 +04:00
arg_no + = 2 ;
}
2013-02-18 01:41:33 +04:00
# else
2013-05-06 22:23:01 +04:00
# if defined __ARM_EABI__ || \
defined LINUX_MIPSO32 | | \
defined POWERPC | | \
defined XTENSA
Fix preadv/pwritev offset decoding on bigendian architectures
This partially reverts commit 7845a42b39e59e904d01e75e21f7bc7eb6462560.
* util.c (printllval): Remove align argument.
* defs.h (printllval): Update prototype.
(printllval_aligned, printllval_unaligned): Remove.
* file.c (sys_readahead, sys_truncate64, sys_ftruncate64, sys_fadvise64,
sys_fadvise64_64, sys_sync_file_range, sys_sync_file_range2,
sys_fallocate): Replace printllval_aligned call with printllval.
* io.c (sys_pread, sys_pwrite): Likewise.
(print_llu_from_low_high_val): New function.
(sys_preadv, sys_pwritev): Use it instead of printllval_unaligned.
2014-08-07 04:07:28 +04:00
/* Align arg_no to the next even number. */
arg_no = ( arg_no + 1 ) & 0xe ;
2013-05-04 23:51:57 +04:00
# endif
2015-01-10 03:08:58 +03:00
* val = LONG_LONG ( tcp - > u_arg [ arg_no ] , tcp - > u_arg [ arg_no + 1 ] ) ;
2013-03-01 13:41:02 +04:00
arg_no + = 2 ;
2013-02-18 01:41:33 +04:00
# endif
2013-05-04 23:51:57 +04:00
2013-03-01 13:41:02 +04:00
return arg_no ;
2009-11-04 19:08:34 +03:00
}
2015-01-10 03:08:58 +03:00
/*
* Print 64 bit argument at position arg_no and
* return the index of the next argument .
*/
int
printllval ( struct tcb * tcp , const char * format , int arg_no )
{
unsigned long long val = 0 ;
arg_no = getllval ( tcp , & val , arg_no ) ;
tprintf ( format , val ) ;
return arg_no ;
}
1999-02-19 03:21:36 +03:00
/*
* Interpret ` xlat ' as an array of flags
* print the entries whose bits are on in ` flags '
* return # of flags printed .
*/
2011-08-19 20:06:46 +04:00
void
2011-05-30 16:00:14 +04:00
addflags ( const struct xlat * xlat , int flags )
1999-02-19 03:21:36 +03:00
{
2011-08-19 20:06:46 +04:00
for ( ; xlat - > str ; xlat + + ) {
1999-02-19 03:21:36 +03:00
if ( xlat - > val & & ( flags & xlat - > val ) = = xlat - > val ) {
tprintf ( " |%s " , xlat - > str ) ;
flags & = ~ xlat - > val ;
}
}
if ( flags ) {
tprintf ( " |%#x " , flags ) ;
}
}
2007-11-02 00:46:22 +03:00
/*
2011-08-19 20:06:46 +04:00
* Interpret ` xlat ' as an array of flags .
2007-11-02 00:46:22 +03:00
* Print to static string the entries whose bits are on in ` flags '
* Return static string .
*/
const char *
sprintflags ( const char * prefix , const struct xlat * xlat , int flags )
{
static char outstr [ 1024 ] ;
2011-08-31 14:07:38 +04:00
char * outptr ;
2007-11-02 00:46:22 +03:00
int found = 0 ;
2011-08-31 14:07:38 +04:00
outptr = stpcpy ( outstr , prefix ) ;
2007-11-02 00:46:22 +03:00
for ( ; xlat - > str ; xlat + + ) {
if ( ( flags & xlat - > val ) = = xlat - > val ) {
if ( found )
2011-08-31 14:07:38 +04:00
* outptr + + = ' | ' ;
outptr = stpcpy ( outptr , xlat - > str ) ;
2007-11-02 00:46:22 +03:00
found = 1 ;
2012-01-30 01:38:35 +04:00
flags & = ~ xlat - > val ;
if ( ! flags )
break ;
2007-11-02 00:46:22 +03:00
}
}
if ( flags ) {
if ( found )
2011-08-31 14:07:38 +04:00
* outptr + + = ' | ' ;
outptr + = sprintf ( outptr , " %#x " , flags ) ;
2007-11-02 00:46:22 +03:00
}
return outstr ;
}
1999-02-19 03:21:36 +03:00
int
2010-09-07 02:08:24 +04:00
printflags ( const struct xlat * xlat , int flags , const char * dflt )
1999-02-19 03:21:36 +03:00
{
int n ;
2010-09-07 02:08:24 +04:00
const char * sep ;
1999-02-19 03:21:36 +03:00
if ( flags = = 0 & & xlat - > val = = 0 ) {
2011-09-01 11:55:05 +04:00
tprints ( xlat - > str ) ;
1999-02-19 03:21:36 +03:00
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 + + ;
}
}
2005-05-31 Dmitry V. Levin <ldv@altlinux.org>
* util.c (printxval): Change third argument from "char *" to
"const char *".
(printflags): Add third argument, "const char *", with similar
meaning to the third argument of printxval().
* defs.h (printxval): Change third argument from "char *" to
"const char *".
(printflags): Add third argument.
* bjm.c (sys_query_module) [LINUX]: Pass third argument to
printflags().
* desc.c (sys_fcntl): Likewise.
(sys_flock) [LOCK_SH]: Likewise.
(print_epoll_event) [HAVE_SYS_EPOLL_H]: Likewise.
* file.c (sys_open): Likewise.
(solaris_open) [LINUXSPARC]: Likewise.
(sys_access): Likewise.
(sys_chflags, sys_fchflags) [FREEBSD]: Likewise.
(realprintstat) [HAVE_LONG_LONG_OFF_T &&
HAVE_STRUCT_STAT_ST_FLAGS]: Likewise.
(printstat64) [HAVE_STAT64 &&
HAVE_STRUCT_STAT_ST_FLAGS]: Likewise.
(sys_setxattr, sys_fsetxattr): Likewise.
* ipc.c (sys_msgget, sys_msgsnd, sys_msgrcv, sys_semget,
sys_shmget, sys_shmat) [LINUX || SUNOS4 || FREEBSD]: Likewise.
(sys_mq_open) [LINUX]: Likewise.
(printmqattr) [HAVE_MQUEUE_H]: Likewise.
* mem.c (print_mmap) [!HAVE_LONG_LONG_OFF_T]: Likewise.
(sys_mmap64) [_LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T]: Likewise.
(sys_mprotect): Likewise.
(sys_mremap, sys_madvise, sys_mlockall) [LINUX]: Likewise.
(sys_msync) [MS_ASYNC]: Likewise.
(sys_mctl) [MC_SYNC]: Likewise.
(sys_remap_file_pages, sys_mbind, sys_get_mempolicy) [LINUX]:
Likewise.
* net.c (printmsghdr) [HAVE_STRUCT_MSGHDR_MSG_CONTROL]: Likewise.
(sys_send, sys_sendto): Likewise.
(sys_sendmsg) [HAVE_SENDMSG]: Likewise.
(sys_recv, sys_recvfrom): Likewise.
(sys_recvmsg) [HAVE_SENDMSG]: Likewise.
(printicmpfilter) [ICMP_FILTER]: Likewise.
* proc.c (proc_ioctl) [SVR4 && !HAVE_MP_PROCFS || FREEBSD]: Likewise.
* process.c (sys_clone) [LINUX]: Likewise.
(printwaitn): Likewise.
(sys_waitid) [SVR4 || LINUX]: Likewise.
* signal.c (sys_sigvec) [SUNOS4 || FREEBSD]: Likewise.
(sys_sigaction): Likewise.
(printcontext) [SVR4]: Likewise.
(print_stack_t) [LINUX) || FREEBSD]: Likewise.
(sys_rt_sigaction) [LINUX]: Likewise.
* sock.c (sock_ioctl) [LINUX]: Likewise.
* stream.c (sys_putmsg, sys_getmsg): Likewise.
(sys_putpmsg) [SYS_putpmsg]: Likewise.
(sys_getpmsg) [SYS_getpmsg]: Likewise.
(sys_poll): Likewise.
(print_transport_message) [TI_BIND]: Likewise.
(stream_ioctl): Likewise.
* system.c (sys_mount, sys_reboot): Likewise.
(sys_cacheflush) [LINUX && M68K]: Likewise.
(sys_capget, sys_capset) [SYS_capget]: Likewise.
* term.c (term_ioctl) [TIOCMGET]: Likewise.
* time.c (sys_clock_nanosleep, sys_timer_settime) [LINUX]:
Likewise.
Fixes RH#159310.
2005-06-01 23:02:36 +04:00
if ( n ) {
if ( flags ) {
tprintf ( " %s%#x " , sep , flags ) ;
n + + ;
}
} else {
if ( flags ) {
tprintf ( " %#x " , flags ) ;
if ( dflt )
tprintf ( " /* %s */ " , dflt ) ;
} else {
if ( dflt )
2011-09-01 12:00:28 +04:00
tprints ( " 0 " ) ;
2005-05-31 Dmitry V. Levin <ldv@altlinux.org>
* util.c (printxval): Change third argument from "char *" to
"const char *".
(printflags): Add third argument, "const char *", with similar
meaning to the third argument of printxval().
* defs.h (printxval): Change third argument from "char *" to
"const char *".
(printflags): Add third argument.
* bjm.c (sys_query_module) [LINUX]: Pass third argument to
printflags().
* desc.c (sys_fcntl): Likewise.
(sys_flock) [LOCK_SH]: Likewise.
(print_epoll_event) [HAVE_SYS_EPOLL_H]: Likewise.
* file.c (sys_open): Likewise.
(solaris_open) [LINUXSPARC]: Likewise.
(sys_access): Likewise.
(sys_chflags, sys_fchflags) [FREEBSD]: Likewise.
(realprintstat) [HAVE_LONG_LONG_OFF_T &&
HAVE_STRUCT_STAT_ST_FLAGS]: Likewise.
(printstat64) [HAVE_STAT64 &&
HAVE_STRUCT_STAT_ST_FLAGS]: Likewise.
(sys_setxattr, sys_fsetxattr): Likewise.
* ipc.c (sys_msgget, sys_msgsnd, sys_msgrcv, sys_semget,
sys_shmget, sys_shmat) [LINUX || SUNOS4 || FREEBSD]: Likewise.
(sys_mq_open) [LINUX]: Likewise.
(printmqattr) [HAVE_MQUEUE_H]: Likewise.
* mem.c (print_mmap) [!HAVE_LONG_LONG_OFF_T]: Likewise.
(sys_mmap64) [_LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T]: Likewise.
(sys_mprotect): Likewise.
(sys_mremap, sys_madvise, sys_mlockall) [LINUX]: Likewise.
(sys_msync) [MS_ASYNC]: Likewise.
(sys_mctl) [MC_SYNC]: Likewise.
(sys_remap_file_pages, sys_mbind, sys_get_mempolicy) [LINUX]:
Likewise.
* net.c (printmsghdr) [HAVE_STRUCT_MSGHDR_MSG_CONTROL]: Likewise.
(sys_send, sys_sendto): Likewise.
(sys_sendmsg) [HAVE_SENDMSG]: Likewise.
(sys_recv, sys_recvfrom): Likewise.
(sys_recvmsg) [HAVE_SENDMSG]: Likewise.
(printicmpfilter) [ICMP_FILTER]: Likewise.
* proc.c (proc_ioctl) [SVR4 && !HAVE_MP_PROCFS || FREEBSD]: Likewise.
* process.c (sys_clone) [LINUX]: Likewise.
(printwaitn): Likewise.
(sys_waitid) [SVR4 || LINUX]: Likewise.
* signal.c (sys_sigvec) [SUNOS4 || FREEBSD]: Likewise.
(sys_sigaction): Likewise.
(printcontext) [SVR4]: Likewise.
(print_stack_t) [LINUX) || FREEBSD]: Likewise.
(sys_rt_sigaction) [LINUX]: Likewise.
* sock.c (sock_ioctl) [LINUX]: Likewise.
* stream.c (sys_putmsg, sys_getmsg): Likewise.
(sys_putpmsg) [SYS_putpmsg]: Likewise.
(sys_getpmsg) [SYS_getpmsg]: Likewise.
(sys_poll): Likewise.
(print_transport_message) [TI_BIND]: Likewise.
(stream_ioctl): Likewise.
* system.c (sys_mount, sys_reboot): Likewise.
(sys_cacheflush) [LINUX && M68K]: Likewise.
(sys_capget, sys_capset) [SYS_capget]: Likewise.
* term.c (term_ioctl) [TIOCMGET]: Likewise.
* time.c (sys_clock_nanosleep, sys_timer_settime) [LINUX]:
Likewise.
Fixes RH#159310.
2005-06-01 23:02:36 +04:00
}
1999-02-19 03:21:36 +03:00
}
2005-05-31 Dmitry V. Levin <ldv@altlinux.org>
* util.c (printxval): Change third argument from "char *" to
"const char *".
(printflags): Add third argument, "const char *", with similar
meaning to the third argument of printxval().
* defs.h (printxval): Change third argument from "char *" to
"const char *".
(printflags): Add third argument.
* bjm.c (sys_query_module) [LINUX]: Pass third argument to
printflags().
* desc.c (sys_fcntl): Likewise.
(sys_flock) [LOCK_SH]: Likewise.
(print_epoll_event) [HAVE_SYS_EPOLL_H]: Likewise.
* file.c (sys_open): Likewise.
(solaris_open) [LINUXSPARC]: Likewise.
(sys_access): Likewise.
(sys_chflags, sys_fchflags) [FREEBSD]: Likewise.
(realprintstat) [HAVE_LONG_LONG_OFF_T &&
HAVE_STRUCT_STAT_ST_FLAGS]: Likewise.
(printstat64) [HAVE_STAT64 &&
HAVE_STRUCT_STAT_ST_FLAGS]: Likewise.
(sys_setxattr, sys_fsetxattr): Likewise.
* ipc.c (sys_msgget, sys_msgsnd, sys_msgrcv, sys_semget,
sys_shmget, sys_shmat) [LINUX || SUNOS4 || FREEBSD]: Likewise.
(sys_mq_open) [LINUX]: Likewise.
(printmqattr) [HAVE_MQUEUE_H]: Likewise.
* mem.c (print_mmap) [!HAVE_LONG_LONG_OFF_T]: Likewise.
(sys_mmap64) [_LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T]: Likewise.
(sys_mprotect): Likewise.
(sys_mremap, sys_madvise, sys_mlockall) [LINUX]: Likewise.
(sys_msync) [MS_ASYNC]: Likewise.
(sys_mctl) [MC_SYNC]: Likewise.
(sys_remap_file_pages, sys_mbind, sys_get_mempolicy) [LINUX]:
Likewise.
* net.c (printmsghdr) [HAVE_STRUCT_MSGHDR_MSG_CONTROL]: Likewise.
(sys_send, sys_sendto): Likewise.
(sys_sendmsg) [HAVE_SENDMSG]: Likewise.
(sys_recv, sys_recvfrom): Likewise.
(sys_recvmsg) [HAVE_SENDMSG]: Likewise.
(printicmpfilter) [ICMP_FILTER]: Likewise.
* proc.c (proc_ioctl) [SVR4 && !HAVE_MP_PROCFS || FREEBSD]: Likewise.
* process.c (sys_clone) [LINUX]: Likewise.
(printwaitn): Likewise.
(sys_waitid) [SVR4 || LINUX]: Likewise.
* signal.c (sys_sigvec) [SUNOS4 || FREEBSD]: Likewise.
(sys_sigaction): Likewise.
(printcontext) [SVR4]: Likewise.
(print_stack_t) [LINUX) || FREEBSD]: Likewise.
(sys_rt_sigaction) [LINUX]: Likewise.
* sock.c (sock_ioctl) [LINUX]: Likewise.
* stream.c (sys_putmsg, sys_getmsg): Likewise.
(sys_putpmsg) [SYS_putpmsg]: Likewise.
(sys_getpmsg) [SYS_getpmsg]: Likewise.
(sys_poll): Likewise.
(print_transport_message) [TI_BIND]: Likewise.
(stream_ioctl): Likewise.
* system.c (sys_mount, sys_reboot): Likewise.
(sys_cacheflush) [LINUX && M68K]: Likewise.
(sys_capget, sys_capset) [SYS_capget]: Likewise.
* term.c (term_ioctl) [TIOCMGET]: Likewise.
* time.c (sys_clock_nanosleep, sys_timer_settime) [LINUX]:
Likewise.
Fixes RH#159310.
2005-06-01 23:02:36 +04:00
1999-02-19 03:21:36 +03:00
return n ;
}
void
2010-09-07 02:08:24 +04:00
printnum ( struct tcb * tcp , long addr , const char * fmt )
1999-02-19 03:21:36 +03:00
{
2003-01-14 12:59:00 +03:00
long num ;
1999-02-19 03:21:36 +03:00
if ( ! addr ) {
2011-09-01 12:00:28 +04:00
tprints ( " NULL " ) ;
1999-02-19 03:21:36 +03:00
return ;
}
if ( umove ( tcp , addr , & num ) < 0 ) {
tprintf ( " %#lx " , addr ) ;
return ;
}
2011-09-01 12:00:28 +04:00
tprints ( " [ " ) ;
1999-02-19 03:21:36 +03:00
tprintf ( fmt , num ) ;
2011-09-01 12:00:28 +04:00
tprints ( " ] " ) ;
1999-02-19 03:21:36 +03:00
}
2005-07-05 03:28:10 +04:00
void
2010-09-07 02:08:24 +04:00
printnum_int ( struct tcb * tcp , long addr , const char * fmt )
2005-07-05 03:28:10 +04:00
{
int num ;
if ( ! addr ) {
2011-09-01 12:00:28 +04:00
tprints ( " NULL " ) ;
2005-07-05 03:28:10 +04:00
return ;
}
if ( umove ( tcp , addr , & num ) < 0 ) {
tprintf ( " %#lx " , addr ) ;
return ;
}
2011-09-01 12:00:28 +04:00
tprints ( " [ " ) ;
2005-07-05 03:28:10 +04:00
tprintf ( fmt , num ) ;
2011-09-01 12:00:28 +04:00
tprints ( " ] " ) ;
2005-07-05 03:28:10 +04:00
}
2014-12-06 06:53:16 +03:00
const char *
sprinttime ( time_t t )
{
struct tm * tmp ;
2015-01-08 18:08:16 +03:00
static char buf [ sizeof ( int ) * 3 * 6 ] ;
2014-12-06 06:53:16 +03:00
if ( t = = 0 ) {
strcpy ( buf , " 0 " ) ;
return buf ;
}
tmp = localtime ( & t ) ;
if ( tmp )
snprintf ( buf , sizeof buf , " %02d/%02d/%02d-%02d:%02d:%02d " ,
tmp - > tm_year + 1900 , tmp - > tm_mon + 1 , tmp - > tm_mday ,
tmp - > tm_hour , tmp - > tm_min , tmp - > tm_sec ) ;
else
snprintf ( buf , sizeof buf , " %lu " , ( unsigned long ) t ) ;
return buf ;
}
2014-11-22 13:03:33 +03:00
static char *
getfdproto ( struct tcb * tcp , int fd , char * buf , unsigned bufsize )
{
# if HAVE_SYS_XATTR_H
ssize_t r ;
char path [ sizeof ( " /proc/%u/fd/%u " ) + 2 * sizeof ( int ) * 3 ] ;
if ( fd < 0 )
return NULL ;
sprintf ( path , " /proc/%u/fd/%u " , tcp - > pid , fd ) ;
r = getxattr ( path , " system.sockprotoname " , buf , bufsize - 1 ) ;
if ( r < = 0 )
return NULL ;
else {
/*
* This is a protection for the case when the kernel
* side does not append a null byte to the buffer .
*/
buf [ r ] = ' \0 ' ;
return buf ;
}
# else
return NULL ;
# endif
}
Fix decoding of file descriptors
* defs.h (printfd): New function prototype.
* util.c (printfd): New function.
* file.c (print_dirfd): Update prototype to use printfd().
(sys_openat, sys_faccessat, sys_newfstatat, sys_mkdirat, sys_linkat,
sys_unlinkat, sys_readlinkat, sys_renameat, sys_fchownat, sys_fchmodat,
sys_futimesat, sys_utimensat, sys_mknodat): Update use of print_dirfd().
(sys_lseek, sys_llseek, sys_readahead, sys_ftruncate, sys_ftruncate64,
sys_fstat, sys_fstat64, sys_oldfstat, sys_fstatfs, sys_fstatfs64,
sys_fchdir, sys_fchroot, sys_linkat, sys_fchown, sys_fchmod, sys_fsync,
sys_readdir, sys_getdents, sys_getdirentries, sys_fsetxattr,
sys_fgetxattr, sys_flistxattr, sys_fremovexattr, sys_fadvise64,
sys_fadvise64_64, sys_inotify_add_watch, sys_inotify_rm_watch,
sys_fallocate): Use printfd() for decoding of file descriptors.
* desc.c (sys_fcntl, sys_flock, sys_close, sys_dup, do_dup2,
decode_select, sys_epoll_ctl, epoll_wait_common): Use printfd() for
decoding of file descriptors.
* io.c (sys_read, sys_write, sys_readv, sys_writev, sys_pread,
sys_pwrite, sys_sendfile, sys_sendfile64, sys_pread64, sys_pwrite64,
sys_ioctl): Likewise.
* mem.c (print_mmap, sys_mmap64): Likewise.
* signal.c (do_signalfd): Likewise.
* stream.c (decode_poll): Likewise.
* time.c (sys_timerfd_settime, sys_timerfd_gettime): Likewise.
Based on patch from Grant Edwards <grant.b.edwards@gmail.com>.
2011-03-04 05:08:02 +03:00
void
printfd ( struct tcb * tcp , int fd )
{
2013-03-06 21:24:34 +04:00
char path [ PATH_MAX + 1 ] ;
2014-08-21 07:17:48 +04:00
if ( show_fd_path & & getfdpath ( tcp , fd , path , sizeof ( path ) ) > = 0 ) {
static const char socket_prefix [ ] = " socket:[ " ;
const size_t socket_prefix_len = sizeof ( socket_prefix ) - 1 ;
size_t path_len ;
if ( show_fd_path > 1 & &
strncmp ( path , socket_prefix , socket_prefix_len ) = = 0 & &
path [ ( path_len = strlen ( path ) ) - 1 ] = = ' ] ' ) {
unsigned long inodenr ;
2014-12-10 06:55:06 +03:00
# define PROTO_NAME_LEN 32
char proto_buf [ PROTO_NAME_LEN ] ;
const char * proto =
getfdproto ( tcp , fd , proto_buf , PROTO_NAME_LEN ) ;
2014-08-21 07:17:48 +04:00
inodenr = strtoul ( path + socket_prefix_len , NULL , 10 ) ;
tprintf ( " %d< " , fd ) ;
2014-12-10 06:55:06 +03:00
if ( ! print_sockaddr_by_inode ( inodenr , proto ) ) {
2014-11-22 13:03:33 +03:00
if ( proto )
tprintf ( " %s:[%lu] " , proto , inodenr ) ;
else
tprints ( path ) ;
}
2014-08-21 07:17:48 +04:00
tprints ( " > " ) ;
} else {
tprintf ( " %d<%s> " , fd , path ) ;
}
} else
2011-04-08 00:25:40 +04:00
tprintf ( " %d " , fd ) ;
Fix decoding of file descriptors
* defs.h (printfd): New function prototype.
* util.c (printfd): New function.
* file.c (print_dirfd): Update prototype to use printfd().
(sys_openat, sys_faccessat, sys_newfstatat, sys_mkdirat, sys_linkat,
sys_unlinkat, sys_readlinkat, sys_renameat, sys_fchownat, sys_fchmodat,
sys_futimesat, sys_utimensat, sys_mknodat): Update use of print_dirfd().
(sys_lseek, sys_llseek, sys_readahead, sys_ftruncate, sys_ftruncate64,
sys_fstat, sys_fstat64, sys_oldfstat, sys_fstatfs, sys_fstatfs64,
sys_fchdir, sys_fchroot, sys_linkat, sys_fchown, sys_fchmod, sys_fsync,
sys_readdir, sys_getdents, sys_getdirentries, sys_fsetxattr,
sys_fgetxattr, sys_flistxattr, sys_fremovexattr, sys_fadvise64,
sys_fadvise64_64, sys_inotify_add_watch, sys_inotify_rm_watch,
sys_fallocate): Use printfd() for decoding of file descriptors.
* desc.c (sys_fcntl, sys_flock, sys_close, sys_dup, do_dup2,
decode_select, sys_epoll_ctl, epoll_wait_common): Use printfd() for
decoding of file descriptors.
* io.c (sys_read, sys_write, sys_readv, sys_writev, sys_pread,
sys_pwrite, sys_sendfile, sys_sendfile64, sys_pread64, sys_pwrite64,
sys_ioctl): Likewise.
* mem.c (print_mmap, sys_mmap64): Likewise.
* signal.c (do_signalfd): Likewise.
* stream.c (decode_poll): Likewise.
* time.c (sys_timerfd_settime, sys_timerfd_gettime): Likewise.
Based on patch from Grant Edwards <grant.b.edwards@gmail.com>.
2011-03-04 05:08:02 +03:00
}
2008-11-11 02:19:13 +03:00
/*
* Quote string ` instr ' of length ` size '
* Write up to ( 3 + ` size ' * 4 ) bytes to ` outstr ' buffer .
2012-01-20 14:56:00 +04:00
*
2015-01-26 04:17:08 +03:00
* If QUOTE_0_TERMINATED ` style ' flag is set ,
* treat ` instr ' as a NUL - terminated string ,
* checking up to ( ` size ' + 1 ) bytes of ` instr ' .
*
* If QUOTE_OMIT_LEADING_TRAILING_QUOTES ` style ' flag is set ,
* do not add leading and trailing quoting symbols .
*
* Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen , 1 otherwise .
* Note that if QUOTE_0_TERMINATED is not set , always returns 1.
2008-11-11 02:19:13 +03:00
*/
2015-01-26 04:17:08 +03:00
static int
string_quote ( const char * instr , char * outstr , const unsigned int size ,
const unsigned int style )
1999-02-19 03:21:36 +03:00
{
2007-10-09 01:48:01 +04:00
const unsigned char * ustr = ( const unsigned char * ) instr ;
char * s = outstr ;
2015-01-26 04:17:08 +03:00
unsigned int i ;
int usehex , c , eol ;
1999-02-19 03:21:36 +03:00
2015-01-26 04:17:08 +03:00
if ( style & QUOTE_0_TERMINATED )
2011-08-31 14:22:56 +04:00
eol = ' \0 ' ;
2015-01-26 04:17:08 +03:00
else
eol = 0x100 ; /* this can never match a char */
2011-08-31 14:22:56 +04:00
usehex = 0 ;
2007-10-09 01:48:01 +04:00
if ( xflag > 1 )
usehex = 1 ;
else if ( xflag ) {
2008-11-11 02:19:13 +03:00
/* Check for presence of symbol which require
to hex - quote the whole string . */
2007-10-09 01:48:01 +04:00
for ( i = 0 ; i < size ; + + i ) {
c = ustr [ i ] ;
2008-11-11 02:19:13 +03:00
/* Check for NUL-terminated string. */
2011-08-31 14:22:56 +04:00
if ( c = = eol )
break ;
2013-03-07 02:44:23 +04:00
/* Force hex unless c is printable or whitespace */
if ( c > 0x7e ) {
usehex = 1 ;
break ;
}
/* In ASCII isspace is only these chars: "\t\n\v\f\r".
* They happen to have ASCII codes 9 , 10 , 11 , 12 , 13.
*/
if ( c < ' ' & & ( unsigned ) ( c - 9 ) > = 5 ) {
2007-10-09 01:48:01 +04:00
usehex = 1 ;
break ;
}
}
1999-02-19 03:21:36 +03:00
}
2007-10-09 01:48:01 +04:00
2015-01-26 04:17:08 +03:00
if ( ! ( style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ) )
* s + + = ' \" ' ;
2007-10-09 01:48:01 +04:00
if ( usehex ) {
2008-11-11 02:19:13 +03:00
/* Hex-quote the whole string. */
2007-10-09 01:48:01 +04:00
for ( i = 0 ; i < size ; + + i ) {
c = ustr [ i ] ;
2008-11-11 02:19:13 +03:00
/* Check for NUL-terminated string. */
2011-08-31 14:22:56 +04:00
if ( c = = eol )
goto asciz_ended ;
* s + + = ' \\ ' ;
* s + + = ' x ' ;
* s + + = " 0123456789abcdef " [ c > > 4 ] ;
* s + + = " 0123456789abcdef " [ c & 0xf ] ;
2007-10-09 01:48:01 +04:00
}
} else {
for ( i = 0 ; i < size ; + + i ) {
c = ustr [ i ] ;
2008-11-11 02:19:13 +03:00
/* Check for NUL-terminated string. */
2011-08-31 14:22:56 +04:00
if ( c = = eol )
goto asciz_ended ;
2007-10-09 01:48:01 +04:00
switch ( c ) {
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 :
2013-03-07 02:44:23 +04:00
if ( c > = ' ' & & c < = 0x7e )
2007-10-09 01:48:01 +04:00
* s + + = c ;
2011-08-31 14:22:56 +04:00
else {
/* Print \octal */
* s + + = ' \\ ' ;
if ( i + 1 < size
& & ustr [ i + 1 ] > = ' 0 '
& & ustr [ i + 1 ] < = ' 9 '
) {
/* Print \ooo */
* s + + = ' 0 ' + ( c > > 6 ) ;
* s + + = ' 0 ' + ( ( c > > 3 ) & 0x7 ) ;
} else {
/* Print \[[o]o]o */
if ( ( c > > 3 ) ! = 0 ) {
if ( ( c > > 6 ) ! = 0 )
* s + + = ' 0 ' + ( c > > 6 ) ;
* s + + = ' 0 ' + ( ( c > > 3 ) & 0x7 ) ;
}
}
* s + + = ' 0 ' + ( c & 0x7 ) ;
2007-10-09 01:48:01 +04:00
}
break ;
}
1999-02-19 03:21:36 +03:00
}
}
2015-01-26 04:17:08 +03:00
if ( ! ( style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ) )
* s + + = ' \" ' ;
2007-10-09 01:48:01 +04:00
* s = ' \0 ' ;
2007-11-02 02:53:59 +03:00
2011-08-31 14:22:56 +04:00
/* Return zero if we printed entire ASCIZ string (didn't truncate it) */
2015-01-26 04:17:08 +03:00
if ( style & QUOTE_0_TERMINATED & & ustr [ i ] = = ' \0 ' ) {
2011-08-31 14:22:56 +04:00
/* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
* but next char is NUL .
*/
return 0 ;
}
return 1 ;
asciz_ended :
2015-01-26 04:17:08 +03:00
if ( ! ( style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ) )
* s + + = ' \" ' ;
2011-08-31 14:22:56 +04:00
* s = ' \0 ' ;
/* Return zero: we printed entire ASCIZ string (didn't truncate it) */
return 0 ;
1999-02-19 03:21:36 +03:00
}
2015-01-26 04:17:08 +03:00
# ifndef ALLOCA_CUTOFF
# define ALLOCA_CUTOFF 4032
# endif
# define use_alloca(n) ((n) <= ALLOCA_CUTOFF)
/*
* Quote string ` str ' of length ` size ' and print the result .
*
* If QUOTE_0_TERMINATED ` style ' flag is set ,
* treat ` str ' as a NUL - terminated string and
* quote at most ( ` size ' - 1 ) bytes .
*
* If QUOTE_OMIT_LEADING_TRAILING_QUOTES ` style ' flag is set ,
* do not add leading and trailing quoting symbols .
*
* Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen , 1 otherwise .
* Note that if QUOTE_0_TERMINATED is not set , always returns 1.
*/
int
print_quoted_string ( const char * str , unsigned int size ,
const unsigned int style )
{
char * buf ;
char * outstr ;
unsigned int alloc_size ;
int rc ;
if ( size & & style & QUOTE_0_TERMINATED )
- - size ;
alloc_size = 4 * size ;
if ( alloc_size / 4 ! = size ) {
error_msg ( " Out of memory " ) ;
tprints ( " ??? " ) ;
return - 1 ;
}
alloc_size + = 1 + ( style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ? 0 : 2 ) ;
if ( use_alloca ( alloc_size ) ) {
outstr = alloca ( alloc_size ) ;
buf = NULL ;
} else {
outstr = buf = malloc ( alloc_size ) ;
if ( ! buf ) {
error_msg ( " Out of memory " ) ;
tprints ( " ??? " ) ;
return - 1 ;
}
}
rc = string_quote ( str , outstr , size , style ) ;
tprints ( outstr ) ;
free ( buf ) ;
return rc ;
}
2008-11-11 02:19:13 +03:00
/*
* Print path string specified by address ` addr ' and length ` n ' .
* If path length exceeds ` n ' , append ` . . . ' to the output .
*/
1999-02-19 03:21:36 +03:00
void
2014-09-10 17:46:04 +04:00
printpathn ( struct tcb * tcp , long addr , unsigned int n )
1999-02-19 03:21:36 +03:00
{
2014-11-22 01:28:34 +03:00
char path [ PATH_MAX + 1 ] ;
2012-01-20 14:56:00 +04:00
int nul_seen ;
2012-01-19 20:20:23 +04:00
2008-11-11 02:19:13 +03:00
if ( ! addr ) {
2011-09-01 12:00:28 +04:00
tprints ( " NULL " ) ;
2007-10-09 01:48:01 +04:00
return ;
}
2012-01-20 14:56:00 +04:00
/* Cap path length to the path buffer size */
2008-11-11 02:19:13 +03:00
if ( n > sizeof path - 1 )
n = sizeof path - 1 ;
/* Fetch one byte more to find out whether path length > n. */
2012-01-20 14:56:00 +04:00
nul_seen = umovestr ( tcp , addr , n + 1 , path ) ;
if ( nul_seen < 0 )
1999-02-19 03:21:36 +03:00
tprintf ( " %#lx " , addr ) ;
else {
2015-01-26 04:17:08 +03:00
path [ n + + ] = ' \0 ' ;
print_quoted_string ( path , n , QUOTE_0_TERMINATED ) ;
2012-01-20 14:56:00 +04:00
if ( ! nul_seen )
2012-01-19 20:20:23 +04:00
tprints ( " ... " ) ;
1999-02-19 03:21:36 +03:00
}
}
void
2007-10-09 01:48:01 +04:00
printpath ( struct tcb * tcp , long addr )
{
2012-01-19 20:20:23 +04:00
/* Size must correspond to char path[] size in printpathn */
2014-11-22 01:28:34 +03:00
printpathn ( tcp , addr , PATH_MAX ) ;
2007-10-09 01:48:01 +04:00
}
2008-11-11 02:19:13 +03:00
/*
* Print string specified by address ` addr ' and length ` len ' .
* If ` len ' < 0 , treat the string as a NUL - terminated string .
* If string length exceeds ` max_strlen ' , append ` . . . ' to the output .
*/
2007-10-09 01:48:01 +04:00
void
2012-04-28 16:58:35 +04:00
printstr ( struct tcb * tcp , long addr , long len )
1999-02-19 03:21:36 +03:00
{
2007-10-09 01:48:01 +04:00
static char * str = NULL ;
1999-02-19 03:21:36 +03:00
static char * outstr ;
2014-09-10 17:46:04 +04:00
unsigned int size ;
2015-01-26 04:17:08 +03:00
unsigned int style ;
2012-01-19 20:20:23 +04:00
int ellipsis ;
1999-02-19 03:21:36 +03:00
if ( ! addr ) {
2011-09-01 12:00:28 +04:00
tprints ( " NULL " ) ;
1999-02-19 03:21:36 +03:00
return ;
}
2008-11-11 02:19:13 +03:00
/* Allocate static buffers if they are not allocated yet. */
2011-08-31 16:00:02 +04:00
if ( ! str ) {
2012-03-26 02:56:53 +04:00
unsigned int outstr_size = 4 * max_strlen + /*for quotes and NUL:*/ 3 ;
if ( outstr_size / 4 ! = max_strlen )
die_out_of_memory ( ) ;
2008-11-11 02:19:13 +03:00
str = malloc ( max_strlen + 1 ) ;
2011-08-31 16:00:02 +04:00
if ( ! str )
die_out_of_memory ( ) ;
2012-03-26 02:56:53 +04:00
outstr = malloc ( outstr_size ) ;
2011-08-31 16:00:02 +04:00
if ( ! outstr )
die_out_of_memory ( ) ;
1999-02-19 03:21:36 +03:00
}
2007-10-09 01:48:01 +04:00
2015-01-26 04:17:08 +03:00
size = max_strlen ;
2012-04-28 16:58:35 +04:00
if ( len = = - 1 ) {
2008-11-11 02:19:13 +03:00
/*
* Treat as a NUL - terminated string : fetch one byte more
2015-01-26 04:17:08 +03:00
* because string_quote may look one byte ahead .
2008-11-11 02:19:13 +03:00
*/
2015-01-26 04:17:08 +03:00
if ( umovestr ( tcp , addr , size + 1 , str ) < 0 ) {
1999-02-19 03:21:36 +03:00
tprintf ( " %#lx " , addr ) ;
return ;
}
2015-01-26 04:17:08 +03:00
style = QUOTE_0_TERMINATED ;
1999-02-19 03:21:36 +03:00
}
else {
2012-04-28 16:58:35 +04:00
if ( size > ( unsigned long ) len )
size = ( unsigned long ) len ;
2007-10-09 01:48:01 +04:00
if ( umoven ( tcp , addr , size , str ) < 0 ) {
1999-02-19 03:21:36 +03:00
tprintf ( " %#lx " , addr ) ;
return ;
}
2015-01-26 04:17:08 +03:00
style = 0 ;
1999-02-19 03:21:36 +03:00
}
2012-01-20 14:56:00 +04:00
/* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
* or we were requested to print more than - s NUM chars ) . . .
*/
2015-01-26 04:17:08 +03:00
ellipsis = ( string_quote ( str , outstr , size , style ) & &
2014-09-10 17:46:04 +04:00
( len < 0 | | ( unsigned long ) len > max_strlen ) ) ;
1999-02-19 03:21:36 +03:00
2012-01-19 20:20:23 +04:00
tprints ( outstr ) ;
if ( ellipsis )
tprints ( " ... " ) ;
1999-02-19 03:21:36 +03:00
}
2001-07-10 17:48:44 +04:00
void
2011-05-30 16:00:14 +04:00
dumpiov ( struct tcb * tcp , int len , long addr )
2001-07-10 17:48:44 +04:00
{
2012-02-25 05:38:52 +04:00
# if SUPPORTED_PERSONALITIES > 1
2006-12-13 20:08:08 +03:00
union {
struct { u_int32_t base ; u_int32_t len ; } * iov32 ;
struct { u_int64_t base ; u_int64_t len ; } * iov64 ;
} iovu ;
# define iov iovu.iov64
# define sizeof_iov \
2012-03-19 12:36:42 +04:00
( current_wordsize = = 4 ? sizeof ( * iovu . iov32 ) : sizeof ( * iovu . iov64 ) )
2006-12-13 20:08:08 +03:00
# define iov_iov_base(i) \
2012-03-19 12:36:42 +04:00
( current_wordsize = = 4 ? ( uint64_t ) iovu . iov32 [ i ] . base : iovu . iov64 [ i ] . base )
2006-12-13 20:08:08 +03:00
# define iov_iov_len(i) \
2012-03-19 12:36:42 +04:00
( current_wordsize = = 4 ? ( uint64_t ) iovu . iov32 [ i ] . len : iovu . iov64 [ i ] . len )
2006-12-13 20:08:08 +03:00
# else
2001-07-10 17:48:44 +04:00
struct iovec * iov ;
2006-12-13 20:08:08 +03:00
# define sizeof_iov sizeof(*iov)
# define iov_iov_base(i) iov[i].iov_base
# define iov_iov_len(i) iov[i].iov_len
# endif
2001-07-10 17:48:44 +04:00
int i ;
2011-09-01 18:35:44 +04:00
unsigned size ;
2001-07-10 17:48:44 +04:00
2011-09-01 18:35:44 +04:00
size = sizeof_iov * len ;
/* Assuming no sane program has millions of iovs */
if ( ( unsigned ) len > 1024 * 1024 /* insane or negative size? */
2006-12-13 20:08:08 +03:00
| | ( iov = malloc ( size ) ) = = NULL ) {
2011-09-01 18:35:44 +04:00
fprintf ( stderr , " Out of memory \n " ) ;
return ;
2001-07-10 17:48:44 +04:00
}
2005-06-01 23:22:06 +04:00
if ( umoven ( tcp , addr , size , ( char * ) iov ) > = 0 ) {
2001-07-10 17:48:44 +04:00
for ( i = 0 ; i < len ; i + + ) {
2008-12-30 21:47:55 +03:00
/* 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_iov_len ( i ) , i ) ;
dumpstr ( tcp , ( long ) iov_iov_base ( i ) ,
iov_iov_len ( i ) ) ;
}
2001-07-10 17:48:44 +04:00
}
2011-09-01 18:35:44 +04:00
free ( iov ) ;
2006-12-13 20:08:08 +03:00
# undef sizeof_iov
# undef iov_iov_base
# undef iov_iov_len
# undef iov
2001-07-10 17:48:44 +04:00
}
1999-02-19 03:21:36 +03:00
void
2011-05-30 16:00:14 +04:00
dumpstr ( struct tcb * tcp , long addr , int len )
1999-02-19 03:21:36 +03:00
{
static int strsize = - 1 ;
static unsigned char * str ;
2013-02-22 17:47:39 +04:00
char outbuf [
(
( sizeof (
" xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx "
" 1234567890123456 " ) + /*in case I'm off by few:*/ 4 )
/*align to 8 to make memset easier:*/ + 7 ) & - 8
] ;
const unsigned char * src ;
int i ;
memset ( outbuf , ' ' , sizeof ( outbuf ) ) ;
if ( strsize < len + 16 ) {
2011-08-20 14:48:18 +04:00
free ( str ) ;
2013-02-22 17:47:39 +04:00
str = malloc ( len + 16 ) ;
2011-09-01 18:35:44 +04:00
if ( ! str ) {
strsize = - 1 ;
fprintf ( stderr , " Out of memory \n " ) ;
return ;
}
2013-02-22 17:47:39 +04:00
strsize = len + 16 ;
1999-02-19 03:21:36 +03:00
}
if ( umoven ( tcp , addr , len , ( char * ) str ) < 0 )
return ;
2013-02-22 17:47:39 +04:00
/* Space-pad to 16 bytes */
i = len ;
while ( i & 0xf )
str [ i + + ] = ' ' ;
i = 0 ;
src = str ;
while ( i < len ) {
char * dst = outbuf ;
/* Hex dump */
do {
if ( i < len ) {
* dst + + = " 0123456789abcdef " [ * src > > 4 ] ;
* dst + + = " 0123456789abcdef " [ * src & 0xf ] ;
1999-02-19 03:21:36 +03:00
}
else {
2013-02-22 17:47:39 +04:00
* dst + + = ' ' ;
* dst + + = ' ' ;
1999-02-19 03:21:36 +03:00
}
2013-02-22 17:47:39 +04:00
dst + + ; /* space is there by memset */
i + + ;
if ( ( i & 7 ) = = 0 )
dst + + ; /* space is there by memset */
src + + ;
} while ( i & 0xf ) ;
/* ASCII dump */
i - = 16 ;
src - = 16 ;
do {
if ( * src > = ' ' & & * src < 0x7f )
* dst + + = * src ;
1999-02-19 03:21:36 +03:00
else
2013-02-22 17:47:39 +04:00
* dst + + = ' . ' ;
src + + ;
} while ( + + i & 0xf ) ;
* dst = ' \0 ' ;
2013-02-22 18:00:11 +04:00
tprintf ( " | %05x %s | \n " , i - 16 , outbuf ) ;
1999-02-19 03:21:36 +03:00
}
}
2012-02-14 17:38:28 +04:00
# ifdef HAVE_PROCESS_VM_READV
/* C library supports this, but the kernel might not. */
static bool process_vm_readv_not_supported = 0 ;
# else
2012-01-28 04:46:33 +04:00
/* Need to do this since process_vm_readv() is not yet available in libc.
* When libc is be updated , only " static bool process_vm_readv_not_supported "
* line should remain .
*/
# if !defined(__NR_process_vm_readv)
# if defined(I386)
# define __NR_process_vm_readv 347
# elif defined(X86_64)
# define __NR_process_vm_readv 310
# elif defined(POWERPC)
# define __NR_process_vm_readv 351
# endif
# endif
# if defined(__NR_process_vm_readv)
static bool process_vm_readv_not_supported = 0 ;
2012-05-05 03:37:29 +04:00
/* Have to avoid duplicating with the C library headers. */
static ssize_t strace_process_vm_readv ( pid_t pid ,
2012-01-28 04:46:33 +04:00
const struct iovec * lvec ,
unsigned long liovcnt ,
const struct iovec * rvec ,
unsigned long riovcnt ,
unsigned long flags )
{
return syscall ( __NR_process_vm_readv , ( long ) pid , lvec , liovcnt , rvec , riovcnt , flags ) ;
}
2012-05-05 03:37:29 +04:00
# define process_vm_readv strace_process_vm_readv
2012-01-28 04:46:33 +04:00
# else
static bool process_vm_readv_not_supported = 1 ;
# define process_vm_readv(...) (errno = ENOSYS, -1)
# endif
2012-02-14 17:38:28 +04:00
# endif /* end of hack */
2012-01-28 04:46:33 +04:00
1999-02-19 03:21:36 +03:00
# define PAGMASK (~(PAGSIZ - 1))
/*
* move ` len ' bytes of data from process ` pid '
* at address ` addr ' to our space at ` laddr '
*/
int
2015-01-14 11:05:45 +03:00
umoven ( struct tcb * tcp , long addr , unsigned int len , char * laddr )
1999-02-19 03:21:36 +03:00
{
2009-06-03 03:49:22 +04:00
int pid = tcp - > pid ;
2015-01-14 11:05:45 +03:00
unsigned int n , m , nread ;
1999-02-19 03:21:36 +03:00
union {
long val ;
char x [ sizeof ( long ) ] ;
} u ;
2013-02-19 20:39:56 +04:00
# if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
2012-03-19 12:36:42 +04:00
if ( current_wordsize < sizeof ( addr ) )
addr & = ( 1ul < < 8 * current_wordsize ) - 1 ;
2012-02-25 03:43:22 +04:00
# endif
2012-01-28 04:46:33 +04:00
if ( ! process_vm_readv_not_supported ) {
struct iovec local [ 1 ] , remote [ 1 ] ;
int r ;
local [ 0 ] . iov_base = laddr ;
remote [ 0 ] . iov_base = ( void * ) addr ;
local [ 0 ] . iov_len = remote [ 0 ] . iov_len = len ;
2013-02-27 01:16:22 +04:00
r = process_vm_readv ( pid , local , 1 , remote , 1 , 0 ) ;
2015-01-14 11:05:45 +03:00
if ( ( unsigned int ) r = = len )
Make umoven report success as 0, not >=0, stop returning success on partial reads
umoven() uses process_vm_readv() when available but it returns the
return value of that syscall, which is the number of bytes copied,
while its callers expect it to simply return zero on success.
It was causing syscalls that take a user-space argument to print
the abbreviated version, e.g.:
epoll_ctl(5, EPOLL_CTL_ADD, 10, {...})
Instead of:
epoll_ctl(5, EPOLL_CTL_ADD, 10, {EPOLLIN, {u32=10, u64=10}})
* util.c (umoven): Make umove[n] report success as 0, not >=0,
stop returning "success" on partial reads.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2013-02-26 15:24:25 +04:00
return 0 ;
2013-02-27 01:16:22 +04:00
if ( r > = 0 ) {
2015-01-14 11:05:45 +03:00
error_msg ( " umoven: short read (%u < %u) @0x%lx " ,
( unsigned int ) r , len , addr ) ;
2013-02-27 01:16:22 +04:00
return - 1 ;
}
switch ( errno ) {
case ENOSYS :
2012-01-28 04:46:33 +04:00
process_vm_readv_not_supported = 1 ;
2013-02-27 01:16:22 +04:00
break ;
case ESRCH :
/* the process is gone */
return - 1 ;
case EFAULT : case EIO : case EPERM :
/* address space is inaccessible */
return - 1 ;
default :
/* all the rest is strange and should be reported */
2013-02-26 15:30:09 +04:00
perror_msg ( " process_vm_readv " ) ;
2013-02-27 01:16:22 +04:00
return - 1 ;
2012-01-28 04:46:33 +04:00
}
}
2013-02-27 01:16:22 +04:00
nread = 0 ;
1999-02-19 03:21:36 +03:00
if ( addr & ( sizeof ( long ) - 1 ) ) {
/* addr not a multiple of sizeof(long) */
2015-01-14 11:05:45 +03:00
n = addr & ( sizeof ( long ) - 1 ) ; /* residue */
addr & = - sizeof ( long ) ; /* aligned address */
2009-06-03 03:49:22 +04:00
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
2013-02-27 01:16:22 +04:00
switch ( errno ) {
case 0 :
break ;
case ESRCH : case EINVAL :
/* these could be seen if the process is gone */
return - 1 ;
case EFAULT : case EIO : case EPERM :
/* address space is inaccessible */
return - 1 ;
default :
/* all the rest is strange and should be reported */
perror_msg ( " umoven: PTRACE_PEEKDATA pid:%d @0x%lx " ,
pid , addr ) ;
return - 1 ;
2009-06-03 03:49:22 +04:00
}
2012-01-21 07:01:56 +04:00
m = MIN ( sizeof ( long ) - n , len ) ;
memcpy ( laddr , & u . x [ n ] , m ) ;
2013-03-01 21:52:59 +04:00
addr + = sizeof ( long ) ;
laddr + = m ;
nread + = m ;
len - = m ;
1999-02-19 03:21:36 +03:00
}
while ( len ) {
2009-06-03 03:49:22 +04:00
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
2013-02-27 01:16:22 +04:00
switch ( errno ) {
case 0 :
break ;
case ESRCH : case EINVAL :
/* these could be seen if the process is gone */
return - 1 ;
case EFAULT : case EIO : case EPERM :
/* address space is inaccessible */
if ( nread ) {
2015-01-14 11:05:45 +03:00
perror_msg ( " umoven: short read (%u < %u) @0x%lx " ,
2013-02-27 01:16:22 +04:00
nread , nread + len , addr - nread ) ;
}
return - 1 ;
default :
/* all the rest is strange and should be reported */
perror_msg ( " umoven: PTRACE_PEEKDATA pid:%d @0x%lx " ,
pid , addr ) ;
return - 1 ;
2009-06-03 03:49:22 +04:00
}
2012-01-21 07:01:56 +04:00
m = MIN ( sizeof ( long ) , len ) ;
memcpy ( laddr , u . x , m ) ;
2013-03-01 21:52:59 +04:00
addr + = sizeof ( long ) ;
laddr + = m ;
nread + = m ;
len - = m ;
1999-02-19 03:21:36 +03:00
}
return 0 ;
}
/*
2012-01-20 14:56:00 +04:00
* Like ` umove ' but make the additional effort of looking
1999-02-19 03:21:36 +03:00
* for a terminating zero byte .
2012-01-20 14:56:00 +04:00
*
* Returns < 0 on error , > 0 if NUL was seen ,
* ( TODO if useful : return count of bytes including NUL ) ,
* else 0 if len bytes were read but no NUL byte seen .
*
* Note : there is no guarantee we won ' t overwrite some bytes
* in laddr [ ] _after_ terminating NUL ( but , of course ,
* we never write past laddr [ len - 1 ] ) .
1999-02-19 03:21:36 +03:00
*/
int
2015-01-14 11:05:45 +03:00
umovestr ( struct tcb * tcp , long addr , unsigned int len , char * laddr )
1999-02-19 03:21:36 +03:00
{
2013-03-01 21:52:59 +04:00
# if SIZEOF_LONG == 4
const unsigned long x01010101 = 0x01010101ul ;
const unsigned long x80808080 = 0x80808080ul ;
# elif SIZEOF_LONG == 8
const unsigned long x01010101 = 0x0101010101010101ul ;
const unsigned long x80808080 = 0x8080808080808080ul ;
# else
# error SIZEOF_LONG > 8
# endif
2009-06-03 03:49:22 +04:00
int pid = tcp - > pid ;
2015-01-14 11:05:45 +03:00
unsigned int n , m , nread ;
1999-02-19 03:21:36 +03:00
union {
2013-03-01 21:52:59 +04:00
unsigned long val ;
1999-02-19 03:21:36 +03:00
char x [ sizeof ( long ) ] ;
} u ;
2013-02-19 20:39:56 +04:00
# if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
2012-03-19 12:36:42 +04:00
if ( current_wordsize < sizeof ( addr ) )
addr & = ( 1ul < < 8 * current_wordsize ) - 1 ;
2011-12-27 00:12:02 +04:00
# endif
2013-02-27 01:16:22 +04:00
nread = 0 ;
2012-01-28 04:46:33 +04:00
if ( ! process_vm_readv_not_supported ) {
struct iovec local [ 1 ] , remote [ 1 ] ;
local [ 0 ] . iov_base = laddr ;
remote [ 0 ] . iov_base = ( void * ) addr ;
while ( len > 0 ) {
2015-01-14 11:05:45 +03:00
unsigned int chunk_len ;
unsigned int end_in_page ;
2012-01-28 04:46:33 +04:00
int r ;
/* Don't read kilobytes: most strings are short */
chunk_len = len ;
if ( chunk_len > 256 )
chunk_len = 256 ;
/* Don't cross pages. I guess otherwise we can get EFAULT
* and fail to notice that terminating NUL lies
* in the existing ( first ) page .
* ( I hope there aren ' t arches with pages < 4 K )
*/
end_in_page = ( ( addr + chunk_len ) & 4095 ) ;
2015-01-14 11:05:45 +03:00
if ( chunk_len > end_in_page ) /* crosses to the next page */
chunk_len - = end_in_page ;
2012-01-28 04:46:33 +04:00
local [ 0 ] . iov_len = remote [ 0 ] . iov_len = chunk_len ;
2013-02-27 01:16:22 +04:00
r = process_vm_readv ( pid , local , 1 , remote , 1 , 0 ) ;
if ( r > 0 ) {
if ( memchr ( local [ 0 ] . iov_base , ' \0 ' , r ) )
return 1 ;
local [ 0 ] . iov_base + = r ;
remote [ 0 ] . iov_base + = r ;
len - = r ;
nread + = r ;
continue ;
}
switch ( errno ) {
case ENOSYS :
2012-01-28 04:46:33 +04:00
process_vm_readv_not_supported = 1 ;
2013-02-27 01:16:22 +04:00
goto vm_readv_didnt_work ;
case ESRCH :
/* the process is gone */
return - 1 ;
case EFAULT : case EIO : case EPERM :
/* address space is inaccessible */
if ( nread ) {
perror_msg ( " umovestr: short read (%d < %d) @0x%lx " ,
nread , nread + len , addr ) ;
}
return - 1 ;
default :
/* all the rest is strange and should be reported */
2013-02-26 15:30:09 +04:00
perror_msg ( " process_vm_readv " ) ;
2013-02-27 01:16:22 +04:00
return - 1 ;
2012-01-28 04:46:33 +04:00
}
}
return 0 ;
}
vm_readv_didnt_work :
1999-02-19 03:21:36 +03:00
if ( addr & ( sizeof ( long ) - 1 ) ) {
/* addr not a multiple of sizeof(long) */
2015-01-14 11:05:45 +03:00
n = addr & ( sizeof ( long ) - 1 ) ; /* residue */
addr & = - sizeof ( long ) ; /* aligned address */
2009-06-03 03:49:22 +04:00
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
2013-02-27 01:16:22 +04:00
switch ( errno ) {
case 0 :
break ;
case ESRCH : case EINVAL :
/* these could be seen if the process is gone */
return - 1 ;
case EFAULT : case EIO : case EPERM :
/* address space is inaccessible */
return - 1 ;
default :
/* all the rest is strange and should be reported */
perror_msg ( " umovestr: PTRACE_PEEKDATA pid:%d @0x%lx " ,
pid , addr ) ;
return - 1 ;
2009-06-03 03:49:22 +04:00
}
2012-01-21 07:01:56 +04:00
m = MIN ( sizeof ( long ) - n , len ) ;
memcpy ( laddr , & u . x [ n ] , m ) ;
1999-02-19 03:21:36 +03:00
while ( n & ( sizeof ( long ) - 1 ) )
if ( u . x [ n + + ] = = ' \0 ' )
2012-01-20 14:56:00 +04:00
return 1 ;
2013-03-01 21:52:59 +04:00
addr + = sizeof ( long ) ;
laddr + = m ;
nread + = m ;
len - = m ;
1999-02-19 03:21:36 +03:00
}
2013-03-01 21:52:59 +04:00
1999-02-19 03:21:36 +03:00
while ( len ) {
2009-06-03 03:49:22 +04:00
errno = 0 ;
u . val = ptrace ( PTRACE_PEEKDATA , pid , ( char * ) addr , 0 ) ;
2013-02-27 01:16:22 +04:00
switch ( errno ) {
case 0 :
break ;
case ESRCH : case EINVAL :
/* these could be seen if the process is gone */
return - 1 ;
case EFAULT : case EIO : case EPERM :
/* address space is inaccessible */
if ( nread ) {
perror_msg ( " umovestr: short read (%d < %d) @0x%lx " ,
nread , nread + len , addr - nread ) ;
}
return - 1 ;
default :
/* all the rest is strange and should be reported */
perror_msg ( " umovestr: PTRACE_PEEKDATA pid:%d @0x%lx " ,
pid , addr ) ;
return - 1 ;
2009-06-03 03:49:22 +04:00
}
2012-01-21 07:01:56 +04:00
m = MIN ( sizeof ( long ) , len ) ;
memcpy ( laddr , u . x , m ) ;
2013-03-01 21:52:59 +04:00
/* "If a NUL char exists in this word" */
if ( ( u . val - x01010101 ) & ~ u . val & x80808080 )
return 1 ;
addr + = sizeof ( long ) ;
laddr + = m ;
nread + = m ;
len - = m ;
1999-02-19 03:21:36 +03:00
}
2001-05-15 18:53:43 +04:00
return 0 ;
1999-02-19 03:21:36 +03:00
}
int
2013-06-28 16:35:47 +04:00
upeek ( int pid , long off , long * res )
1999-02-19 03:21:36 +03:00
{
long val ;
2009-06-03 03:49:22 +04:00
errno = 0 ;
2013-06-28 16:35:47 +04:00
val = ptrace ( PTRACE_PEEKUSER , ( pid_t ) pid , ( char * ) off , 0 ) ;
2009-06-03 03:49:22 +04:00
if ( val = = - 1 & & errno ) {
if ( errno ! = ESRCH ) {
2013-06-28 16:35:47 +04:00
perror_msg ( " upeek: PTRACE_PEEKUSER pid:%d @0x%lx) " , pid , off ) ;
2009-06-03 03:49:22 +04:00
}
1999-02-19 03:21:36 +03:00
return - 1 ;
2009-06-03 03:49:22 +04:00
}
1999-02-19 03:21:36 +03:00
* res = val ;
return 0 ;
}
2013-02-12 15:50:10 +04:00
/* Note! On new kernels (about 2.5.46+), we use PTRACE_O_TRACECLONE
* and PTRACE_O_TRACE [ V ] FORK for tracing children .
* If you are adding a new arch which is only supported by newer kernels ,
* you most likely don ' t need to add any code below
* beside a dummy " return 0 " block in change_syscall ( ) .
*/
2009-02-09 21:55:59 +03:00
/*
* These # if ' s are huge , please indent them correctly .
* It ' s easy to get confused otherwise .
*/
1999-02-19 03:21:36 +03:00
2012-02-25 05:46:14 +04:00
# include "syscall.h"
2008-05-20 04:34:34 +04:00
2012-02-25 05:46:14 +04:00
# ifndef CLONE_PTRACE
# define CLONE_PTRACE 0x00002000
# endif
# ifndef CLONE_VFORK
# define CLONE_VFORK 0x00004000
# endif
# ifndef CLONE_VM
# define CLONE_VM 0x00000100
# endif
2003-01-09 09:53:34 +03:00
2012-02-25 05:46:14 +04:00
# ifdef IA64
2003-01-09 09:53:34 +03:00
typedef unsigned long * arg_setup_state ;
static int
arg_setup ( struct tcb * tcp , arg_setup_state * state )
{
2008-08-07 01:38:52 +04:00
unsigned long cfm , sof , sol ;
long bsp ;
2003-01-09 09:53:34 +03:00
2013-07-01 14:28:17 +04:00
if ( ia64_ia32mode ) {
2008-08-07 01:38:52 +04:00
/* Satisfy a false GCC warning. */
* state = NULL ;
2004-02-21 01:56:43 +03:00
return 0 ;
2008-08-07 01:38:52 +04:00
}
2004-02-21 01:56:43 +03:00
2013-06-28 16:35:47 +04:00
if ( upeek ( tcp - > pid , PT_AR_BSP , & bsp ) < 0 )
2003-01-09 09:53:34 +03:00
return - 1 ;
2013-06-28 16:35:47 +04:00
if ( upeek ( tcp - > pid , PT_CFM , ( long * ) & cfm ) < 0 )
2003-01-09 09:53:34 +03:00
return - 1 ;
sof = ( cfm > > 0 ) & 0x7f ;
sol = ( cfm > > 7 ) & 0x7f ;
2008-08-07 01:38:52 +04:00
bsp = ( long ) ia64_rse_skip_regs ( ( unsigned long * ) bsp , - sof + sol ) ;
2003-01-09 09:53:34 +03:00
2008-08-07 01:38:52 +04:00
* state = ( unsigned long * ) bsp ;
2003-01-09 09:53:34 +03:00
return 0 ;
}
2012-02-25 05:46:14 +04:00
# define arg_finish_change(tcp, state) 0
2003-01-09 09:53:34 +03:00
static int
2011-05-30 16:00:14 +04:00
get_arg0 ( struct tcb * tcp , arg_setup_state * state , long * valp )
2003-01-09 09:53:34 +03:00
{
2004-02-21 01:56:43 +03:00
int ret ;
2013-07-01 14:28:17 +04:00
if ( ia64_ia32mode )
2013-06-28 16:35:47 +04:00
ret = upeek ( tcp - > pid , PT_R11 , valp ) ;
2004-02-21 01:56:43 +03:00
else
2011-06-07 14:13:24 +04:00
ret = umoven ( tcp ,
2004-02-21 01:56:43 +03:00
( unsigned long ) ia64_rse_skip_regs ( * state , 0 ) ,
sizeof ( long ) , ( void * ) valp ) ;
return ret ;
2003-01-09 09:53:34 +03:00
}
static int
2011-05-30 16:00:14 +04:00
get_arg1 ( struct tcb * tcp , arg_setup_state * state , long * valp )
2003-01-09 09:53:34 +03:00
{
2004-02-21 01:56:43 +03:00
int ret ;
2013-07-01 14:28:17 +04:00
if ( ia64_ia32mode )
2013-06-28 16:35:47 +04:00
ret = upeek ( tcp - > pid , PT_R9 , valp ) ;
2004-02-21 01:56:43 +03:00
else
2011-06-07 14:13:24 +04:00
ret = umoven ( tcp ,
2004-02-21 01:56:43 +03:00
( unsigned long ) ia64_rse_skip_regs ( * state , 1 ) ,
sizeof ( long ) , ( void * ) valp ) ;
return ret ;
2003-01-09 09:53:34 +03:00
}
static int
2011-05-30 16:00:14 +04:00
set_arg0 ( struct tcb * tcp , arg_setup_state * state , long val )
2003-01-09 09:53:34 +03:00
{
2004-02-21 01:56:43 +03:00
int req = PTRACE_POKEDATA ;
void * ap ;
2013-07-01 14:28:17 +04:00
if ( ia64_ia32mode ) {
2004-02-21 01:56:43 +03:00
ap = ( void * ) ( intptr_t ) PT_R11 ; /* r11 == EBX */
req = PTRACE_POKEUSER ;
} else
ap = ia64_rse_skip_regs ( * state , 0 ) ;
2009-06-03 03:49:22 +04:00
errno = 0 ;
ptrace ( req , tcp - > pid , ap , val ) ;
return errno ? - 1 : 0 ;
2003-01-09 09:53:34 +03:00
}
static int
2011-05-30 16:00:14 +04:00
set_arg1 ( struct tcb * tcp , arg_setup_state * state , long val )
2003-01-09 09:53:34 +03:00
{
2004-02-21 01:56:43 +03:00
int req = PTRACE_POKEDATA ;
void * ap ;
2013-07-01 14:28:17 +04:00
if ( ia64_ia32mode ) {
2004-02-21 01:56:43 +03:00
ap = ( void * ) ( intptr_t ) PT_R9 ; /* r9 == ECX */
req = PTRACE_POKEUSER ;
} else
ap = ia64_rse_skip_regs ( * state , 1 ) ;
2009-06-03 03:49:22 +04:00
errno = 0 ;
ptrace ( req , tcp - > pid , ap , val ) ;
return errno ? - 1 : 0 ;
2003-01-09 09:53:34 +03:00
}
2008-07-18 05:19:36 +04:00
/* ia64 does not return the input arguments from functions (and syscalls)
according to ia64 RSE ( Register Stack Engine ) behavior . */
2012-02-25 05:46:14 +04:00
# define restore_arg0(tcp, state, val) ((void) (state), 0)
# define restore_arg1(tcp, state, val) ((void) (state), 0)
2008-07-18 05:19:36 +04:00
2012-02-25 05:46:14 +04:00
# elif defined(SPARC) || defined(SPARC64)
2003-01-09 09:53:34 +03:00
Optimize out PTRACE_PEEKUSER with -i
strace -i was fetching PC with a separate PEEKUSER
despite having GETREGS data:
ptrace(PTRACE_GETREGS, 22331, 0, 0x8087f00) = 0
ptrace(PTRACE_PEEKUSER, 22331, 4*EIP, [0x80dd7b7]) = 0
write(3, "[080dd7b7] ioctl(0, SNDCTL_TMR_T"..., 82) = 82
ptrace(PTRACE_SYSCALL, 22331, 0, SIG_0) = 0
Now it does this:
ptrace(PTRACE_GETREGS, 22549, 0, 0x8087ea0) = 0
write(3, "[080dd7b7] ioctl(0, SNDCTL_TMR_T"..., 82) = 82
ptrace(PTRACE_SYSCALL, 22549, 0, SIG_0) = 0
Analogous improvement in sys_sigreturn() is also implemented.
* defs.h: Declare extern struct pt_regs regs for SPARC[64] and ARM.
Declare clear_regs(), get_regs() and get_regs_error flag variable.
* strace.c (trace): Call get_regs(pid) as soon as we know the tcb
and that it is stopped.
* syscall.c (get_regs): New function. Used to fetch registers early,
just after tracee has stopped.
(printcall): Move it here from util.c. Use global regs.REG data,
if available on the arch, instead of re-fetching it.
(get_scno): Use global regs.REG data.
(get_syscall_result): Likewise.
* signal.c (sys_sigreturn): Likewise.
* util.c (printcall): Moved to syscall.c.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2013-02-05 19:36:13 +04:00
# if defined(SPARC64)
# undef PTRACE_GETREGS
# define PTRACE_GETREGS PTRACE_GETREGS64
# undef PTRACE_SETREGS
# define PTRACE_SETREGS PTRACE_SETREGS64
# endif
sparc/linux: Rewrite to use asm/ptrace.h
The current sparc/linux code uses asm/reg.h, but recent Linux kernels
dropped that header completely. So switch over to the ptrace headers
as those should stick around indefinitely as part of the ABI.
* defs.h [LINUXSPARC] (U_REG_G1, U_REG_O0, U_REG_O1): Define.
* process.c: Drop asm/regs.h include.
[SPARC || SPARC64] (change_syscall): Change struct regs to struct pt_regs.
* signal.c: Drop asm/regs.h include.
(m_siginfo_t): Unify [SPARC || SPARC64] and [MIPS].
[SPARC || SPARC64] (sys_sigreturn): Change struct regs to struct pt_regs.
* syscall.c: Drop asm/regs.h include.
[SPARC || SPARC64] (internal_syscall, get_scno, get_error, force_result,
syscall_enter): Change struct regs to struct pt_regs.
* util.c: Drop asm/regs.h include.
(_hack_syscall5, _ptrace): Delete.
[SPARC || SPARC64] (getpc, printcall, arg_setup_state): Change
struct regs to struct pt_regs.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
2009-10-12 19:05:14 +04:00
typedef struct pt_regs arg_setup_state ;
2003-01-09 09:53:34 +03:00
2012-02-25 05:46:14 +04:00
# 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 ) )
2003-01-09 09:53:34 +03:00
2012-02-25 05:46:14 +04:00
# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
# define restore_arg0(tcp, state, val) 0
2003-01-09 09:53:34 +03:00
2012-02-25 05:46:14 +04:00
# else /* other architectures */
2003-01-09 09:53:34 +03:00
2012-02-25 05:46:14 +04:00
# 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 . */
2012-02-25 05:46:14 +04:00
# 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)
# define arg0_index 1
# define arg1_index 0
# elif defined(ALPHA) || defined(MIPS)
# define arg0_offset REG_A0
# define arg1_offset (REG_A0+1)
# elif defined(POWERPC)
# define arg0_offset (sizeof(unsigned long)*PT_R3)
# define arg1_offset (sizeof(unsigned long)*PT_R4)
# define restore_arg0(tcp, state, val) ((void) (state), 0)
# elif defined(HPPA)
# define arg0_offset PT_GR26
# define arg1_offset (PT_GR26-4)
Add x32 support to strace
X32 support is added to Linux kernel 3.4. In a nutshell, x32 is x86-64 with
32bit pointers. At system call level, x32 is also identical to x86-64,
as shown by many changes like "defined(X86_64) || defined(X32)". The
main differerence bewteen x32 and x86-64 is off_t in x32 is long long
instead of long.
This patch adds x32 support to strace. Tested on Linux/x32.
* configure.ac: Support X32.
* defs.h: Set SUPPORTED_PERSONALITIES to 3 for X86_64,
Set PERSONALITY2_WORDSIZE to 4 for X86_64.
Add tcb::ext_arg for X32.
* file.c (stat): New for X32.
(sys_lseek): Use 64-bit version for X32.
(printstat64): Check current_personality != 1 for X86_64.
* ipc.c (indirect_ipccall): Check current_personality == 1
for X86_64.
* mem.c (sys_mmap64): Also use tcp->u_arg for X32. Print NULL
for zero address. Call printllval for offset for X32.
* pathtrace.c (pathtrace_match): Don't check sys_old_mmap for
X32.
* process.c (ARG_FLAGS): Defined for X32.
(ARG_STACK): Likewise.
(ARG_PTID): Likewise.
(change_syscall): Handle X32.
(struct_user_offsets): Support X32.
(sys_arch_prctl): Likewise.
* signal.c: Include <asm/sigcontext.h> for X32.
(SA_RESTORER): Also define for X32.
* syscall.c (update_personality): Support X32 for X86_64.
(is_restart_error): Likewise.
(syscall_fixup_on_sysenter): Likewise.
(get_syscall_args): Likewise.
(get_syscall_result): Likewise.
(get_error): Likewise.
(__X32_SYSCALL_BIT): Define if not defined.
(__X32_SYSCALL_MASK): Likewise.
(get_scno): Check DS register value for X32. Use
__X32_SYSCALL_MASK on X32 system calls.
* util.c (printllval): Use ext_arg for X32.
(printcall): Support X32.
(change_syscall): Likewise.
(arg0_offset): Likewise.
(arg1_offset): Likewise.
* Makefile.am (EXTRA_DIST): Add linux/x32/errnoent.h,
linux/x32/ioctlent.h.in, linux/x32/signalent.h,
linux/x32/syscallent.h, linux/x86_64/errnoent2.h,
linux/x86_64/ioctlent2.h, linux/x86_64/signalent2.h and
linux/x86_64/syscallent2.h.
* linux/x32/errnoent.h: New.
* linux/x32/ioctlent.h.in: Likewise.
* linux/x32/signalent.h: Likewise.
* linux/x32/syscallent.h: Likewise.
* linux/x86_64/errnoent2.h: Likewise.
* linux/x86_64/ioctlent2.h: Likewise.
* linux/x86_64/signalent2.h: Likewise.
* linux/x86_64/syscallent2.h: Likewise.
Signed-off-by: H.J. Lu <hongjiu.lu@intel.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2012-04-16 15:00:01 +04:00
# elif defined(X86_64) || defined(X32)
2012-02-25 05:46:14 +04:00
# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
# elif defined(SH)
# define arg0_offset (4*(REG_REG0+4))
# define arg1_offset (4*(REG_REG0+5))
# elif defined(SH64)
/* 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
# elif defined CRISV10 || defined CRISV32
# define arg0_offset (4*PT_R11)
# define arg1_offset (4*PT_ORIG_R10)
# define restore_arg0(tcp, state, val) 0
# define restore_arg1(tcp, state, val) 0
# define arg0_index 1
# define arg1_index 0
# else
# define arg0_offset 0
# define arg1_offset 4
# if defined ARM
# define restore_arg0(tcp, state, val) 0
# endif
# endif
2003-01-09 09:53:34 +03:00
typedef int arg_setup_state ;
2012-02-25 05:46:14 +04:00
# define arg_setup(tcp, state) (0)
# define arg_finish_change(tcp, state) 0
2013-06-28 16:35:47 +04:00
# define get_arg0(tcp, cookie, valp) (upeek((tcp)->pid, arg0_offset, (valp)))
# define get_arg1(tcp, cookie, valp) (upeek((tcp)->pid, arg1_offset, (valp)))
2003-01-09 09:53:34 +03:00
static int
2011-05-30 16:00:14 +04:00
set_arg0 ( struct tcb * tcp , void * cookie , long val )
2003-01-09 09:53:34 +03:00
{
2011-06-07 14:13:24 +04:00
return ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) arg0_offset , val ) ;
2003-01-09 09:53:34 +03:00
}
static int
2011-05-30 16:00:14 +04:00
set_arg1 ( struct tcb * tcp , void * cookie , long val )
2003-01-09 09:53:34 +03:00
{
2011-06-07 14:13:24 +04:00
return ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) arg1_offset , val ) ;
2003-01-09 09:53:34 +03:00
}
2012-02-25 05:46:14 +04:00
# endif /* architectures */
2003-01-09 09:53:34 +03:00
2012-02-25 05:46:14 +04: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
2012-02-25 05:46:14 +04:00
# ifndef arg0_index
# define arg0_index 0
# define arg1_index 1
# endif
2004-03-02 00:05:16 +03:00
2012-11-29 21:37:37 +04:00
static int
change_syscall ( struct tcb * tcp , arg_setup_state * state , int new )
{
# if defined(I386)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( ORIG_EAX * 4 ) , new ) < 0 )
return - 1 ;
return 0 ;
2013-02-12 16:06:51 +04:00
# elif defined(X86_64)
2012-11-29 21:37:37 +04:00
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( ORIG_RAX * 8 ) , new ) < 0 )
return - 1 ;
return 0 ;
2013-02-12 16:06:51 +04:00
# elif defined(X32)
/* setbpt/clearbpt never used: */
/* X32 is only supported since about linux-3.0.30 */
2012-11-29 21:37:37 +04:00
# elif defined(POWERPC)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid ,
( char * ) ( sizeof ( unsigned long ) * PT_R0 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(S390) || defined(S390X)
/* s390 linux after 2.4.7 has a hook in entry.S to allow this */
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( PT_GPR2 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(M68K)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( 4 * PT_ORIG_D0 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(SPARC) || defined(SPARC64)
state - > u_regs [ U_REG_G1 ] = new ;
return 0 ;
# elif defined(MIPS)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( REG_V0 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(ALPHA)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( REG_A3 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(AVR32)
2013-02-12 15:50:10 +04:00
/* setbpt/clearbpt never used: */
/* AVR32 is only supported since about linux-2.6.19 */
2012-11-29 21:37:37 +04:00
# elif defined(BFIN)
2013-02-12 15:50:10 +04:00
/* setbpt/clearbpt never used: */
/* Blackfin is only supported since about linux-2.6.23 */
2012-11-29 21:37:37 +04:00
# elif defined(IA64)
2013-07-01 14:28:17 +04:00
if ( ia64_ia32mode ) {
2012-11-29 21:37:37 +04:00
switch ( new ) {
case 2 :
break ; /* x86 SYS_fork */
case SYS_clone :
new = 120 ;
break ;
default :
fprintf ( stderr , " %s: unexpected syscall %d \n " ,
__FUNCTION__ , new ) ;
return - 1 ;
}
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( PT_R1 ) , new ) < 0 )
return - 1 ;
} else if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( PT_R15 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(HPPA)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( PT_GR20 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(SH)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( 4 * ( REG_REG0 + 3 ) ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(SH64)
/* Top half of reg encodes the no. of args n as 0x1n.
Assume 0 args as kernel never actually checks . . . */
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( REG_SYSCALL ) ,
0x100000 | new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(CRISV10) || defined(CRISV32)
if ( ptrace ( PTRACE_POKEUSER , tcp - > pid , ( char * ) ( 4 * PT_R9 ) , new ) < 0 )
return - 1 ;
return 0 ;
# elif defined(ARM)
/* Some kernels support this, some (pre-2.6.16 or so) don't. */
# ifndef PTRACE_SET_SYSCALL
# define PTRACE_SET_SYSCALL 23
# endif
if ( ptrace ( PTRACE_SET_SYSCALL , tcp - > pid , 0 , new & 0xffff ) ! = 0 )
return - 1 ;
return 0 ;
2013-02-12 16:06:51 +04:00
# elif defined(AARCH64)
/* setbpt/clearbpt never used: */
/* AARCH64 is only supported since about linux-3.0.31 */
2012-11-29 21:37:37 +04:00
# elif defined(TILE)
2013-02-12 15:50:10 +04:00
/* setbpt/clearbpt never used: */
/* Tilera CPUs are only supported since about linux-2.6.34 */
2012-11-29 21:37:37 +04:00
# elif defined(MICROBLAZE)
2013-02-12 19:07:54 +04:00
/* setbpt/clearbpt never used: */
/* microblaze is only supported since about linux-2.6.30 */
2013-02-14 16:26:27 +04:00
# elif defined(OR1K)
/* never reached; OR1K is only supported by kernels since 3.1.0. */
2013-02-22 18:44:10 +04:00
# elif defined(METAG)
/* setbpt/clearbpt never used: */
/* Meta is only supported since linux-3.7 */
2013-03-25 21:22:07 +04:00
# elif defined(XTENSA)
/* setbpt/clearbpt never used: */
/* Xtensa is only supported since linux 2.6.13 */
2013-08-16 11:17:06 +04:00
# elif defined(ARC)
/* setbpt/clearbpt never used: */
/* ARC only supported since 3.9 */
2012-11-29 21:37:37 +04:00
# else
# warning Do not know how to handle change_syscall for this architecture
# endif /* architecture */
return - 1 ;
}
2003-01-09 09:53:34 +03:00
int
Two cleanups: tcb table expansion failure is not really a survivable
event, we do not have any viable way to continue. No wonder most
places where that is detected have FIXMEs.
It's way simpler to treat as fatal failure, and handle it inside
tcb table expansion finctions.
Second cleanup: tidy up haphazard locations of a few externs.
* defs.h: Change return type of expand_tcbtab() to void.
Declare change_syscall().
* process.c: Change all callsites of alloctcb(), alloc_tcb() and
fork_tcb(), removing now-redundant error checks.
(fork_tcb): Change return type to void - it can't fail now.
* strace.c: Move extern declarations out of function bodies.
Change all callsites of alloctcb(), alloc_tcb() and
fork_tcb(), removing now-redundant error checks.
(expand_tcbtab): Change return type to void - it can't fail now.
On failure to expand, print a message, clean up, and exit.
(alloc_tcb): On failure to expand, print a message, clean up, and exit.
* util.c (setbpt): Remove extern declaration from function body.
2009-01-17 04:52:54 +03:00
setbpt ( struct tcb * tcp )
2003-01-09 09:53:34 +03:00
{
2008-05-20 04:34:34 +04:00
static int clone_scno [ SUPPORTED_PERSONALITIES ] = { SYS_clone } ;
2003-01-09 09:53:34 +03:00
arg_setup_state state ;
if ( tcp - > flags & TCB_BPTSET ) {
fprintf ( stderr , " PANIC: TCB already set in pid %u \n " , tcp - > pid ) ;
return - 1 ;
}
2008-05-20 04:34:34 +04:00
/*
* It ' s a silly kludge to initialize this with a search at runtime .
* But it ' s better than maintaining another magic thing in the
* godforsaken tables .
*/
if ( clone_scno [ current_personality ] = = 0 ) {
2014-09-10 17:46:04 +04:00
unsigned int i ;
2008-05-20 04:34:34 +04:00
for ( i = 0 ; i < nsyscalls ; + + i )
if ( sysent [ i ] . sys_func = = sys_clone ) {
clone_scno [ current_personality ] = i ;
break ;
}
}
2014-05-12 17:43:10 +04:00
if ( tcp - > s_ent - > sys_func = = sys_fork ) {
2011-06-07 14:13:24 +04:00
if ( arg_setup ( tcp , & state ) < 0
| | get_arg0 ( tcp , & state , & tcp - > inst [ 0 ] ) < 0
| | get_arg1 ( tcp , & state , & tcp - > inst [ 1 ] ) < 0
2012-11-29 21:37:37 +04:00
| | change_syscall ( tcp , & state ,
clone_scno [ current_personality ] ) < 0
2011-06-07 14:13:24 +04:00
| | set_arg0 ( tcp , & state , CLONE_PTRACE | SIGCHLD ) < 0
| | set_arg1 ( tcp , & state , 0 ) < 0
| | arg_finish_change ( tcp , & state ) < 0 )
2003-01-09 09:53:34 +03:00
return - 1 ;
2004-03-01 23:57:09 +03:00
tcp - > u_arg [ arg0_index ] = CLONE_PTRACE | SIGCHLD ;
tcp - > u_arg [ arg1_index ] = 0 ;
2003-01-09 09:53:34 +03:00
tcp - > flags | = TCB_BPTSET ;
return 0 ;
2012-02-21 01:17:58 +04:00
}
2003-01-09 09:53:34 +03:00
2013-02-21 19:13:47 +04:00
if ( tcp - > s_ent - > sys_func = = sys_clone ) {
2008-08-07 01:43:35 +04:00
/* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
2012-02-21 01:17:58 +04:00
contrary to x86 vfork above . Even on x86 we turn the
2008-08-07 01:43:35 +04:00
vfork semantics into plain fork - each application must not
depend on the vfork specifics according to POSIX . We would
hang waiting for the parent resume otherwise . We need to
clear also CLONE_VM but only in the CLONE_VFORK case as
otherwise we would break pthread_create . */
2011-06-23 23:57:54 +04:00
long new_arg0 = ( tcp - > u_arg [ arg0_index ] | CLONE_PTRACE ) ;
if ( new_arg0 & CLONE_VFORK )
new_arg0 & = ~ ( unsigned long ) ( CLONE_VFORK | CLONE_VM ) ;
if ( arg_setup ( tcp , & state ) < 0
| | set_arg0 ( tcp , & state , new_arg0 ) < 0
| | arg_finish_change ( tcp , & state ) < 0 )
2009-02-27 23:32:52 +03:00
return - 1 ;
2004-03-01 23:57:09 +03:00
tcp - > inst [ 0 ] = tcp - > u_arg [ arg0_index ] ;
tcp - > inst [ 1 ] = tcp - > u_arg [ arg1_index ] ;
2012-05-14 18:40:28 +04:00
tcp - > flags | = TCB_BPTSET ;
2003-01-09 09:53:34 +03:00
return 0 ;
}
2012-02-21 01:17:58 +04:00
fprintf ( stderr , " PANIC: setbpt for syscall %ld on %u??? \n " ,
tcp - > scno , tcp - > pid ) ;
2003-01-09 09:53:34 +03:00
return - 1 ;
}
int
2011-05-30 16:00:14 +04:00
clearbpt ( struct tcb * tcp )
2003-01-09 09:53:34 +03:00
{
arg_setup_state state ;
2011-06-07 14:13:24 +04:00
if ( arg_setup ( tcp , & state ) < 0
2012-11-29 21:37:37 +04:00
| | change_syscall ( tcp , & state , tcp - > scno ) < 0
2011-06-07 14:13:24 +04:00
| | restore_arg0 ( tcp , & state , tcp - > inst [ 0 ] ) < 0
| | restore_arg1 ( tcp , & state , tcp - > inst [ 1 ] ) < 0
| | arg_finish_change ( tcp , & state ) )
2011-06-23 23:57:54 +04:00
if ( errno ! = ESRCH )
return - 1 ;
2003-01-09 09:53:34 +03:00
tcp - > flags & = ~ TCB_BPTSET ;
return 0 ;
}