2007-10-16 12:27:00 +04:00
/*
* Copyright ( C ) 2002 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-17 02:20:36 +04:00
* Licensed under the GPL
*/
# include <stdio.h>
2007-10-16 12:27:00 +04:00
# include <unistd.h>
2005-04-17 02:20:36 +04:00
# include <errno.h>
# include <signal.h>
2007-10-16 12:27:11 +04:00
# include <fcntl.h>
2005-04-17 02:20:36 +04:00
# include <sys/mman.h>
2007-10-16 12:27:00 +04:00
# include <sys/ptrace.h>
2005-04-17 02:20:36 +04:00
# include <sys/wait.h>
2007-10-16 12:27:00 +04:00
# include <asm/unistd.h>
2012-10-08 06:27:32 +04:00
# include <init.h>
# include <longjmp.h>
# include <os.h>
# include <skas_ptrace.h>
2005-04-17 02:20:36 +04:00
# define ARBITRARY_ADDR -1
# define FAILURE_PID -1
# define STAT_PATH_LEN sizeof(" / proc / ####### / stat\0")
# define COMM_SCANF "%*[^)])"
unsigned long os_process_pc ( int pid )
{
char proc_stat [ STAT_PATH_LEN ] , buf [ 256 ] ;
2007-10-16 12:27:11 +04:00
unsigned long pc = ARBITRARY_ADDR ;
2005-04-17 02:20:36 +04:00
int fd , err ;
sprintf ( proc_stat , " /proc/%d/stat " , pid ) ;
2007-10-16 12:27:11 +04:00
fd = open ( proc_stat , O_RDONLY , 0 ) ;
2007-10-16 12:27:00 +04:00
if ( fd < 0 ) {
printk ( UM_KERN_ERR " os_process_pc - couldn't open '%s', "
2007-10-16 12:27:11 +04:00
" errno = %d \n " , proc_stat , errno ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2007-05-07 01:51:35 +04:00
CATCH_EINTR ( err = read ( fd , buf , sizeof ( buf ) ) ) ;
2007-10-16 12:27:00 +04:00
if ( err < 0 ) {
printk ( UM_KERN_ERR " os_process_pc - couldn't read '%s', "
" err = %d \n " , proc_stat , errno ) ;
2007-10-16 12:27:11 +04:00
goto out_close ;
2005-04-17 02:20:36 +04:00
}
os_close_file ( fd ) ;
pc = ARBITRARY_ADDR ;
2007-10-16 12:27:00 +04:00
if ( sscanf ( buf , " %*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
2007-10-16 12:27:11 +04:00
" %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
" %*d %*d %*d %*d %*d %lu " , & pc ) ! = 1 )
2007-10-16 12:27:00 +04:00
printk ( UM_KERN_ERR " os_process_pc - couldn't find pc in '%s' \n " ,
buf ) ;
2007-10-16 12:27:11 +04:00
out_close :
close ( fd ) ;
out :
2007-05-07 01:51:33 +04:00
return pc ;
2005-04-17 02:20:36 +04:00
}
int os_process_parent ( int pid )
{
char stat [ STAT_PATH_LEN ] ;
char data [ 256 ] ;
2007-10-16 12:27:11 +04:00
int parent = FAILURE_PID , n , fd ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:00 +04:00
if ( pid = = - 1 )
2007-10-16 12:27:11 +04:00
return parent ;
2005-04-17 02:20:36 +04:00
snprintf ( stat , sizeof ( stat ) , " /proc/%d/stat " , pid ) ;
2007-10-16 12:27:11 +04:00
fd = open ( stat , O_RDONLY , 0 ) ;
2007-10-16 12:27:00 +04:00
if ( fd < 0 ) {
2007-10-16 12:27:11 +04:00
printk ( UM_KERN_ERR " Couldn't open '%s', errno = %d \n " , stat ,
errno ) ;
return parent ;
2005-04-17 02:20:36 +04:00
}
2007-05-07 01:51:35 +04:00
CATCH_EINTR ( n = read ( fd , data , sizeof ( data ) ) ) ;
2007-10-16 12:27:11 +04:00
close ( fd ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:00 +04:00
if ( n < 0 ) {
2007-10-16 12:27:11 +04:00
printk ( UM_KERN_ERR " Couldn't read '%s', errno = %d \n " , stat ,
2007-10-16 12:27:00 +04:00
errno ) ;
2007-10-16 12:27:11 +04:00
return parent ;
2005-04-17 02:20:36 +04:00
}
parent = FAILURE_PID ;
n = sscanf ( data , " %*d " COMM_SCANF " %*c %d " , & parent ) ;
2007-10-16 12:27:00 +04:00
if ( n ! = 1 )
printk ( UM_KERN_ERR " Failed to scan '%s' \n " , data ) ;
2005-04-17 02:20:36 +04:00
2007-05-07 01:51:33 +04:00
return parent ;
2005-04-17 02:20:36 +04:00
}
void os_stop_process ( int pid )
{
kill ( pid , SIGSTOP ) ;
}
void os_kill_process ( int pid , int reap_child )
{
kill ( pid , SIGKILL ) ;
2007-10-16 12:27:00 +04:00
if ( reap_child )
2007-12-18 03:19:46 +03:00
CATCH_EINTR ( waitpid ( pid , NULL , __WALL ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-25 00:03:55 +03:00
/* This is here uniquely to have access to the userspace errno, i.e. the one
* used by ptrace in case of error .
*/
long os_ptrace_ldt ( long pid , long addr , long data )
{
int ret ;
ret = ptrace ( PTRACE_LDT , pid , addr , data ) ;
if ( ret < 0 )
return - errno ;
return ret ;
}
2005-04-17 02:20:36 +04:00
/* Kill off a ptraced child by all means available. kill it normally first,
* then PTRACE_KILL it , then PTRACE_CONT it in case it ' s in a run state from
* which it can ' t exit directly .
*/
void os_kill_ptraced_process ( int pid , int reap_child )
{
kill ( pid , SIGKILL ) ;
ptrace ( PTRACE_KILL , pid ) ;
ptrace ( PTRACE_CONT , pid ) ;
2007-10-16 12:27:00 +04:00
if ( reap_child )
2007-12-18 03:19:46 +03:00
CATCH_EINTR ( waitpid ( pid , NULL , __WALL ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:57:47 +04:00
/* Don't use the glibc version, which caches the result in TLS. It misses some
* syscalls , and also breaks with clone ( ) , which does not unshare the TLS .
*/
2005-04-17 02:20:36 +04:00
int os_getpid ( void )
{
2007-05-07 01:51:33 +04:00
return syscall ( __NR_getpid ) ;
2005-04-17 02:20:36 +04:00
}
2005-05-06 03:15:32 +04:00
int os_getpgrp ( void )
{
return getpgrp ( ) ;
}
2005-04-17 02:20:36 +04:00
int os_map_memory ( void * virt , int fd , unsigned long long off , unsigned long len ,
int r , int w , int x )
{
void * loc ;
int prot ;
2007-10-16 12:27:00 +04:00
prot = ( r ? PROT_READ : 0 ) | ( w ? PROT_WRITE : 0 ) |
2005-04-17 02:20:36 +04:00
( x ? PROT_EXEC : 0 ) ;
loc = mmap64 ( ( void * ) virt , len , prot , MAP_SHARED | MAP_FIXED ,
fd , off ) ;
2007-10-16 12:27:00 +04:00
if ( loc = = MAP_FAILED )
2007-05-07 01:51:33 +04:00
return - errno ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
int os_protect_memory ( void * addr , unsigned long len , int r , int w , int x )
{
2007-10-16 12:27:00 +04:00
int prot = ( ( r ? PROT_READ : 0 ) | ( w ? PROT_WRITE : 0 ) |
2005-04-17 02:20:36 +04:00
( x ? PROT_EXEC : 0 ) ) ;
2007-10-16 12:27:00 +04:00
if ( mprotect ( addr , len , prot ) < 0 )
2007-05-07 01:51:33 +04:00
return - errno ;
2007-10-16 12:27:00 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
int os_unmap_memory ( void * addr , int len )
{
2007-10-16 12:27:00 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:00 +04:00
err = munmap ( addr , len ) ;
if ( err < 0 )
2007-05-07 01:51:33 +04:00
return - errno ;
2007-10-16 12:27:00 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 14:30:08 +04:00
# ifndef MADV_REMOVE
2006-04-19 09:20:24 +04:00
# define MADV_REMOVE KERNEL_MADV_REMOVE
2006-03-31 14:30:08 +04:00
# endif
2007-07-24 05:43:48 +04:00
int os_drop_memory ( void * addr , int length )
2006-03-31 14:30:08 +04:00
{
int err ;
err = madvise ( addr , length , MADV_REMOVE ) ;
2007-10-16 12:27:00 +04:00
if ( err < 0 )
2006-03-31 14:30:08 +04:00
err = - errno ;
return err ;
}
2007-05-07 01:51:11 +04:00
int __init can_drop_memory ( void )
2006-03-31 14:30:08 +04:00
{
void * addr ;
2006-05-01 23:15:58 +04:00
int fd , ok = 0 ;
2006-03-31 14:30:08 +04:00
2007-10-16 12:27:00 +04:00
printk ( UM_KERN_INFO " Checking host MADV_REMOVE support... " ) ;
2006-03-31 14:30:08 +04:00
fd = create_mem_file ( UM_KERN_PAGE_SIZE ) ;
2007-10-16 12:27:00 +04:00
if ( fd < 0 ) {
printk ( UM_KERN_ERR " Creating test memory file failed, "
" err = %d \n " , - fd ) ;
2006-05-01 23:15:58 +04:00
goto out ;
2006-03-31 14:30:08 +04:00
}
addr = mmap64 ( NULL , UM_KERN_PAGE_SIZE , PROT_READ | PROT_WRITE ,
2006-04-19 09:20:24 +04:00
MAP_SHARED , fd , 0 ) ;
2007-10-16 12:27:00 +04:00
if ( addr = = MAP_FAILED ) {
printk ( UM_KERN_ERR " Mapping test memory file failed, "
" err = %d \n " , - errno ) ;
2006-05-01 23:15:58 +04:00
goto out_close ;
2006-03-31 14:30:08 +04:00
}
2007-10-16 12:27:00 +04:00
if ( madvise ( addr , UM_KERN_PAGE_SIZE , MADV_REMOVE ) ! = 0 ) {
printk ( UM_KERN_ERR " MADV_REMOVE failed, err = %d \n " , - errno ) ;
2006-05-01 23:15:58 +04:00
goto out_unmap ;
2006-03-31 14:30:08 +04:00
}
2008-02-08 15:22:08 +03:00
printk ( UM_KERN_CONT " OK \n " ) ;
2006-05-01 23:15:58 +04:00
ok = 1 ;
out_unmap :
munmap ( addr , UM_KERN_PAGE_SIZE ) ;
out_close :
close ( fd ) ;
out :
return ok ;
2006-03-31 14:30:08 +04:00
}
2006-07-10 15:45:07 +04:00
void init_new_thread_signals ( void )
2005-09-04 02:57:47 +04:00
{
2011-08-18 23:04:39 +04:00
set_handler ( SIGSEGV ) ;
set_handler ( SIGTRAP ) ;
set_handler ( SIGFPE ) ;
set_handler ( SIGILL ) ;
set_handler ( SIGBUS ) ;
2005-09-04 02:57:47 +04:00
signal ( SIGHUP , SIG_IGN ) ;
2011-08-18 23:04:39 +04:00
set_handler ( SIGIO ) ;
2008-02-05 09:31:16 +03:00
signal ( SIGWINCH , SIG_IGN ) ;
2011-05-25 04:13:04 +04:00
signal ( SIGTERM , SIG_DFL ) ;
2005-09-04 02:57:47 +04:00
}