|
@@ -1,4 +1,4 @@
|
|
|
-/*
|
|
|
+/*
|
|
|
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
|
|
|
* Licensed under the GPL
|
|
|
*/
|
|
@@ -19,7 +19,6 @@
|
|
|
#include "user_util.h"
|
|
|
#include "kern_util.h"
|
|
|
#include "user.h"
|
|
|
-#include "process.h"
|
|
|
#include "signal_kern.h"
|
|
|
#include "signal_user.h"
|
|
|
#include "sysdep/ptrace.h"
|
|
@@ -39,98 +38,6 @@
|
|
|
#include "registers.h"
|
|
|
#endif
|
|
|
|
|
|
-void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
|
|
|
-{
|
|
|
- int flags = 0, pages;
|
|
|
-
|
|
|
- if(sig_stack != NULL){
|
|
|
- pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
|
|
|
- set_sigstack(sig_stack, pages * page_size());
|
|
|
- flags = SA_ONSTACK;
|
|
|
- }
|
|
|
- if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
|
|
|
-}
|
|
|
-
|
|
|
-void init_new_thread_signals(int altstack)
|
|
|
-{
|
|
|
- int flags = altstack ? SA_ONSTACK : 0;
|
|
|
-
|
|
|
- set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
|
|
|
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
|
|
|
- set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
|
|
|
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
|
|
|
- set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
|
|
|
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
|
|
|
- set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
|
|
|
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
|
|
|
- set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
|
|
|
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
|
|
|
- set_handler(SIGUSR2, (__sighandler_t) sig_handler,
|
|
|
- flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
|
|
|
- signal(SIGHUP, SIG_IGN);
|
|
|
-
|
|
|
- init_irq_signals(altstack);
|
|
|
-}
|
|
|
-
|
|
|
-struct tramp {
|
|
|
- int (*tramp)(void *);
|
|
|
- void *tramp_data;
|
|
|
- unsigned long temp_stack;
|
|
|
- int flags;
|
|
|
- int pid;
|
|
|
-};
|
|
|
-
|
|
|
-/* See above for why sigkill is here */
|
|
|
-
|
|
|
-int sigkill = SIGKILL;
|
|
|
-
|
|
|
-int outer_tramp(void *arg)
|
|
|
-{
|
|
|
- struct tramp *t;
|
|
|
- int sig = sigkill;
|
|
|
-
|
|
|
- t = arg;
|
|
|
- t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
|
|
|
- t->flags, t->tramp_data);
|
|
|
- if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
|
|
|
- kill(os_getpid(), sig);
|
|
|
- _exit(0);
|
|
|
-}
|
|
|
-
|
|
|
-int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
|
|
|
- int clone_flags, int (*tramp)(void *))
|
|
|
-{
|
|
|
- struct tramp arg;
|
|
|
- unsigned long sp;
|
|
|
- int new_pid, status, err;
|
|
|
-
|
|
|
- /* The trampoline will run on the temporary stack */
|
|
|
- sp = stack_sp(temp_stack);
|
|
|
-
|
|
|
- clone_flags |= CLONE_FILES | SIGCHLD;
|
|
|
-
|
|
|
- arg.tramp = tramp;
|
|
|
- arg.tramp_data = thread_arg;
|
|
|
- arg.temp_stack = temp_stack;
|
|
|
- arg.flags = clone_flags;
|
|
|
-
|
|
|
- /* Start the process and wait for it to kill itself */
|
|
|
- new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
|
|
|
- if(new_pid < 0)
|
|
|
- return(new_pid);
|
|
|
-
|
|
|
- CATCH_EINTR(err = waitpid(new_pid, &status, 0));
|
|
|
- if(err < 0)
|
|
|
- panic("Waiting for outer trampoline failed - errno = %d",
|
|
|
- errno);
|
|
|
-
|
|
|
- if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
|
|
|
- panic("outer trampoline didn't exit with SIGKILL, "
|
|
|
- "status = %d", status);
|
|
|
-
|
|
|
- return(arg.pid);
|
|
|
-}
|
|
|
-
|
|
|
static int ptrace_child(void *arg)
|
|
|
{
|
|
|
int ret;
|
|
@@ -165,7 +72,7 @@ static int start_ptraced_child(void **stack_out)
|
|
|
void *stack;
|
|
|
unsigned long sp;
|
|
|
int pid, n, status;
|
|
|
-
|
|
|
+
|
|
|
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
|
if(stack == MAP_FAILED)
|
|
@@ -173,10 +80,10 @@ static int start_ptraced_child(void **stack_out)
|
|
|
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
|
|
|
pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
|
|
|
if(pid < 0)
|
|
|
- panic("check_ptrace : clone failed, errno = %d", errno);
|
|
|
+ panic("start_ptraced_child : clone failed, errno = %d", errno);
|
|
|
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
|
|
if(n < 0)
|
|
|
- panic("check_ptrace : wait failed, errno = %d", errno);
|
|
|
+ panic("check_ptrace : clone failed, errno = %d", errno);
|
|
|
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
|
|
|
panic("check_ptrace : expected SIGSTOP, got status = %d",
|
|
|
status);
|
|
@@ -185,11 +92,14 @@ static int start_ptraced_child(void **stack_out)
|
|
|
return(pid);
|
|
|
}
|
|
|
|
|
|
-/* When testing for SYSEMU support, if it is one of the broken versions, we must
|
|
|
- * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
|
|
|
+/* When testing for SYSEMU support, if it is one of the broken versions, we
|
|
|
+ * must just avoid using sysemu, not panic, but only if SYSEMU features are
|
|
|
+ * broken.
|
|
|
* So only for SYSEMU features we test mustpanic, while normal host features
|
|
|
- * must work anyway!*/
|
|
|
-static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
|
|
|
+ * must work anyway!
|
|
|
+ */
|
|
|
+static int stop_ptraced_child(int pid, void *stack, int exitcode,
|
|
|
+ int mustpanic)
|
|
|
{
|
|
|
int status, n, ret = 0;
|
|
|
|
|
@@ -217,8 +127,6 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int force_sysemu_disabled = 0;
|
|
|
-
|
|
|
int ptrace_faultinfo = 1;
|
|
|
int proc_mm = 1;
|
|
|
|
|
@@ -228,24 +136,27 @@ static int __init skas0_cmd_param(char *str, int* add)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+__uml_setup("skas0", skas0_cmd_param,
|
|
|
+ "skas0\n"
|
|
|
+ " Disables SKAS3 usage, so that SKAS0 is used, unless \n"
|
|
|
+ " you specify mode=tt.\n\n");
|
|
|
+
|
|
|
+static int force_sysemu_disabled = 0;
|
|
|
+
|
|
|
static int __init nosysemu_cmd_param(char *str, int* add)
|
|
|
{
|
|
|
force_sysemu_disabled = 1;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-__uml_setup("skas0", skas0_cmd_param,
|
|
|
- "skas0\n"
|
|
|
- " Disables SKAS3 usage, so that SKAS0 is used, unless you \n"
|
|
|
- " specify mode=tt.\n\n");
|
|
|
-
|
|
|
__uml_setup("nosysemu", nosysemu_cmd_param,
|
|
|
- "nosysemu\n"
|
|
|
- " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
|
|
|
- " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
|
|
|
- " behaviour of ptrace() and helps reducing host context switch rate.\n"
|
|
|
- " To make it working, you need a kernel patch for your host, too.\n"
|
|
|
- " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n");
|
|
|
+"nosysemu\n"
|
|
|
+" Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
|
|
|
+" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
|
|
|
+" behaviour of ptrace() and helps reducing host context switch rate.\n"
|
|
|
+" To make it working, you need a kernel patch for your host, too.\n"
|
|
|
+" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
|
|
|
+" information.\n\n");
|
|
|
|
|
|
static void __init check_sysemu(void)
|
|
|
{
|
|
@@ -321,7 +232,7 @@ fail_stopped:
|
|
|
printk("missing\n");
|
|
|
}
|
|
|
|
|
|
-void __init check_ptrace(void)
|
|
|
+static void __init check_ptrace(void)
|
|
|
{
|
|
|
void *stack;
|
|
|
int pid, syscall, n, status;
|
|
@@ -329,12 +240,12 @@ void __init check_ptrace(void)
|
|
|
printk("Checking that ptrace can change system call numbers...");
|
|
|
pid = start_ptraced_child(&stack);
|
|
|
|
|
|
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
|
|
- panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
|
|
|
+ if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
|
|
+ panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno);
|
|
|
|
|
|
while(1){
|
|
|
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
|
|
- panic("check_ptrace : ptrace failed, errno = %d",
|
|
|
+ panic("check_ptrace : ptrace failed, errno = %d",
|
|
|
errno);
|
|
|
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
|
|
if(n < 0)
|
|
@@ -342,7 +253,7 @@ void __init check_ptrace(void)
|
|
|
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80))
|
|
|
panic("check_ptrace : expected SIGTRAP + 0x80, "
|
|
|
"got status = %d", status);
|
|
|
-
|
|
|
+
|
|
|
syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
|
|
|
0);
|
|
|
if(syscall == __NR_getpid){
|
|
@@ -359,33 +270,12 @@ void __init check_ptrace(void)
|
|
|
check_sysemu();
|
|
|
}
|
|
|
|
|
|
-int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
|
|
|
-{
|
|
|
- sigjmp_buf buf;
|
|
|
- int n;
|
|
|
-
|
|
|
- *jmp_ptr = &buf;
|
|
|
- n = sigsetjmp(buf, 1);
|
|
|
- if(n != 0)
|
|
|
- return(n);
|
|
|
- (*fn)(arg);
|
|
|
- return(0);
|
|
|
-}
|
|
|
-
|
|
|
-void forward_pending_sigio(int target)
|
|
|
+void os_early_checks(void)
|
|
|
{
|
|
|
- sigset_t sigs;
|
|
|
-
|
|
|
- if(sigpending(&sigs))
|
|
|
- panic("forward_pending_sigio : sigpending failed");
|
|
|
- if(sigismember(&sigs, SIGIO))
|
|
|
- kill(target, SIGIO);
|
|
|
+ check_ptrace();
|
|
|
}
|
|
|
|
|
|
-extern void *__syscall_stub_start, __syscall_stub_end;
|
|
|
-
|
|
|
#ifdef UML_CONFIG_MODE_SKAS
|
|
|
-
|
|
|
static inline void check_skas3_ptrace_support(void)
|
|
|
{
|
|
|
struct ptrace_faultinfo fi;
|
|
@@ -400,9 +290,8 @@ static inline void check_skas3_ptrace_support(void)
|
|
|
ptrace_faultinfo = 0;
|
|
|
if(errno == EIO)
|
|
|
printf("not found\n");
|
|
|
- else {
|
|
|
+ else
|
|
|
perror("not found");
|
|
|
- }
|
|
|
}
|
|
|
else {
|
|
|
if (!ptrace_faultinfo)
|
|
@@ -419,9 +308,10 @@ int can_do_skas(void)
|
|
|
{
|
|
|
printf("Checking for /proc/mm...");
|
|
|
if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
|
|
|
- proc_mm = 0;
|
|
|
+ proc_mm = 0;
|
|
|
printf("not found\n");
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ else {
|
|
|
if (!proc_mm)
|
|
|
printf("found but disabled on command line\n");
|
|
|
else
|