uml: throw out CONFIG_MODE_TT
This patchset throws out tt mode, which has been non-functional for a while. This is done in phases, interspersed with code cleanups on the affected files. The removal is done as follows: remove all code, config options, and files which depend on CONFIG_MODE_TT get rid of the CHOOSE_MODE macro, which decided whether to call tt-mode or skas-mode code, and replace invocations with their skas portions replace all now-trivial procedures with their skas equivalents There are now a bunch of now-redundant pieces of data structures, including mode-specific pieces of the thread structure, pt_regs, and mm_context. These are all replaced with their skas-specific contents. As part of the ongoing style compliance project, I made a style pass over all files that were changed. There are three such patches, one for each phase, covering the files affected by that phase but no later ones. I noticed that we weren't freeing the LDT state associated with a process when it exited, so that's fixed in one of the later patches. The last patch is a tidying patch which I've had for a while, but which caused inexplicable crashes under tt mode. Since that is no longer a problem, this can now go in. This patch: Start getting rid of tt mode support. This patch throws out CONFIG_MODE_TT and all config options, code, and files which depend on it. CONFIG_MODE_SKAS is gone and everything that depends on it is included unconditionally. The few changed lines are in re-written Kconfig help, lines which needed something skas-related removed from them, and a few more which weren't strictly deletions. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
a1ff5878d2
commit
42fda66387
@ -9,15 +9,12 @@ clean-files :=
|
||||
obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
|
||||
physmem.o process.o ptrace.o reboot.o sigio.o \
|
||||
signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
|
||||
um_arch.o umid.o
|
||||
um_arch.o umid.o skas/
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
|
||||
obj-$(CONFIG_GPROF) += gprof_syms.o
|
||||
obj-$(CONFIG_GCOV) += gmon_syms.o
|
||||
|
||||
obj-$(CONFIG_MODE_TT) += tt/
|
||||
obj-$(CONFIG_MODE_SKAS) += skas/
|
||||
|
||||
USER_OBJS := config.o
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
||||
|
@ -10,8 +10,6 @@ SECTIONS
|
||||
PROVIDE (__executable_start = START);
|
||||
. = START + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
/* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
|
||||
* is remapped.*/
|
||||
__binary_start = .;
|
||||
. = ALIGN(4096); /* Init code and data */
|
||||
_text = .;
|
||||
|
@ -57,7 +57,6 @@ static long execve1(char *file, char __user * __user *argv,
|
||||
SUBARCH_EXECVE1(¤t->thread.regs.regs);
|
||||
#endif
|
||||
task_unlock(current);
|
||||
set_cmdline(current_cmd());
|
||||
}
|
||||
return(error);
|
||||
}
|
||||
|
@ -46,10 +46,3 @@ union thread_union init_thread_union
|
||||
union thread_union cpu0_irqstack
|
||||
__attribute__((__section__(".data.init_irqstack"))) =
|
||||
{ INIT_THREAD_INFO(init_task) };
|
||||
|
||||
#ifdef CONFIG_MODE_TT
|
||||
void unprotect_stack(unsigned long stack)
|
||||
{
|
||||
os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0);
|
||||
}
|
||||
#endif
|
||||
|
@ -339,30 +339,6 @@ int deactivate_all_fds(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODE_TT
|
||||
void forward_interrupts(int pid)
|
||||
{
|
||||
struct irq_fd *irq;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
spin_lock_irqsave(&irq_lock, flags);
|
||||
for (irq = active_fds; irq != NULL; irq = irq->next) {
|
||||
err = os_set_owner(irq->fd, pid);
|
||||
if (err < 0) {
|
||||
/* XXX Just remove the irq rather than
|
||||
* print out an infinite stream of these
|
||||
*/
|
||||
printk("Failed to forward %d to pid %d, err = %d\n",
|
||||
irq->fd, pid, -err);
|
||||
}
|
||||
|
||||
irq->pid = pid;
|
||||
}
|
||||
spin_unlock_irqrestore(&irq_lock, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* do_IRQ handles all normal device IRQ's (the special
|
||||
* SMP cross-CPU interrupts have their own specific
|
||||
|
@ -34,24 +34,14 @@ EXPORT_SYMBOL(get_kmem_end);
|
||||
EXPORT_SYMBOL(high_physmem);
|
||||
EXPORT_SYMBOL(empty_zero_page);
|
||||
EXPORT_SYMBOL(um_virt_to_phys);
|
||||
EXPORT_SYMBOL(mode_tt);
|
||||
EXPORT_SYMBOL(handle_page_fault);
|
||||
EXPORT_SYMBOL(find_iomem);
|
||||
|
||||
#ifdef CONFIG_MODE_TT
|
||||
EXPORT_SYMBOL(stop);
|
||||
EXPORT_SYMBOL(strncpy_from_user_tt);
|
||||
EXPORT_SYMBOL(copy_from_user_tt);
|
||||
EXPORT_SYMBOL(copy_to_user_tt);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODE_SKAS
|
||||
EXPORT_SYMBOL(strnlen_user_skas);
|
||||
EXPORT_SYMBOL(strncpy_from_user_skas);
|
||||
EXPORT_SYMBOL(copy_to_user_skas);
|
||||
EXPORT_SYMBOL(copy_from_user_skas);
|
||||
EXPORT_SYMBOL(clear_user_skas);
|
||||
#endif
|
||||
EXPORT_SYMBOL(uml_strdup);
|
||||
|
||||
EXPORT_SYMBOL(os_stat_fd);
|
||||
|
@ -183,13 +183,6 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
|
||||
kmalloc_ok = save_kmalloc_ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODE_TT
|
||||
unsigned long stack_sp(unsigned long page)
|
||||
{
|
||||
return page + PAGE_SIZE - sizeof(void *);
|
||||
}
|
||||
#endif
|
||||
|
||||
void default_idle(void)
|
||||
{
|
||||
CHOOSE_MODE(uml_idle_timer(), (void) 0);
|
||||
|
@ -14,28 +14,9 @@
|
||||
|
||||
void (*pm_power_off)(void);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void kill_idlers(int me)
|
||||
{
|
||||
#ifdef CONFIG_MODE_TT
|
||||
struct task_struct *p;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(idle_threads); i++){
|
||||
p = idle_threads[i];
|
||||
if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
|
||||
os_kill_process(p->thread.mode.tt.extern_pid, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kill_off_processes(void)
|
||||
{
|
||||
CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
|
||||
#ifdef CONFIG_SMP
|
||||
kill_idlers(os_getpid());
|
||||
#endif
|
||||
}
|
||||
|
||||
void uml_cleanup(void)
|
||||
|
@ -95,7 +95,6 @@ static int idle_proc(void *cpup)
|
||||
static struct task_struct *idle_thread(int cpu)
|
||||
{
|
||||
struct task_struct *new_task;
|
||||
unsigned char c;
|
||||
|
||||
current->thread.request.u.thread.proc = idle_proc;
|
||||
current->thread.request.u.thread.arg = (void *) cpu;
|
||||
@ -108,9 +107,7 @@ static struct task_struct *idle_thread(int cpu)
|
||||
{ .pid = new_task->thread.mode.tt.extern_pid,
|
||||
.task = new_task } );
|
||||
idle_threads[cpu] = new_task;
|
||||
CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
|
||||
sizeof(c)),
|
||||
({ panic("skas mode doesn't support SMP"); }));
|
||||
panic("skas mode doesn't support SMP");
|
||||
return new_task;
|
||||
}
|
||||
|
||||
|
@ -29,9 +29,7 @@
|
||||
#include "sysdep/sigcontext.h"
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "os.h"
|
||||
#ifdef CONFIG_MODE_SKAS
|
||||
#include "skas.h"
|
||||
#endif
|
||||
#include "os.h"
|
||||
|
||||
/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
|
||||
|
@ -1,14 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
|
||||
syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
|
||||
uaccess.o uaccess_user.o
|
||||
|
||||
obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
|
||||
|
||||
USER_OBJS := gdb.o tracer.o
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/kernel.h"
|
||||
#include "linux/mm.h"
|
||||
#include "asm/signal.h"
|
||||
#include "asm/ptrace.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "asm/pgalloc.h"
|
||||
#include "asm/tlbflush.h"
|
||||
#include "kern_util.h"
|
||||
#include "irq_user.h"
|
||||
#include "mem_user.h"
|
||||
#include "os.h"
|
||||
#include "tlb.h"
|
||||
#include "mode.h"
|
||||
|
||||
static int exec_tramp(void *sig_stack)
|
||||
{
|
||||
init_new_thread_stack(sig_stack, NULL);
|
||||
init_new_thread_signals();
|
||||
os_stop_process(os_getpid());
|
||||
return(0);
|
||||
}
|
||||
|
||||
void flush_thread_tt(void)
|
||||
{
|
||||
unsigned long stack;
|
||||
int new_pid;
|
||||
|
||||
stack = alloc_stack(0, 0);
|
||||
if(stack == 0){
|
||||
printk(KERN_ERR
|
||||
"flush_thread : failed to allocate temporary stack\n");
|
||||
do_exit(SIGKILL);
|
||||
}
|
||||
|
||||
new_pid = start_fork_tramp(task_stack_page(current), stack, 0, exec_tramp);
|
||||
if(new_pid < 0){
|
||||
printk(KERN_ERR
|
||||
"flush_thread : new thread failed, errno = %d\n",
|
||||
-new_pid);
|
||||
do_exit(SIGKILL);
|
||||
}
|
||||
|
||||
if(current_thread->cpu == 0)
|
||||
forward_interrupts(new_pid);
|
||||
current->thread.request.op = OP_EXEC;
|
||||
current->thread.request.u.exec.pid = new_pid;
|
||||
unprotect_stack((unsigned long) current_thread);
|
||||
os_usr1_process(os_getpid());
|
||||
change_sig(SIGUSR1, 1);
|
||||
|
||||
change_sig(SIGUSR1, 0);
|
||||
enable_timer();
|
||||
free_page(stack);
|
||||
protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
|
||||
stack_protections((unsigned long) current_thread);
|
||||
force_flush_all();
|
||||
unblock_signals();
|
||||
}
|
||||
|
||||
void start_thread_tt(struct pt_regs *regs, unsigned long eip,
|
||||
unsigned long esp)
|
||||
{
|
||||
set_fs(USER_DS);
|
||||
flush_tlb_mm(current->mm);
|
||||
PT_REGS_IP(regs) = eip;
|
||||
PT_REGS_SP(regs) = esp;
|
||||
PT_FIX_EXEC_STACK(esp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include "kern_util.h"
|
||||
#include "user.h"
|
||||
#include "ptrace_user.h"
|
||||
#include "os.h"
|
||||
|
||||
void do_exec(int old_pid, int new_pid)
|
||||
{
|
||||
unsigned long regs[FRAME_SIZE];
|
||||
int err;
|
||||
|
||||
if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
|
||||
(ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
|
||||
tracer_panic("do_exec failed to attach proc - errno = %d",
|
||||
errno);
|
||||
|
||||
CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
|
||||
if (err < 0)
|
||||
tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
|
||||
errno);
|
||||
|
||||
if(ptrace_getregs(old_pid, regs) < 0)
|
||||
tracer_panic("do_exec failed to get registers - errno = %d",
|
||||
errno);
|
||||
|
||||
os_kill_ptraced_process(old_pid, 0);
|
||||
|
||||
if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
||||
tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
|
||||
|
||||
if(ptrace_setregs(new_pid, regs) < 0)
|
||||
tracer_panic("do_exec failed to start new proc - errno = %d",
|
||||
errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,280 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include "ptrace_user.h"
|
||||
#include "uml-config.h"
|
||||
#include "kern_constants.h"
|
||||
#include "chan_user.h"
|
||||
#include "init.h"
|
||||
#include "user.h"
|
||||
#include "debug.h"
|
||||
#include "kern_util.h"
|
||||
#include "tt.h"
|
||||
#include "sysdep/thread.h"
|
||||
#include "os.h"
|
||||
|
||||
extern int debugger_pid;
|
||||
extern int debugger_fd;
|
||||
extern int debugger_parent;
|
||||
|
||||
int detach(int pid, int sig)
|
||||
{
|
||||
return(ptrace(PTRACE_DETACH, pid, 0, sig));
|
||||
}
|
||||
|
||||
int attach(int pid)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ptrace(PTRACE_ATTACH, pid, 0, 0);
|
||||
if(err < 0) return(-errno);
|
||||
else return(err);
|
||||
}
|
||||
|
||||
int cont(int pid)
|
||||
{
|
||||
return(ptrace(PTRACE_CONT, pid, 0, 0));
|
||||
}
|
||||
|
||||
#ifdef UML_CONFIG_PT_PROXY
|
||||
|
||||
int debugger_signal(int status, pid_t pid)
|
||||
{
|
||||
return(debugger_proxy(status, pid));
|
||||
}
|
||||
|
||||
void child_signal(pid_t pid, int status)
|
||||
{
|
||||
child_proxy(pid, status);
|
||||
}
|
||||
|
||||
static void gdb_announce(char *dev_name, int dev)
|
||||
{
|
||||
printf("gdb assigned device '%s'\n", dev_name);
|
||||
}
|
||||
|
||||
static struct chan_opts opts = {
|
||||
.announce = gdb_announce,
|
||||
.xterm_title = "UML kernel debugger",
|
||||
.raw = 0,
|
||||
.tramp_stack = 0,
|
||||
.in_kernel = 0,
|
||||
};
|
||||
|
||||
/* Accessed by the tracing thread, which automatically serializes access */
|
||||
static void *xterm_data;
|
||||
static int xterm_fd;
|
||||
|
||||
extern void *xterm_init(char *, int, struct chan_opts *);
|
||||
extern int xterm_open(int, int, int, void *, char **);
|
||||
extern void xterm_close(int, void *);
|
||||
|
||||
int open_gdb_chan(void)
|
||||
{
|
||||
char stack[UM_KERN_PAGE_SIZE], *dummy;
|
||||
|
||||
opts.tramp_stack = (unsigned long) stack;
|
||||
xterm_data = xterm_init("", 0, &opts);
|
||||
xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
|
||||
return(xterm_fd);
|
||||
}
|
||||
|
||||
static void exit_debugger_cb(void *unused)
|
||||
{
|
||||
if(debugger_pid != -1){
|
||||
if(gdb_pid != -1){
|
||||
fake_child_exit();
|
||||
gdb_pid = -1;
|
||||
}
|
||||
else kill_child_dead(debugger_pid);
|
||||
debugger_pid = -1;
|
||||
if(debugger_parent != -1)
|
||||
detach(debugger_parent, SIGINT);
|
||||
}
|
||||
if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
|
||||
}
|
||||
|
||||
static void exit_debugger(void)
|
||||
{
|
||||
initial_thread_cb(exit_debugger_cb, NULL);
|
||||
}
|
||||
|
||||
__uml_exitcall(exit_debugger);
|
||||
|
||||
struct gdb_data {
|
||||
char *str;
|
||||
int err;
|
||||
};
|
||||
|
||||
extern char *linux_prog;
|
||||
|
||||
static void config_gdb_cb(void *arg)
|
||||
{
|
||||
struct gdb_data *data = arg;
|
||||
void *task;
|
||||
int pid;
|
||||
|
||||
data->err = -1;
|
||||
if(debugger_pid != -1) exit_debugger_cb(NULL);
|
||||
if(!strncmp(data->str, "pid,", strlen("pid,"))){
|
||||
data->str += strlen("pid,");
|
||||
pid = strtoul(data->str, NULL, 0);
|
||||
task = cpu_tasks[0].task;
|
||||
debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
|
||||
if(debugger_pid != -1){
|
||||
data->err = 0;
|
||||
gdb_pid = pid;
|
||||
}
|
||||
return;
|
||||
}
|
||||
data->err = 0;
|
||||
debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
|
||||
init_proxy(debugger_pid, 0, 0);
|
||||
}
|
||||
|
||||
int gdb_config(char *str, char **error_out)
|
||||
{
|
||||
struct gdb_data data;
|
||||
|
||||
if(*str++ != '=') return(-1);
|
||||
data.str = str;
|
||||
initial_thread_cb(config_gdb_cb, &data);
|
||||
return(data.err);
|
||||
}
|
||||
|
||||
void remove_gdb_cb(void *unused)
|
||||
{
|
||||
exit_debugger_cb(NULL);
|
||||
}
|
||||
|
||||
int gdb_remove(int unused, char **error_out)
|
||||
{
|
||||
initial_thread_cb(remove_gdb_cb, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void signal_usr1(int sig)
|
||||
{
|
||||
if(debugger_pid != -1){
|
||||
printf("The debugger is already running\n");
|
||||
return;
|
||||
}
|
||||
debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
|
||||
init_proxy(debugger_pid, 0, 0);
|
||||
}
|
||||
|
||||
int init_ptrace_proxy(int idle_pid, int startup, int stop)
|
||||
{
|
||||
int pid, status;
|
||||
|
||||
pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
|
||||
status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
|
||||
if(pid < 0){
|
||||
cont(idle_pid);
|
||||
return(-1);
|
||||
}
|
||||
init_proxy(pid, 1, status);
|
||||
return(pid);
|
||||
}
|
||||
|
||||
int attach_debugger(int idle_pid, int pid, int stop)
|
||||
{
|
||||
int status = 0, err;
|
||||
|
||||
err = attach(pid);
|
||||
if(err < 0){
|
||||
printf("Failed to attach pid %d, errno = %d\n", pid, -err);
|
||||
return(-1);
|
||||
}
|
||||
if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
|
||||
init_proxy(pid, 1, status);
|
||||
return(pid);
|
||||
}
|
||||
|
||||
#ifdef notdef /* Put this back in when it does something useful */
|
||||
static int __init uml_gdb_init_setup(char *line, int *add)
|
||||
{
|
||||
gdb_init = uml_strdup(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__uml_setup("gdb=", uml_gdb_init_setup,
|
||||
"gdb=<channel description>\n\n"
|
||||
);
|
||||
#endif
|
||||
|
||||
static int __init uml_gdb_pid_setup(char *line, int *add)
|
||||
{
|
||||
gdb_pid = strtoul(line, NULL, 0);
|
||||
*add = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__uml_setup("gdb-pid=", uml_gdb_pid_setup,
|
||||
"gdb-pid=<pid>\n"
|
||||
" gdb-pid is used to attach an external debugger to UML. This may be\n"
|
||||
" an already-running gdb or a debugger-like process like strace.\n\n"
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
int debugger_signal(int status, pid_t pid){ return(0); }
|
||||
void child_signal(pid_t pid, int status){ }
|
||||
int init_ptrace_proxy(int idle_pid, int startup, int stop)
|
||||
{
|
||||
printf("debug requested when CONFIG_PT_PROXY is off\n");
|
||||
kill_child_dead(idle_pid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void signal_usr1(int sig)
|
||||
{
|
||||
printf("debug requested when CONFIG_PT_PROXY is off\n");
|
||||
}
|
||||
|
||||
int attach_debugger(int idle_pid, int pid, int stop)
|
||||
{
|
||||
printf("attach_debugger called when CONFIG_PT_PROXY "
|
||||
"is off\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int config_gdb(char *str)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int remove_gdb(void)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int init_parent_proxy(int pid)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void debugger_parent_signal(int status, int pid)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/init.h"
|
||||
#include "mconsole_kern.h"
|
||||
|
||||
#ifdef CONFIG_MCONSOLE
|
||||
|
||||
extern int gdb_config(char *str, char **error_out);
|
||||
extern int gdb_remove(int n, char **error_out);
|
||||
|
||||
static struct mc_device gdb_mc = {
|
||||
.list = INIT_LIST_HEAD(gdb_mc.list),
|
||||
.name = "gdb",
|
||||
.config = gdb_config,
|
||||
.remove = gdb_remove,
|
||||
};
|
||||
|
||||
int gdb_mc_init(void)
|
||||
{
|
||||
mconsole_register_dev(&gdb_mc);
|
||||
return(0);
|
||||
}
|
||||
|
||||
__initcall(gdb_mc_init);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef __MODE_TT_H__
|
||||
#define __MODE_TT_H__
|
||||
|
||||
#include "sysdep/ptrace.h"
|
||||
|
||||
enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
|
||||
|
||||
extern int tracing_pid;
|
||||
|
||||
extern int tracer(int (*init_proc)(void *), void *sp);
|
||||
extern void sig_handler_common_tt(int sig, void *sc);
|
||||
extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
|
||||
extern void reboot_tt(void);
|
||||
extern void halt_tt(void);
|
||||
extern int is_tracer_winch(int pid, int fd, void *data);
|
||||
extern void kill_off_processes_tt(void);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/module.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "mode.h"
|
||||
|
||||
EXPORT_SYMBOL(__do_copy_from_user);
|
||||
EXPORT_SYMBOL(__do_copy_to_user);
|
||||
EXPORT_SYMBOL(__do_strncpy_from_user);
|
||||
EXPORT_SYMBOL(__do_strnlen_user);
|
||||
EXPORT_SYMBOL(__do_clear_user);
|
||||
EXPORT_SYMBOL(clear_user_tt);
|
||||
|
||||
EXPORT_SYMBOL(tracing_pid);
|
||||
EXPORT_SYMBOL(honeypot);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/stddef.h"
|
||||
#include "linux/mm.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "mem_user.h"
|
||||
#include "kern_util.h"
|
||||
#include "kern.h"
|
||||
#include "tt.h"
|
||||
|
||||
void before_mem_tt(unsigned long brk_start)
|
||||
{
|
||||
if(debug)
|
||||
remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
|
||||
remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
|
||||
remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
|
||||
}
|
||||
|
||||
#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
|
||||
#define START (CONFIG_TOP_ADDR - SIZE)
|
||||
|
||||
unsigned long set_task_sizes_tt(unsigned long *task_size_out)
|
||||
{
|
||||
unsigned long host_task_size;
|
||||
|
||||
/* Round up to the nearest 4M */
|
||||
host_task_size = ROUND_4M((unsigned long) &host_task_size);
|
||||
*task_size_out = START;
|
||||
|
||||
return host_task_size;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include "tt.h"
|
||||
#include "mem_user.h"
|
||||
#include "os.h"
|
||||
|
||||
void remap_data(void *segment_start, void *segment_end, int w)
|
||||
{
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
int data, prot;
|
||||
|
||||
if(w) prot = PROT_WRITE;
|
||||
else prot = 0;
|
||||
prot |= PROT_READ | PROT_EXEC;
|
||||
size = (unsigned long) segment_end -
|
||||
(unsigned long) segment_start;
|
||||
data = create_mem_file(size);
|
||||
addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
|
||||
if(addr == MAP_FAILED){
|
||||
perror("mapping new data segment");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(addr, segment_start, size);
|
||||
if(switcheroo(data, prot, addr, segment_start, size) < 0){
|
||||
printf("switcheroo failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,461 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/sched.h"
|
||||
#include "linux/signal.h"
|
||||
#include "linux/kernel.h"
|
||||
#include "linux/interrupt.h"
|
||||
#include "linux/ptrace.h"
|
||||
#include "asm/system.h"
|
||||
#include "asm/pgalloc.h"
|
||||
#include "asm/ptrace.h"
|
||||
#include "asm/tlbflush.h"
|
||||
#include "irq_user.h"
|
||||
#include "kern_util.h"
|
||||
#include "os.h"
|
||||
#include "kern.h"
|
||||
#include "sigcontext.h"
|
||||
#include "mem_user.h"
|
||||
#include "tlb.h"
|
||||
#include "mode.h"
|
||||
#include "mode_kern.h"
|
||||
#include "init.h"
|
||||
#include "tt.h"
|
||||
|
||||
void switch_to_tt(void *prev, void *next)
|
||||
{
|
||||
struct task_struct *from, *to, *prev_sched;
|
||||
unsigned long flags;
|
||||
int err, vtalrm, alrm, prof, cpu;
|
||||
char c;
|
||||
|
||||
from = prev;
|
||||
to = next;
|
||||
|
||||
cpu = task_thread_info(from)->cpu;
|
||||
if(cpu == 0)
|
||||
forward_interrupts(to->thread.mode.tt.extern_pid);
|
||||
#ifdef CONFIG_SMP
|
||||
forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
|
||||
#endif
|
||||
local_irq_save(flags);
|
||||
|
||||
vtalrm = change_sig(SIGVTALRM, 0);
|
||||
alrm = change_sig(SIGALRM, 0);
|
||||
prof = change_sig(SIGPROF, 0);
|
||||
|
||||
forward_pending_sigio(to->thread.mode.tt.extern_pid);
|
||||
|
||||
c = 0;
|
||||
|
||||
/* Notice that here we "up" the semaphore on which "to" is waiting, and
|
||||
* below (the read) we wait on this semaphore (which is implemented by
|
||||
* switch_pipe) and go sleeping. Thus, after that, we have resumed in
|
||||
* "to", and can't use any more the value of "from" (which is outdated),
|
||||
* nor the value in "to" (since it was the task which stole us the CPU,
|
||||
* which we don't care about). */
|
||||
|
||||
err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
|
||||
if(err != sizeof(c))
|
||||
panic("write of switch_pipe failed, err = %d", -err);
|
||||
|
||||
if(from->thread.mode.tt.switch_pipe[0] == -1)
|
||||
os_kill_process(os_getpid(), 0);
|
||||
|
||||
err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c,
|
||||
sizeof(c));
|
||||
if(err != sizeof(c))
|
||||
panic("read of switch_pipe failed, errno = %d", -err);
|
||||
|
||||
/* If the process that we have just scheduled away from has exited,
|
||||
* then it needs to be killed here. The reason is that, even though
|
||||
* it will kill itself when it next runs, that may be too late. Its
|
||||
* stack will be freed, possibly before then, and if that happens,
|
||||
* we have a use-after-free situation. So, it gets killed here
|
||||
* in case it has not already killed itself.
|
||||
*/
|
||||
prev_sched = current->thread.prev_sched;
|
||||
if(prev_sched->thread.mode.tt.switch_pipe[0] == -1)
|
||||
os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
|
||||
|
||||
change_sig(SIGVTALRM, vtalrm);
|
||||
change_sig(SIGALRM, alrm);
|
||||
change_sig(SIGPROF, prof);
|
||||
|
||||
arch_switch_to_tt(prev_sched, current);
|
||||
|
||||
flush_tlb_all();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void release_thread_tt(struct task_struct *task)
|
||||
{
|
||||
int pid = task->thread.mode.tt.extern_pid;
|
||||
|
||||
/*
|
||||
* We first have to kill the other process, before
|
||||
* closing its switch_pipe. Else it might wake up
|
||||
* and receive "EOF" before we could kill it.
|
||||
*/
|
||||
if(os_getpid() != pid)
|
||||
os_kill_process(pid, 0);
|
||||
|
||||
os_close_file(task->thread.mode.tt.switch_pipe[0]);
|
||||
os_close_file(task->thread.mode.tt.switch_pipe[1]);
|
||||
/* use switch_pipe as flag: thread is released */
|
||||
task->thread.mode.tt.switch_pipe[0] = -1;
|
||||
}
|
||||
|
||||
void suspend_new_thread(int fd)
|
||||
{
|
||||
int err;
|
||||
char c;
|
||||
|
||||
os_stop_process(os_getpid());
|
||||
err = os_read_file(fd, &c, sizeof(c));
|
||||
if(err != sizeof(c))
|
||||
panic("read failed in suspend_new_thread, err = %d", -err);
|
||||
}
|
||||
|
||||
void schedule_tail(struct task_struct *prev);
|
||||
|
||||
static void new_thread_handler(int sig)
|
||||
{
|
||||
unsigned long disable;
|
||||
int (*fn)(void *);
|
||||
void *arg;
|
||||
|
||||
fn = current->thread.request.u.thread.proc;
|
||||
arg = current->thread.request.u.thread.arg;
|
||||
|
||||
UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
|
||||
disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
|
||||
(1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
|
||||
SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable;
|
||||
|
||||
suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
|
||||
|
||||
force_flush_all();
|
||||
if(current->thread.prev_sched != NULL)
|
||||
schedule_tail(current->thread.prev_sched);
|
||||
current->thread.prev_sched = NULL;
|
||||
|
||||
init_new_thread_signals();
|
||||
enable_timer();
|
||||
free_page(current->thread.temp_stack);
|
||||
set_cmdline("(kernel thread)");
|
||||
|
||||
change_sig(SIGUSR1, 1);
|
||||
change_sig(SIGPROF, 1);
|
||||
local_irq_enable();
|
||||
if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf))
|
||||
do_exit(0);
|
||||
|
||||
/* XXX No set_user_mode here because a newly execed process will
|
||||
* immediately segfault on its non-existent IP, coming straight back
|
||||
* to the signal handler, which will call set_user_mode on its way
|
||||
* out. This should probably change since it's confusing.
|
||||
*/
|
||||
}
|
||||
|
||||
static int new_thread_proc(void *stack)
|
||||
{
|
||||
/* local_irq_disable is needed to block out signals until this thread is
|
||||
* properly scheduled. Otherwise, the tracing thread will get mighty
|
||||
* upset about any signals that arrive before that.
|
||||
* This has the complication that it sets the saved signal mask in
|
||||
* the sigcontext to block signals. This gets restored when this
|
||||
* thread (or a descendant, since they get a copy of this sigcontext)
|
||||
* returns to userspace.
|
||||
* So, this is compensated for elsewhere.
|
||||
* XXX There is still a small window until local_irq_disable() actually
|
||||
* finishes where signals are possible - shouldn't be a problem in
|
||||
* practice since SIGIO hasn't been forwarded here yet, and the
|
||||
* local_irq_disable should finish before a SIGVTALRM has time to be
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
local_irq_disable();
|
||||
init_new_thread_stack(stack, new_thread_handler);
|
||||
os_usr1_process(os_getpid());
|
||||
change_sig(SIGUSR1, 1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Signal masking - signals are blocked at the start of fork_tramp. They
|
||||
* are re-enabled when finish_fork_handler is entered by fork_tramp hitting
|
||||
* itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
|
||||
* so it is blocked before it's called. They are re-enabled on sigreturn
|
||||
* despite the fact that they were blocked when the SIGUSR1 was issued because
|
||||
* copy_thread copies the parent's sigcontext, including the signal mask
|
||||
* onto the signal frame.
|
||||
*/
|
||||
|
||||
void finish_fork_handler(int sig)
|
||||
{
|
||||
UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
|
||||
suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
|
||||
|
||||
force_flush_all();
|
||||
if(current->thread.prev_sched != NULL)
|
||||
schedule_tail(current->thread.prev_sched);
|
||||
current->thread.prev_sched = NULL;
|
||||
|
||||
enable_timer();
|
||||
change_sig(SIGVTALRM, 1);
|
||||
local_irq_enable();
|
||||
if(current->mm != current->parent->mm)
|
||||
protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
|
||||
1, 0, 1);
|
||||
stack_protections((unsigned long) current_thread);
|
||||
|
||||
free_page(current->thread.temp_stack);
|
||||
local_irq_disable();
|
||||
change_sig(SIGUSR1, 0);
|
||||
set_user_mode(current);
|
||||
}
|
||||
|
||||
int fork_tramp(void *stack)
|
||||
{
|
||||
local_irq_disable();
|
||||
arch_init_thread();
|
||||
init_new_thread_stack(stack, finish_fork_handler);
|
||||
|
||||
os_usr1_process(os_getpid());
|
||||
change_sig(SIGUSR1, 1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
|
||||
unsigned long stack_top, struct task_struct * p,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
int (*tramp)(void *);
|
||||
int new_pid, err;
|
||||
unsigned long stack;
|
||||
|
||||
if(current->thread.forking)
|
||||
tramp = fork_tramp;
|
||||
else {
|
||||
tramp = new_thread_proc;
|
||||
p->thread.request.u.thread = current->thread.request.u.thread;
|
||||
}
|
||||
|
||||
err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
|
||||
if(err < 0){
|
||||
printk("copy_thread : pipe failed, err = %d\n", -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
stack = alloc_stack(0, 0);
|
||||
if(stack == 0){
|
||||
printk(KERN_ERR "copy_thread : failed to allocate "
|
||||
"temporary stack\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
|
||||
clone_flags &= CLONE_VM;
|
||||
p->thread.temp_stack = stack;
|
||||
new_pid = start_fork_tramp(task_stack_page(p), stack, clone_flags, tramp);
|
||||
if(new_pid < 0){
|
||||
printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
|
||||
-new_pid);
|
||||
return(new_pid);
|
||||
}
|
||||
|
||||
if(current->thread.forking){
|
||||
sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(®s->regs));
|
||||
SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
|
||||
if(sp != 0)
|
||||
SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
|
||||
}
|
||||
p->thread.mode.tt.extern_pid = new_pid;
|
||||
|
||||
current->thread.request.op = OP_FORK;
|
||||
current->thread.request.u.fork.pid = new_pid;
|
||||
os_usr1_process(os_getpid());
|
||||
|
||||
/* Enable the signal and then disable it to ensure that it is handled
|
||||
* here, and nowhere else.
|
||||
*/
|
||||
change_sig(SIGUSR1, 1);
|
||||
|
||||
change_sig(SIGUSR1, 0);
|
||||
err = 0;
|
||||
return(err);
|
||||
}
|
||||
|
||||
void reboot_tt(void)
|
||||
{
|
||||
current->thread.request.op = OP_REBOOT;
|
||||
os_usr1_process(os_getpid());
|
||||
change_sig(SIGUSR1, 1);
|
||||
}
|
||||
|
||||
void halt_tt(void)
|
||||
{
|
||||
current->thread.request.op = OP_HALT;
|
||||
os_usr1_process(os_getpid());
|
||||
change_sig(SIGUSR1, 1);
|
||||
}
|
||||
|
||||
void kill_off_processes_tt(void)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int me;
|
||||
|
||||
me = os_getpid();
|
||||
for_each_process(p){
|
||||
if(p->thread.mode.tt.extern_pid != me)
|
||||
os_kill_process(p->thread.mode.tt.extern_pid, 0);
|
||||
}
|
||||
if(init_task.thread.mode.tt.extern_pid != me)
|
||||
os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
|
||||
}
|
||||
|
||||
void initial_thread_cb_tt(void (*proc)(void *), void *arg)
|
||||
{
|
||||
if(os_getpid() == tracing_pid){
|
||||
(*proc)(arg);
|
||||
}
|
||||
else {
|
||||
current->thread.request.op = OP_CB;
|
||||
current->thread.request.u.cb.proc = proc;
|
||||
current->thread.request.u.cb.arg = arg;
|
||||
os_usr1_process(os_getpid());
|
||||
change_sig(SIGUSR1, 1);
|
||||
|
||||
change_sig(SIGUSR1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int do_proc_op(void *t, int proc_id)
|
||||
{
|
||||
struct task_struct *task;
|
||||
struct thread_struct *thread;
|
||||
int op, pid;
|
||||
|
||||
task = t;
|
||||
thread = &task->thread;
|
||||
op = thread->request.op;
|
||||
switch(op){
|
||||
case OP_NONE:
|
||||
case OP_TRACE_ON:
|
||||
break;
|
||||
case OP_EXEC:
|
||||
pid = thread->request.u.exec.pid;
|
||||
do_exec(thread->mode.tt.extern_pid, pid);
|
||||
thread->mode.tt.extern_pid = pid;
|
||||
cpu_tasks[task_thread_info(task)->cpu].pid = pid;
|
||||
break;
|
||||
case OP_FORK:
|
||||
attach_process(thread->request.u.fork.pid);
|
||||
break;
|
||||
case OP_CB:
|
||||
(*thread->request.u.cb.proc)(thread->request.u.cb.arg);
|
||||
break;
|
||||
case OP_REBOOT:
|
||||
case OP_HALT:
|
||||
break;
|
||||
default:
|
||||
tracer_panic("Bad op in do_proc_op");
|
||||
break;
|
||||
}
|
||||
thread->request.op = OP_NONE;
|
||||
return(op);
|
||||
}
|
||||
|
||||
void init_idle_tt(void)
|
||||
{
|
||||
default_idle();
|
||||
}
|
||||
|
||||
extern void start_kernel(void);
|
||||
|
||||
static int start_kernel_proc(void *unused)
|
||||
{
|
||||
int pid;
|
||||
|
||||
block_signals();
|
||||
pid = os_getpid();
|
||||
|
||||
cpu_tasks[0].pid = pid;
|
||||
cpu_tasks[0].task = current;
|
||||
#ifdef CONFIG_SMP
|
||||
cpu_online_map = cpumask_of_cpu(0);
|
||||
#endif
|
||||
if(debug) os_stop_process(pid);
|
||||
start_kernel();
|
||||
return(0);
|
||||
}
|
||||
|
||||
void set_tracing(void *task, int tracing)
|
||||
{
|
||||
((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
|
||||
}
|
||||
|
||||
int is_tracing(void *t)
|
||||
{
|
||||
return (((struct task_struct *) t)->thread.mode.tt.tracing);
|
||||
}
|
||||
|
||||
int set_user_mode(void *t)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = t ? t : current;
|
||||
if(task->thread.mode.tt.tracing)
|
||||
return(1);
|
||||
task->thread.request.op = OP_TRACE_ON;
|
||||
os_usr1_process(os_getpid());
|
||||
return(0);
|
||||
}
|
||||
|
||||
void set_init_pid(int pid)
|
||||
{
|
||||
int err;
|
||||
|
||||
init_task.thread.mode.tt.extern_pid = pid;
|
||||
err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
|
||||
if(err)
|
||||
panic("Can't create switch pipe for init_task, errno = %d",
|
||||
-err);
|
||||
}
|
||||
|
||||
int start_uml_tt(void)
|
||||
{
|
||||
void *sp;
|
||||
int pages;
|
||||
|
||||
pages = (1 << CONFIG_KERNEL_STACK_ORDER);
|
||||
sp = task_stack_page(&init_task) +
|
||||
pages * PAGE_SIZE - sizeof(unsigned long);
|
||||
return(tracer(start_kernel_proc, sp));
|
||||
}
|
||||
|
||||
int external_pid_tt(struct task_struct *task)
|
||||
{
|
||||
return(task->thread.mode.tt.extern_pid);
|
||||
}
|
||||
|
||||
int thread_pid_tt(struct task_struct *task)
|
||||
{
|
||||
return(task->thread.mode.tt.extern_pid);
|
||||
}
|
||||
|
||||
int is_valid_pid(int pid)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process(task){
|
||||
if(task->thread.mode.tt.extern_pid == pid){
|
||||
read_unlock(&tasklist_lock);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
return(0);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
obj-y = proxy.o ptrace.o sysdep.o wait.o
|
||||
|
||||
USER_OBJS := $(obj-y)
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
@ -1,377 +0,0 @@
|
||||
/**********************************************************************
|
||||
proxy.c
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
|
||||
Jeff Dike (jdike@karaya.com) : Modified for integration into uml
|
||||
**********************************************************************/
|
||||
|
||||
/* XXX This file shouldn't refer to CONFIG_* */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <asm/unistd.h>
|
||||
#include "ptrace_user.h"
|
||||
|
||||
#include "ptproxy.h"
|
||||
#include "sysdep.h"
|
||||
#include "wait.h"
|
||||
|
||||
#include "user.h"
|
||||
#include "os.h"
|
||||
#include "tempfile.h"
|
||||
|
||||
static int debugger_wait(debugger_state *debugger, int *status, int options,
|
||||
int (*syscall)(debugger_state *debugger, pid_t child),
|
||||
int (*normal_return)(debugger_state *debugger,
|
||||
pid_t unused),
|
||||
int (*wait_return)(debugger_state *debugger,
|
||||
pid_t unused))
|
||||
{
|
||||
if(debugger->real_wait){
|
||||
debugger->handle_trace = normal_return;
|
||||
syscall_continue(debugger->pid);
|
||||
debugger->real_wait = 0;
|
||||
return(1);
|
||||
}
|
||||
debugger->wait_status_ptr = status;
|
||||
debugger->wait_options = options;
|
||||
if((debugger->debugee != NULL) && debugger->debugee->event){
|
||||
syscall_continue(debugger->pid);
|
||||
wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
|
||||
NULL);
|
||||
(*wait_return)(debugger, -1);
|
||||
return(0);
|
||||
}
|
||||
else if(debugger->wait_options & WNOHANG){
|
||||
syscall_cancel(debugger->pid, 0);
|
||||
debugger->handle_trace = syscall;
|
||||
return(0);
|
||||
}
|
||||
else {
|
||||
syscall_pause(debugger->pid);
|
||||
debugger->handle_trace = wait_return;
|
||||
debugger->waiting = 1;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle debugger trap, i.e. syscall.
|
||||
*/
|
||||
|
||||
int debugger_syscall(debugger_state *debugger, pid_t child)
|
||||
{
|
||||
long arg1, arg2, arg3, arg4, arg5, result;
|
||||
int syscall, ret = 0;
|
||||
|
||||
syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
|
||||
&arg5);
|
||||
|
||||
switch(syscall){
|
||||
case __NR_execve:
|
||||
/* execve never returns */
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
break;
|
||||
|
||||
case __NR_ptrace:
|
||||
if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
|
||||
if(!debugger->debugee->in_context)
|
||||
child = debugger->debugee->pid;
|
||||
result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
|
||||
&ret);
|
||||
syscall_cancel(debugger->pid, result);
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
return(ret);
|
||||
|
||||
#ifdef __NR_waitpid
|
||||
case __NR_waitpid:
|
||||
#endif
|
||||
case __NR_wait4:
|
||||
if(!debugger_wait(debugger, (int *) arg2, arg3,
|
||||
debugger_syscall, debugger_normal_return,
|
||||
proxy_wait_return))
|
||||
return(0);
|
||||
break;
|
||||
|
||||
case __NR_kill:
|
||||
if(!debugger->debugee->in_context)
|
||||
child = debugger->debugee->pid;
|
||||
if(arg1 == debugger->debugee->pid){
|
||||
result = kill(child, arg2);
|
||||
syscall_cancel(debugger->pid, result);
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
return(0);
|
||||
}
|
||||
else debugger->handle_trace = debugger_normal_return;
|
||||
break;
|
||||
|
||||
default:
|
||||
debugger->handle_trace = debugger_normal_return;
|
||||
}
|
||||
|
||||
syscall_continue(debugger->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Used by the tracing thread */
|
||||
static debugger_state parent;
|
||||
static int parent_syscall(debugger_state *debugger, int pid);
|
||||
|
||||
int init_parent_proxy(int pid)
|
||||
{
|
||||
parent = ((debugger_state) { .pid = pid,
|
||||
.wait_options = 0,
|
||||
.wait_status_ptr = NULL,
|
||||
.waiting = 0,
|
||||
.real_wait = 0,
|
||||
.expecting_child = 0,
|
||||
.handle_trace = parent_syscall,
|
||||
.debugee = NULL } );
|
||||
return(0);
|
||||
}
|
||||
|
||||
int parent_normal_return(debugger_state *debugger, pid_t unused)
|
||||
{
|
||||
debugger->handle_trace = parent_syscall;
|
||||
syscall_continue(debugger->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int parent_syscall(debugger_state *debugger, int pid)
|
||||
{
|
||||
long arg1, arg2, arg3, arg4, arg5;
|
||||
int syscall;
|
||||
|
||||
syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
|
||||
|
||||
if((syscall == __NR_wait4)
|
||||
#ifdef __NR_waitpid
|
||||
|| (syscall == __NR_waitpid)
|
||||
#endif
|
||||
){
|
||||
debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
|
||||
parent_normal_return, parent_wait_return);
|
||||
}
|
||||
else ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int debugger_normal_return(debugger_state *debugger, pid_t unused)
|
||||
{
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
syscall_continue(debugger->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void debugger_cancelled_return(debugger_state *debugger, int result)
|
||||
{
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
syscall_set_result(debugger->pid, result);
|
||||
syscall_continue(debugger->pid);
|
||||
}
|
||||
|
||||
/* Used by the tracing thread */
|
||||
static debugger_state debugger;
|
||||
static debugee_state debugee;
|
||||
|
||||
void init_proxy (pid_t debugger_pid, int stopped, int status)
|
||||
{
|
||||
debugger.pid = debugger_pid;
|
||||
debugger.handle_trace = debugger_syscall;
|
||||
debugger.debugee = &debugee;
|
||||
debugger.waiting = 0;
|
||||
debugger.real_wait = 0;
|
||||
debugger.expecting_child = 0;
|
||||
|
||||
debugee.pid = 0;
|
||||
debugee.traced = 0;
|
||||
debugee.stopped = stopped;
|
||||
debugee.event = 0;
|
||||
debugee.zombie = 0;
|
||||
debugee.died = 0;
|
||||
debugee.wait_status = status;
|
||||
debugee.in_context = 1;
|
||||
}
|
||||
|
||||
int debugger_proxy(int status, int pid)
|
||||
{
|
||||
int ret = 0, sig;
|
||||
|
||||
if(WIFSTOPPED(status)){
|
||||
sig = WSTOPSIG(status);
|
||||
if (sig == SIGTRAP)
|
||||
ret = (*debugger.handle_trace)(&debugger, pid);
|
||||
|
||||
else if(sig == SIGCHLD){
|
||||
if(debugger.expecting_child){
|
||||
ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
||||
debugger.expecting_child = 0;
|
||||
}
|
||||
else if(debugger.waiting)
|
||||
real_wait_return(&debugger);
|
||||
else {
|
||||
ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
||||
debugger.real_wait = 1;
|
||||
}
|
||||
}
|
||||
else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
||||
}
|
||||
else if(WIFEXITED(status)){
|
||||
tracer_panic("debugger (pid %d) exited with status %d",
|
||||
debugger.pid, WEXITSTATUS(status));
|
||||
}
|
||||
else if(WIFSIGNALED(status)){
|
||||
tracer_panic("debugger (pid %d) exited with signal %d",
|
||||
debugger.pid, WTERMSIG(status));
|
||||
}
|
||||
else {
|
||||
tracer_panic("proxy got unknown status (0x%x) on debugger "
|
||||
"(pid %d)", status, debugger.pid);
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void child_proxy(pid_t pid, int status)
|
||||
{
|
||||
debugee.event = 1;
|
||||
debugee.wait_status = status;
|
||||
|
||||
if(WIFSTOPPED(status)){
|
||||
debugee.stopped = 1;
|
||||
debugger.expecting_child = 1;
|
||||
kill(debugger.pid, SIGCHLD);
|
||||
}
|
||||
else if(WIFEXITED(status) || WIFSIGNALED(status)){
|
||||
debugee.zombie = 1;
|
||||
debugger.expecting_child = 1;
|
||||
kill(debugger.pid, SIGCHLD);
|
||||
}
|
||||
else panic("proxy got unknown status (0x%x) on child (pid %d)",
|
||||
status, pid);
|
||||
}
|
||||
|
||||
void debugger_parent_signal(int status, int pid)
|
||||
{
|
||||
int sig;
|
||||
|
||||
if(WIFSTOPPED(status)){
|
||||
sig = WSTOPSIG(status);
|
||||
if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
|
||||
else ptrace(PTRACE_SYSCALL, pid, 0, sig);
|
||||
}
|
||||
}
|
||||
|
||||
void fake_child_exit(void)
|
||||
{
|
||||
int status, pid;
|
||||
|
||||
child_proxy(1, W_EXITCODE(0, 0));
|
||||
while(debugger.waiting == 1){
|
||||
CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
|
||||
if(pid != debugger.pid){
|
||||
printk("fake_child_exit - waitpid failed, "
|
||||
"errno = %d\n", errno);
|
||||
return;
|
||||
}
|
||||
debugger_proxy(status, debugger.pid);
|
||||
}
|
||||
CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
|
||||
if(pid != debugger.pid){
|
||||
printk("fake_child_exit - waitpid failed, "
|
||||
"errno = %d\n", errno);
|
||||
return;
|
||||
}
|
||||
if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
|
||||
printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
|
||||
char gdb_init_string[] =
|
||||
"att 1 \n\
|
||||
b panic \n\
|
||||
b stop \n\
|
||||
handle SIGWINCH nostop noprint pass \n\
|
||||
";
|
||||
|
||||
int start_debugger(char *prog, int startup, int stop, int *fd_out)
|
||||
{
|
||||
int slave, child;
|
||||
|
||||
slave = open_gdb_chan();
|
||||
child = fork();
|
||||
if(child == 0){
|
||||
char *tempname = NULL;
|
||||
int fd;
|
||||
|
||||
if(setsid() < 0) perror("setsid");
|
||||
if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
|
||||
(dup2(slave, 2) < 0)){
|
||||
printk("start_debugger : dup2 failed, errno = %d\n",
|
||||
errno);
|
||||
exit(1);
|
||||
}
|
||||
if(ioctl(0, TIOCSCTTY, 0) < 0){
|
||||
printk("start_debugger : TIOCSCTTY failed, "
|
||||
"errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if(tcsetpgrp (1, os_getpid()) < 0){
|
||||
printk("start_debugger : tcsetpgrp failed, "
|
||||
"errno = %d\n", errno);
|
||||
#ifdef notdef
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
|
||||
if(fd < 0){
|
||||
printk("start_debugger : make_tempfile failed,"
|
||||
"err = %d\n", -fd);
|
||||
exit(1);
|
||||
}
|
||||
os_write_file(fd, gdb_init_string,
|
||||
sizeof(gdb_init_string) - 1);
|
||||
if(startup){
|
||||
if(stop){
|
||||
os_write_file(fd, "b start_kernel\n",
|
||||
strlen("b start_kernel\n"));
|
||||
}
|
||||
os_write_file(fd, "c\n", strlen("c\n"));
|
||||
}
|
||||
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
|
||||
printk("start_debugger : PTRACE_TRACEME failed, "
|
||||
"errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
execlp("gdb", "gdb", "--command", tempname, prog, NULL);
|
||||
printk("start_debugger : exec of gdb failed, errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
if(child < 0){
|
||||
printk("start_debugger : fork for gdb failed, errno = %d\n",
|
||||
errno);
|
||||
return(-1);
|
||||
}
|
||||
*fd_out = slave;
|
||||
return(child);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,61 +0,0 @@
|
||||
/**********************************************************************
|
||||
ptproxy.h
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __PTPROXY_H
|
||||
#define __PTPROXY_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct debugger debugger_state;
|
||||
typedef struct debugee debugee_state;
|
||||
|
||||
struct debugger
|
||||
{
|
||||
pid_t pid;
|
||||
int wait_options;
|
||||
int *wait_status_ptr;
|
||||
unsigned int waiting : 1;
|
||||
unsigned int real_wait : 1;
|
||||
unsigned int expecting_child : 1;
|
||||
int (*handle_trace) (debugger_state *, pid_t);
|
||||
|
||||
debugee_state *debugee;
|
||||
};
|
||||
|
||||
struct debugee
|
||||
{
|
||||
pid_t pid;
|
||||
int wait_status;
|
||||
unsigned int died : 1;
|
||||
unsigned int event : 1;
|
||||
unsigned int stopped : 1;
|
||||
unsigned int trace_singlestep : 1;
|
||||
unsigned int trace_syscall : 1;
|
||||
unsigned int traced : 1;
|
||||
unsigned int zombie : 1;
|
||||
unsigned int in_context : 1;
|
||||
};
|
||||
|
||||
extern int debugger_syscall(debugger_state *debugger, pid_t pid);
|
||||
extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
|
||||
|
||||
extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
|
||||
int *strace_out);
|
||||
extern void debugger_cancelled_return(debugger_state *debugger, int result);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,237 +0,0 @@
|
||||
/**********************************************************************
|
||||
ptrace.c
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
|
||||
Jeff Dike (jdike@karaya.com) : Modified for integration into uml
|
||||
**********************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "ptproxy.h"
|
||||
#include "debug.h"
|
||||
#include "kern_util.h"
|
||||
#include "ptrace_user.h"
|
||||
#include "tt.h"
|
||||
#include "os.h"
|
||||
|
||||
long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
|
||||
long arg3, long arg4, pid_t child, int *ret)
|
||||
{
|
||||
sigset_t relay;
|
||||
long result;
|
||||
int status;
|
||||
|
||||
*ret = 0;
|
||||
if(debugger->debugee->died) return(-ESRCH);
|
||||
|
||||
switch(arg1){
|
||||
case PTRACE_ATTACH:
|
||||
if(debugger->debugee->traced) return(-EPERM);
|
||||
|
||||
debugger->debugee->pid = arg2;
|
||||
debugger->debugee->traced = 1;
|
||||
|
||||
if(is_valid_pid(arg2) && (arg2 != child)){
|
||||
debugger->debugee->in_context = 0;
|
||||
kill(arg2, SIGSTOP);
|
||||
debugger->debugee->event = 1;
|
||||
debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
|
||||
}
|
||||
else {
|
||||
debugger->debugee->in_context = 1;
|
||||
if(debugger->debugee->stopped)
|
||||
child_proxy(child, W_STOPCODE(SIGSTOP));
|
||||
else kill(child, SIGSTOP);
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
||||
case PTRACE_DETACH:
|
||||
if(!debugger->debugee->traced) return(-EPERM);
|
||||
|
||||
debugger->debugee->traced = 0;
|
||||
debugger->debugee->pid = 0;
|
||||
if(!debugger->debugee->in_context)
|
||||
kill(child, SIGCONT);
|
||||
|
||||
return(0);
|
||||
|
||||
case PTRACE_CONT:
|
||||
if(!debugger->debugee->in_context) return(-EPERM);
|
||||
*ret = PTRACE_CONT;
|
||||
return(ptrace(PTRACE_CONT, child, arg3, arg4));
|
||||
|
||||
#ifdef UM_HAVE_GETFPREGS
|
||||
case PTRACE_GETFPREGS:
|
||||
{
|
||||
long regs[FP_FRAME_SIZE];
|
||||
int i, result;
|
||||
|
||||
result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
||||
ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
|
||||
regs[i]);
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UM_HAVE_GETFPXREGS
|
||||
case PTRACE_GETFPXREGS:
|
||||
{
|
||||
long regs[FPX_FRAME_SIZE];
|
||||
int i, result;
|
||||
|
||||
result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
||||
ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
|
||||
regs[i]);
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UM_HAVE_GETREGS
|
||||
case PTRACE_GETREGS:
|
||||
{
|
||||
long regs[FRAME_SIZE];
|
||||
int i, result;
|
||||
|
||||
result = ptrace(PTRACE_GETREGS, child, 0, regs);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
||||
ptrace (PTRACE_POKEDATA, debugger->pid,
|
||||
arg4 + 4 * i, regs[i]);
|
||||
return(result);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PTRACE_KILL:
|
||||
result = ptrace(PTRACE_KILL, child, arg3, arg4);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
return(result);
|
||||
|
||||
case PTRACE_PEEKDATA:
|
||||
case PTRACE_PEEKTEXT:
|
||||
case PTRACE_PEEKUSR:
|
||||
/* The value being read out could be -1, so we have to
|
||||
* check errno to see if there's an error, and zero it
|
||||
* beforehand so we're not faked out by an old error
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
result = ptrace(arg1, child, arg3, 0);
|
||||
if((result == -1) && (errno != 0)) return(-errno);
|
||||
|
||||
result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
return(result);
|
||||
|
||||
case PTRACE_POKEDATA:
|
||||
case PTRACE_POKETEXT:
|
||||
case PTRACE_POKEUSR:
|
||||
result = ptrace(arg1, child, arg3, arg4);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
|
||||
return(result);
|
||||
|
||||
#ifdef UM_HAVE_SETFPREGS
|
||||
case PTRACE_SETFPREGS:
|
||||
{
|
||||
long regs[FP_FRAME_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
||||
regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
|
||||
arg4 + 4 * i, 0);
|
||||
result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UM_HAVE_SETFPXREGS
|
||||
case PTRACE_SETFPXREGS:
|
||||
{
|
||||
long regs[FPX_FRAME_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
||||
regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
|
||||
arg4 + 4 * i, 0);
|
||||
result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UM_HAVE_SETREGS
|
||||
case PTRACE_SETREGS:
|
||||
{
|
||||
long regs[FRAME_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
||||
regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
|
||||
arg4 + 4 * i, 0);
|
||||
result = ptrace(PTRACE_SETREGS, child, 0, regs);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
case PTRACE_SINGLESTEP:
|
||||
if(!debugger->debugee->in_context) return(-EPERM);
|
||||
sigemptyset(&relay);
|
||||
sigaddset(&relay, SIGSEGV);
|
||||
sigaddset(&relay, SIGILL);
|
||||
sigaddset(&relay, SIGBUS);
|
||||
result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
|
||||
&relay);
|
||||
child_proxy(child, status);
|
||||
return(result);
|
||||
|
||||
case PTRACE_SYSCALL:
|
||||
if(!debugger->debugee->in_context) return(-EPERM);
|
||||
result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
|
||||
if(result == -1) return(-errno);
|
||||
|
||||
*ret = PTRACE_SYSCALL;
|
||||
return(result);
|
||||
|
||||
case PTRACE_TRACEME:
|
||||
default:
|
||||
return(-EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,70 +0,0 @@
|
||||
/**********************************************************************
|
||||
sysdep.c
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/unistd.h>
|
||||
#include "ptrace_user.h"
|
||||
#include "user.h"
|
||||
#include "os.h"
|
||||
|
||||
int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
|
||||
long *arg5)
|
||||
{
|
||||
*arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
|
||||
*arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
|
||||
*arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
|
||||
*arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
|
||||
*arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
|
||||
return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
|
||||
}
|
||||
|
||||
void syscall_cancel(pid_t pid, int result)
|
||||
{
|
||||
if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
||||
__NR_getpid) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
|
||||
(wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
|
||||
(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
|
||||
printk("ptproxy: couldn't cancel syscall: errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
|
||||
void syscall_set_result(pid_t pid, long result)
|
||||
{
|
||||
ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
|
||||
}
|
||||
|
||||
void syscall_continue(pid_t pid)
|
||||
{
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
}
|
||||
|
||||
int syscall_pause(pid_t pid)
|
||||
{
|
||||
if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
|
||||
printk("syscall_change - ptrace failed, errno = %d\n", errno);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,25 +0,0 @@
|
||||
/**********************************************************************
|
||||
sysdep.h
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff.
|
||||
Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
||||
See the file COPYING for licensing terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,
|
||||
long *arg4, long *arg5);
|
||||
extern void syscall_cancel (pid_t pid, long result);
|
||||
extern void syscall_set_result (pid_t pid, long result);
|
||||
extern void syscall_continue (pid_t pid);
|
||||
extern int syscall_pause(pid_t pid);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,85 +0,0 @@
|
||||
/**********************************************************************
|
||||
wait.c
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "ptproxy.h"
|
||||
#include "sysdep.h"
|
||||
#include "wait.h"
|
||||
#include "ptrace_user.h"
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "sysdep/sigcontext.h"
|
||||
|
||||
int proxy_wait_return(struct debugger *debugger, pid_t unused)
|
||||
{
|
||||
debugger->waiting = 0;
|
||||
|
||||
if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
|
||||
debugger_cancelled_return(debugger, -ECHILD);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(debugger->debugee->zombie && debugger->debugee->event)
|
||||
debugger->debugee->died = 1;
|
||||
|
||||
if(debugger->debugee->event){
|
||||
debugger->debugee->event = 0;
|
||||
ptrace(PTRACE_POKEDATA, debugger->pid,
|
||||
debugger->wait_status_ptr,
|
||||
debugger->debugee->wait_status);
|
||||
/* if (wait4)
|
||||
ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
|
||||
debugger_cancelled_return(debugger, debugger->debugee->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* pause will return -EINTR, which happens to be right for wait */
|
||||
debugger_normal_return(debugger, -1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int parent_wait_return(struct debugger *debugger, pid_t unused)
|
||||
{
|
||||
return(debugger_normal_return(debugger, -1));
|
||||
}
|
||||
|
||||
int real_wait_return(struct debugger *debugger)
|
||||
{
|
||||
unsigned long ip;
|
||||
int pid;
|
||||
|
||||
pid = debugger->pid;
|
||||
|
||||
ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
|
||||
IP_RESTART_SYSCALL(ip);
|
||||
|
||||
if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
|
||||
tracer_panic("real_wait_return : Failed to restart system "
|
||||
"call, errno = %d\n", errno);
|
||||
|
||||
if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
|
||||
debugger_normal_return(debugger, -1))
|
||||
tracer_panic("real_wait_return : gdb failed to wait, "
|
||||
"errno = %d\n", errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,15 +0,0 @@
|
||||
/**********************************************************************
|
||||
wait.h
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __PTPROXY_WAIT_H
|
||||
#define __PTPROXY_WAIT_H
|
||||
|
||||
extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
|
||||
extern int real_wait_return(struct debugger *debugger);
|
||||
extern int parent_wait_return(struct debugger *debugger, pid_t unused);
|
||||
|
||||
#endif
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/types.h"
|
||||
#include "linux/utime.h"
|
||||
#include "linux/sys.h"
|
||||
#include "linux/ptrace.h"
|
||||
#include "asm/unistd.h"
|
||||
#include "asm/ptrace.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "asm/stat.h"
|
||||
#include "sysdep/syscalls.h"
|
||||
#include "sysdep/sigcontext.h"
|
||||
#include "kern_util.h"
|
||||
#include "syscall.h"
|
||||
|
||||
void syscall_handler_tt(int sig, struct pt_regs *regs)
|
||||
{
|
||||
void *sc;
|
||||
long result;
|
||||
int syscall;
|
||||
|
||||
sc = UPT_SC(®s->regs);
|
||||
SC_START_SYSCALL(sc);
|
||||
|
||||
syscall = UPT_SYSCALL_NR(®s->regs);
|
||||
syscall_trace(®s->regs, 0);
|
||||
|
||||
current->thread.nsyscalls++;
|
||||
nsyscalls++;
|
||||
|
||||
if((syscall >= NR_syscalls) || (syscall < 0))
|
||||
result = -ENOSYS;
|
||||
else result = EXECUTE_SYSCALL(syscall, regs);
|
||||
|
||||
/* regs->sc may have changed while the system call ran (there may
|
||||
* have been an interrupt or segfault), so it needs to be refreshed.
|
||||
*/
|
||||
UPT_SC(®s->regs) = sc;
|
||||
|
||||
SC_SET_SYSCALL_RETURN(sc, result);
|
||||
|
||||
syscall_trace(®s->regs, 1);
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <asm/unistd.h>
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "sigcontext.h"
|
||||
#include "ptrace_user.h"
|
||||
#include "task.h"
|
||||
#include "kern_util.h"
|
||||
#include "syscall.h"
|
||||
#include "tt.h"
|
||||
|
||||
void do_sigtrap(void *task)
|
||||
{
|
||||
UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
|
||||
}
|
||||
|
||||
void do_syscall(void *task, int pid, int local_using_sysemu)
|
||||
{
|
||||
unsigned long proc_regs[FRAME_SIZE];
|
||||
|
||||
if(ptrace_getregs(pid, proc_regs) < 0)
|
||||
tracer_panic("Couldn't read registers");
|
||||
|
||||
UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
|
||||
|
||||
#ifdef UPT_ORIGGPR2
|
||||
UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs);
|
||||
#endif
|
||||
|
||||
if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
|
||||
((unsigned long *) PT_IP(proc_regs) <= &_etext))
|
||||
tracer_panic("I'm tracing myself and I can't get out");
|
||||
|
||||
/* advanced sysemu mode set syscall number to -1 automatically */
|
||||
if (local_using_sysemu==2)
|
||||
return;
|
||||
|
||||
/* syscall number -1 in sysemu skips syscall restarting in host */
|
||||
if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
||||
local_using_sysemu ? -1 : __NR_getpid) < 0)
|
||||
tracer_panic("do_syscall : Nullifying syscall failed, "
|
||||
"errno = %d", errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Copyright 2003 PathScale, Inc.
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/stddef.h"
|
||||
#include "linux/kernel.h"
|
||||
#include "linux/sched.h"
|
||||
#include "linux/mm.h"
|
||||
#include "asm/page.h"
|
||||
#include "asm/pgtable.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "asm/tlbflush.h"
|
||||
#include "mem_user.h"
|
||||
#include "os.h"
|
||||
#include "tlb.h"
|
||||
|
||||
static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
|
||||
int finished, void **flush)
|
||||
{
|
||||
struct host_vm_op *op;
|
||||
int i, ret=0;
|
||||
|
||||
for(i = 0; i <= last && !ret; i++){
|
||||
op = &ops[i];
|
||||
switch(op->type){
|
||||
case MMAP:
|
||||
ret = os_map_memory((void *) op->u.mmap.addr,
|
||||
op->u.mmap.fd, op->u.mmap.offset,
|
||||
op->u.mmap.len, op->u.mmap.r,
|
||||
op->u.mmap.w, op->u.mmap.x);
|
||||
break;
|
||||
case MUNMAP:
|
||||
ret = os_unmap_memory((void *) op->u.munmap.addr,
|
||||
op->u.munmap.len);
|
||||
break;
|
||||
case MPROTECT:
|
||||
ret = protect_memory(op->u.mprotect.addr,
|
||||
op->u.munmap.len,
|
||||
op->u.mprotect.r,
|
||||
op->u.mprotect.w,
|
||||
op->u.mprotect.x, 1);
|
||||
protect_memory(op->u.mprotect.addr, op->u.munmap.len,
|
||||
op->u.mprotect.r, op->u.mprotect.w,
|
||||
op->u.mprotect.x, 1);
|
||||
break;
|
||||
default:
|
||||
printk("Unknown op type %d in do_ops\n", op->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
|
||||
unsigned long end_addr, int force)
|
||||
{
|
||||
if((current->thread.mode.tt.extern_pid != -1) &&
|
||||
(current->thread.mode.tt.extern_pid != os_getpid()))
|
||||
panic("fix_range fixing wrong address space, current = 0x%p",
|
||||
current);
|
||||
|
||||
fix_range_common(mm, start_addr, end_addr, force, do_ops);
|
||||
}
|
||||
|
||||
atomic_t vmchange_seq = ATOMIC_INIT(1);
|
||||
|
||||
void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
|
||||
{
|
||||
if(flush_tlb_kernel_range_common(start, end))
|
||||
atomic_inc(&vmchange_seq);
|
||||
}
|
||||
|
||||
void flush_tlb_kernel_vm_tt(void)
|
||||
{
|
||||
flush_tlb_kernel_range(start_vm, end_vm);
|
||||
}
|
||||
|
||||
void __flush_tlb_one_tt(unsigned long addr)
|
||||
{
|
||||
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
|
||||
}
|
||||
|
||||
void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
if(vma->vm_mm != current->mm) return;
|
||||
|
||||
/* Assumes that the range start ... end is entirely within
|
||||
* either process memory or kernel vm
|
||||
*/
|
||||
if((start >= start_vm) && (start < end_vm)){
|
||||
if(flush_tlb_kernel_range_common(start, end))
|
||||
atomic_inc(&vmchange_seq);
|
||||
}
|
||||
else fix_range(vma->vm_mm, start, end, 0);
|
||||
}
|
||||
|
||||
void flush_tlb_mm_tt(struct mm_struct *mm)
|
||||
{
|
||||
unsigned long seq;
|
||||
|
||||
if(mm != current->mm) return;
|
||||
|
||||
fix_range(mm, 0, STACK_TOP, 0);
|
||||
|
||||
seq = atomic_read(&vmchange_seq);
|
||||
if(current->thread.mode.tt.vm_seq == seq)
|
||||
return;
|
||||
current->thread.mode.tt.vm_seq = seq;
|
||||
flush_tlb_kernel_range_common(start_vm, end_vm);
|
||||
}
|
||||
|
||||
void force_flush_all_tt(void)
|
||||
{
|
||||
fix_range(current->mm, 0, STACK_TOP, 1);
|
||||
flush_tlb_kernel_range_common(start_vm, end_vm);
|
||||
}
|
@ -1,461 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include "user.h"
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "sigcontext.h"
|
||||
#include "sysdep/sigcontext.h"
|
||||
#include "os.h"
|
||||
#include "mem_user.h"
|
||||
#include "process.h"
|
||||
#include "kern_util.h"
|
||||
#include "chan_user.h"
|
||||
#include "ptrace_user.h"
|
||||
#include "irq_user.h"
|
||||
#include "mode.h"
|
||||
#include "tt.h"
|
||||
|
||||
static int tracer_winch[2];
|
||||
|
||||
int is_tracer_winch(int pid, int fd, void *data)
|
||||
{
|
||||
if(pid != os_getpgrp())
|
||||
return(0);
|
||||
|
||||
register_winch_irq(tracer_winch[0], fd, -1, data);
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void tracer_winch_handler(int sig)
|
||||
{
|
||||
int n;
|
||||
char c = 1;
|
||||
|
||||
n = os_write_file(tracer_winch[1], &c, sizeof(c));
|
||||
if(n != sizeof(c))
|
||||
printk("tracer_winch_handler - write failed, err = %d\n", -n);
|
||||
}
|
||||
|
||||
/* Called only by the tracing thread during initialization */
|
||||
|
||||
static void setup_tracer_winch(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = os_pipe(tracer_winch, 1, 1);
|
||||
if(err < 0){
|
||||
printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
|
||||
return;
|
||||
}
|
||||
signal(SIGWINCH, tracer_winch_handler);
|
||||
}
|
||||
|
||||
void attach_process(int pid)
|
||||
{
|
||||
if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
|
||||
(ptrace(PTRACE_CONT, pid, 0, 0) < 0))
|
||||
tracer_panic("OP_FORK failed to attach pid");
|
||||
wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
|
||||
if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
||||
tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
|
||||
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
|
||||
tracer_panic("OP_FORK failed to continue process");
|
||||
}
|
||||
|
||||
void tracer_panic(char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vprintf(format, ap);
|
||||
va_end(ap);
|
||||
printf("\n");
|
||||
while(1) pause();
|
||||
}
|
||||
|
||||
static void tracer_segv(int sig, struct sigcontext sc)
|
||||
{
|
||||
struct faultinfo fi;
|
||||
GET_FAULTINFO_FROM_SC(fi, &sc);
|
||||
printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
|
||||
FAULT_ADDRESS(fi), SC_IP(&sc));
|
||||
while(1)
|
||||
pause();
|
||||
}
|
||||
|
||||
/* Changed early in boot, and then only read */
|
||||
int debug = 0;
|
||||
int debug_stop = 1;
|
||||
int debug_parent = 0;
|
||||
int honeypot = 0;
|
||||
|
||||
static int signal_tramp(void *arg)
|
||||
{
|
||||
int (*proc)(void *);
|
||||
|
||||
if(honeypot && munmap((void *) (host_task_size - 0x10000000),
|
||||
0x10000000))
|
||||
panic("Unmapping stack failed");
|
||||
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
|
||||
panic("ptrace PTRACE_TRACEME failed");
|
||||
os_stop_process(os_getpid());
|
||||
change_sig(SIGWINCH, 0);
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
change_sig(SIGCHLD, 0);
|
||||
signal(SIGSEGV, (__sighandler_t) sig_handler);
|
||||
set_cmdline("(idle thread)");
|
||||
set_init_pid(os_getpid());
|
||||
init_irq_signals(0);
|
||||
proc = arg;
|
||||
return((*proc)(NULL));
|
||||
}
|
||||
|
||||
static void sleeping_process_signal(int pid, int sig)
|
||||
{
|
||||
switch(sig){
|
||||
/* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
|
||||
* right because the process must be in the kernel already.
|
||||
*/
|
||||
case SIGCONT:
|
||||
case SIGTSTP:
|
||||
if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
|
||||
tracer_panic("sleeping_process_signal : Failed to "
|
||||
"continue pid %d, signal = %d, "
|
||||
"errno = %d\n", pid, sig, errno);
|
||||
break;
|
||||
|
||||
/* This happens when the debugger (e.g. strace) is doing system call
|
||||
* tracing on the kernel. During a context switch, the current task
|
||||
* will be set to the incoming process and the outgoing process will
|
||||
* hop into write and then read. Since it's not the current process
|
||||
* any more, the trace of those will land here. So, we need to just
|
||||
* PTRACE_SYSCALL it.
|
||||
*/
|
||||
case (SIGTRAP + 0x80):
|
||||
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
||||
tracer_panic("sleeping_process_signal : Failed to "
|
||||
"PTRACE_SYSCALL pid %d, errno = %d\n",
|
||||
pid, errno);
|
||||
break;
|
||||
case SIGSTOP:
|
||||
break;
|
||||
default:
|
||||
tracer_panic("sleeping process %d got unexpected "
|
||||
"signal : %d\n", pid, sig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accessed only by the tracing thread */
|
||||
int debugger_pid = -1;
|
||||
int debugger_parent = -1;
|
||||
int debugger_fd = -1;
|
||||
int gdb_pid = -1;
|
||||
|
||||
struct {
|
||||
int pid;
|
||||
int signal;
|
||||
unsigned long addr;
|
||||
struct timeval time;
|
||||
} signal_record[1024][32];
|
||||
|
||||
int signal_index[32];
|
||||
int nsignals = 0;
|
||||
int debug_trace = 0;
|
||||
|
||||
extern void signal_usr1(int sig);
|
||||
|
||||
int tracing_pid = -1;
|
||||
|
||||
int tracer(int (*init_proc)(void *), void *sp)
|
||||
{
|
||||
void *task = NULL;
|
||||
int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
|
||||
int proc_id = 0, n, err, old_tracing = 0, strace = 0;
|
||||
int local_using_sysemu = 0;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
setup_tracer_winch();
|
||||
tracing_pid = os_getpid();
|
||||
printf("tracing thread pid = %d\n", tracing_pid);
|
||||
|
||||
pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
|
||||
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
||||
if(n < 0){
|
||||
printf("waitpid on idle thread failed, errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
|
||||
printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
|
||||
printf("Failed to continue idle thread, errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
signal(SIGSEGV, (sighandler_t) tracer_segv);
|
||||
signal(SIGUSR1, signal_usr1);
|
||||
if(debug_trace){
|
||||
printf("Tracing thread pausing to be attached\n");
|
||||
stop();
|
||||
}
|
||||
if(debug){
|
||||
if(gdb_pid != -1)
|
||||
debugger_pid = attach_debugger(pid, gdb_pid, 1);
|
||||
else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
|
||||
if(debug_parent){
|
||||
debugger_parent = os_process_parent(debugger_pid);
|
||||
init_parent_proxy(debugger_parent);
|
||||
err = attach(debugger_parent);
|
||||
if(err){
|
||||
printf("Failed to attach debugger parent %d, "
|
||||
"errno = %d\n", debugger_parent, -err);
|
||||
debugger_parent = -1;
|
||||
}
|
||||
else {
|
||||
if(ptrace(PTRACE_SYSCALL, debugger_parent,
|
||||
0, 0) < 0){
|
||||
printf("Failed to continue debugger "
|
||||
"parent, errno = %d\n", errno);
|
||||
debugger_parent = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
set_cmdline("(tracing thread)");
|
||||
while(1){
|
||||
CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
|
||||
if(pid <= 0){
|
||||
if(errno != ECHILD){
|
||||
printf("wait failed - errno = %d\n", errno);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(pid == debugger_pid){
|
||||
int cont = 0;
|
||||
|
||||
if(WIFEXITED(status) || WIFSIGNALED(status))
|
||||
debugger_pid = -1;
|
||||
/* XXX Figure out how to deal with gdb and SMP */
|
||||
else cont = debugger_signal(status, cpu_tasks[0].pid);
|
||||
if(cont == PTRACE_SYSCALL) strace = 1;
|
||||
continue;
|
||||
}
|
||||
else if(pid == debugger_parent){
|
||||
debugger_parent_signal(status, pid);
|
||||
continue;
|
||||
}
|
||||
nsignals++;
|
||||
if(WIFEXITED(status)) ;
|
||||
#ifdef notdef
|
||||
{
|
||||
printf("Child %d exited with status %d\n", pid,
|
||||
WEXITSTATUS(status));
|
||||
}
|
||||
#endif
|
||||
else if(WIFSIGNALED(status)){
|
||||
sig = WTERMSIG(status);
|
||||
if(sig != 9){
|
||||
printf("Child %d exited with signal %d\n", pid,
|
||||
sig);
|
||||
}
|
||||
}
|
||||
else if(WIFSTOPPED(status)){
|
||||
proc_id = pid_to_processor_id(pid);
|
||||
sig = WSTOPSIG(status);
|
||||
if(proc_id == -1){
|
||||
sleeping_process_signal(pid, sig);
|
||||
continue;
|
||||
}
|
||||
|
||||
task = cpu_tasks[proc_id].task;
|
||||
tracing = is_tracing(task);
|
||||
old_tracing = tracing;
|
||||
|
||||
/* Assume: no syscall, when coming from user */
|
||||
if ( tracing )
|
||||
do_sigtrap(task);
|
||||
|
||||
switch(sig){
|
||||
case SIGUSR1:
|
||||
sig = 0;
|
||||
op = do_proc_op(task, proc_id);
|
||||
switch(op){
|
||||
/*
|
||||
* This is called when entering user mode; after
|
||||
* this, we start intercepting syscalls.
|
||||
*
|
||||
* In fact, a process is started in kernel mode,
|
||||
* so with is_tracing() == 0 (and that is reset
|
||||
* when executing syscalls, since UML kernel has
|
||||
* the right to do syscalls);
|
||||
*/
|
||||
case OP_TRACE_ON:
|
||||
arch_leave_kernel(task, pid);
|
||||
tracing = 1;
|
||||
break;
|
||||
case OP_REBOOT:
|
||||
case OP_HALT:
|
||||
unmap_physmem();
|
||||
kmalloc_ok = 0;
|
||||
os_kill_ptraced_process(pid, 0);
|
||||
/* Now let's reap remaining zombies */
|
||||
errno = 0;
|
||||
do {
|
||||
waitpid(-1, &status,
|
||||
WUNTRACED);
|
||||
} while (errno != ECHILD);
|
||||
return(op == OP_REBOOT);
|
||||
case OP_NONE:
|
||||
printf("Detaching pid %d\n", pid);
|
||||
detach(pid, SIGSTOP);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* OP_EXEC switches host processes on us,
|
||||
* we want to continue the new one.
|
||||
*/
|
||||
pid = cpu_tasks[proc_id].pid;
|
||||
break;
|
||||
case (SIGTRAP + 0x80):
|
||||
if(!tracing && (debugger_pid != -1)){
|
||||
child_signal(pid, status & 0x7fff);
|
||||
continue;
|
||||
}
|
||||
tracing = 0;
|
||||
/* local_using_sysemu has been already set
|
||||
* below, since if we are here, is_tracing() on
|
||||
* the traced task was 1, i.e. the process had
|
||||
* already run through one iteration of the
|
||||
* loop which executed a OP_TRACE_ON request.*/
|
||||
do_syscall(task, pid, local_using_sysemu);
|
||||
sig = SIGUSR2;
|
||||
break;
|
||||
case SIGTRAP:
|
||||
if(!tracing && (debugger_pid != -1)){
|
||||
child_signal(pid, status);
|
||||
continue;
|
||||
}
|
||||
tracing = 0;
|
||||
break;
|
||||
case SIGPROF:
|
||||
if(tracing) sig = 0;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
case SIGHUP:
|
||||
sig = 0;
|
||||
break;
|
||||
case SIGSEGV:
|
||||
case SIGIO:
|
||||
case SIGALRM:
|
||||
case SIGVTALRM:
|
||||
case SIGFPE:
|
||||
case SIGBUS:
|
||||
case SIGILL:
|
||||
case SIGWINCH:
|
||||
|
||||
default:
|
||||
tracing = 0;
|
||||
break;
|
||||
}
|
||||
set_tracing(task, tracing);
|
||||
|
||||
if(!tracing && old_tracing)
|
||||
arch_enter_kernel(task, pid);
|
||||
|
||||
if(!tracing && (debugger_pid != -1) && (sig != 0) &&
|
||||
(sig != SIGALRM) && (sig != SIGVTALRM) &&
|
||||
(sig != SIGSEGV) && (sig != SIGTRAP) &&
|
||||
(sig != SIGUSR2) && (sig != SIGIO) &&
|
||||
(sig != SIGFPE)){
|
||||
child_signal(pid, status);
|
||||
continue;
|
||||
}
|
||||
|
||||
local_using_sysemu = get_using_sysemu();
|
||||
|
||||
if(tracing)
|
||||
cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
|
||||
singlestepping(task));
|
||||
else if((debugger_pid != -1) && strace)
|
||||
cont_type = PTRACE_SYSCALL;
|
||||
else
|
||||
cont_type = PTRACE_CONT;
|
||||
|
||||
if(ptrace(cont_type, pid, 0, sig) != 0){
|
||||
tracer_panic("ptrace failed to continue "
|
||||
"process - errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int __init uml_debug_setup(char *line, int *add)
|
||||
{
|
||||
char *next;
|
||||
|
||||
debug = 1;
|
||||
*add = 0;
|
||||
if(*line != '=') return(0);
|
||||
line++;
|
||||
|
||||
while(line != NULL){
|
||||
next = strchr(line, ',');
|
||||
if(next) *next++ = '\0';
|
||||
|
||||
if(!strcmp(line, "go")) debug_stop = 0;
|
||||
else if(!strcmp(line, "parent")) debug_parent = 1;
|
||||
else printf("Unknown debug option : '%s'\n", line);
|
||||
|
||||
line = next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
__uml_setup("debug", uml_debug_setup,
|
||||
"debug\n"
|
||||
" Starts up the kernel under the control of gdb. See the \n"
|
||||
" kernel debugging tutorial and the debugging session pages\n"
|
||||
" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
|
||||
);
|
||||
|
||||
static int __init uml_debugtrace_setup(char *line, int *add)
|
||||
{
|
||||
debug_trace = 1;
|
||||
return 0;
|
||||
}
|
||||
__uml_setup("debugtrace", uml_debugtrace_setup,
|
||||
"debugtrace\n"
|
||||
" Causes the tracing thread to pause until it is attached by a\n"
|
||||
" debugger and continued. This is mostly for debugging crashes\n"
|
||||
" early during boot, and should be pretty much obsoleted by\n"
|
||||
" the debug switch.\n\n"
|
||||
);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "sysdep/sigcontext.h"
|
||||
#include "kern_util.h"
|
||||
#include "task.h"
|
||||
#include "tt.h"
|
||||
#include "os.h"
|
||||
|
||||
void sig_handler_common_tt(int sig, void *sc_ptr)
|
||||
{
|
||||
struct sigcontext *sc = sc_ptr;
|
||||
struct tt_regs save_regs, *r;
|
||||
int save_errno = errno, is_user = 0;
|
||||
void (*handler)(int, union uml_pt_regs *);
|
||||
|
||||
/* This is done because to allow SIGSEGV to be delivered inside a SEGV
|
||||
* handler. This can happen in copy_user, and if SEGV is disabled,
|
||||
* the process will die.
|
||||
*/
|
||||
if(sig == SIGSEGV)
|
||||
change_sig(SIGSEGV, 1);
|
||||
|
||||
r = &TASK_REGS(get_current())->tt;
|
||||
if ( sig == SIGFPE || sig == SIGSEGV ||
|
||||
sig == SIGBUS || sig == SIGILL ||
|
||||
sig == SIGTRAP ) {
|
||||
GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
|
||||
}
|
||||
save_regs = *r;
|
||||
if (sc)
|
||||
is_user = user_context(SC_SP(sc));
|
||||
r->sc = sc;
|
||||
if(sig != SIGUSR2)
|
||||
r->syscall = -1;
|
||||
|
||||
handler = sig_info[sig];
|
||||
|
||||
/* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */
|
||||
if (sig != SIGIO && sig != SIGWINCH &&
|
||||
sig != SIGVTALRM && sig != SIGALRM)
|
||||
unblock_signals();
|
||||
|
||||
handler(sig, (union uml_pt_regs *) r);
|
||||
|
||||
if(is_user){
|
||||
interrupt_end();
|
||||
block_signals();
|
||||
set_user_mode(NULL);
|
||||
}
|
||||
*r = save_regs;
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/sched.h"
|
||||
#include "asm/uaccess.h"
|
||||
|
||||
int copy_from_user_tt(void *to, const void __user *from, int n)
|
||||
{
|
||||
if(!access_ok(VERIFY_READ, from, n))
|
||||
return(n);
|
||||
|
||||
return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr,
|
||||
¤t->thread.fault_catcher));
|
||||
}
|
||||
|
||||
int copy_to_user_tt(void __user *to, const void *from, int n)
|
||||
{
|
||||
if(!access_ok(VERIFY_WRITE, to, n))
|
||||
return(n);
|
||||
|
||||
return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr,
|
||||
¤t->thread.fault_catcher));
|
||||
}
|
||||
|
||||
int strncpy_from_user_tt(char *dst, const char __user *src, int count)
|
||||
{
|
||||
int n;
|
||||
|
||||
if(!access_ok(VERIFY_READ, src, 1))
|
||||
return(-EFAULT);
|
||||
|
||||
n = __do_strncpy_from_user(dst, src, count,
|
||||
¤t->thread.fault_addr,
|
||||
¤t->thread.fault_catcher);
|
||||
if(n < 0) return(-EFAULT);
|
||||
return(n);
|
||||
}
|
||||
|
||||
int __clear_user_tt(void __user *mem, int len)
|
||||
{
|
||||
return(__do_clear_user(mem, len,
|
||||
¤t->thread.fault_addr,
|
||||
¤t->thread.fault_catcher));
|
||||
}
|
||||
|
||||
int clear_user_tt(void __user *mem, int len)
|
||||
{
|
||||
if(!access_ok(VERIFY_WRITE, mem, len))
|
||||
return(len);
|
||||
|
||||
return(__do_clear_user(mem, len, ¤t->thread.fault_addr,
|
||||
¤t->thread.fault_catcher));
|
||||
}
|
||||
|
||||
int strnlen_user_tt(const void __user *str, int len)
|
||||
{
|
||||
return(__do_strnlen_user(str, len,
|
||||
¤t->thread.fault_addr,
|
||||
¤t->thread.fault_catcher));
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
|
||||
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "uml_uaccess.h"
|
||||
#include "task.h"
|
||||
#include "kern_util.h"
|
||||
#include "os.h"
|
||||
#include "longjmp.h"
|
||||
|
||||
int __do_copy_from_user(void *to, const void *from, int n,
|
||||
void **fault_addr, void **fault_catcher)
|
||||
{
|
||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
||||
unsigned long fault;
|
||||
int faulted;
|
||||
|
||||
fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
|
||||
__do_copy, &faulted);
|
||||
TASK_REGS(get_current())->tt = save;
|
||||
|
||||
if(!faulted)
|
||||
return 0;
|
||||
else if (fault)
|
||||
return n - (fault - (unsigned long) from);
|
||||
else
|
||||
/* In case of a general protection fault, we don't have the
|
||||
* fault address, so NULL is used instead. Pretend we didn't
|
||||
* copy anything. */
|
||||
return n;
|
||||
}
|
||||
|
||||
static void __do_strncpy(void *dst, const void *src, int count)
|
||||
{
|
||||
strncpy(dst, src, count);
|
||||
}
|
||||
|
||||
int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
|
||||
void **fault_addr, void **fault_catcher)
|
||||
{
|
||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
||||
unsigned long fault;
|
||||
int faulted;
|
||||
|
||||
fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
|
||||
__do_strncpy, &faulted);
|
||||
TASK_REGS(get_current())->tt = save;
|
||||
|
||||
if(!faulted) return(strlen(dst));
|
||||
else return(-1);
|
||||
}
|
||||
|
||||
static void __do_clear(void *to, const void *from, int n)
|
||||
{
|
||||
memset(to, 0, n);
|
||||
}
|
||||
|
||||
int __do_clear_user(void *mem, unsigned long len,
|
||||
void **fault_addr, void **fault_catcher)
|
||||
{
|
||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
||||
unsigned long fault;
|
||||
int faulted;
|
||||
|
||||
fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
|
||||
__do_clear, &faulted);
|
||||
TASK_REGS(get_current())->tt = save;
|
||||
|
||||
if(!faulted) return(0);
|
||||
else return(len - (fault - (unsigned long) mem));
|
||||
}
|
||||
|
||||
int __do_strnlen_user(const char *str, unsigned long n,
|
||||
void **fault_addr, void **fault_catcher)
|
||||
{
|
||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
||||
int ret;
|
||||
unsigned long *faddrp = (unsigned long *)fault_addr;
|
||||
jmp_buf jbuf;
|
||||
|
||||
*fault_catcher = &jbuf;
|
||||
if(UML_SETJMP(&jbuf) == 0)
|
||||
ret = strlen(str) + 1;
|
||||
else ret = *faddrp - (unsigned long) str;
|
||||
|
||||
*fault_addr = NULL;
|
||||
*fault_catcher = NULL;
|
||||
|
||||
TASK_REGS(get_current())->tt = save;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@ -38,9 +38,7 @@
|
||||
#include "choose-mode.h"
|
||||
#include "mode_kern.h"
|
||||
#include "mode.h"
|
||||
#ifdef UML_CONFIG_MODE_SKAS
|
||||
#include "skas.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_COMMAND_LINE "root=98:0"
|
||||
|
||||
@ -132,43 +130,12 @@ unsigned long end_vm;
|
||||
/* Set in uml_ncpus_setup */
|
||||
int ncpus = 1;
|
||||
|
||||
#ifdef CONFIG_CMDLINE_ON_HOST
|
||||
/* Pointer set in linux_main, the array itself is private to each thread,
|
||||
* and changed at address space creation time so this poses no concurrency
|
||||
* problems.
|
||||
*/
|
||||
static char *argv1_begin = NULL;
|
||||
static char *argv1_end = NULL;
|
||||
#endif
|
||||
|
||||
/* Set in early boot */
|
||||
static int have_root __initdata = 0;
|
||||
|
||||
/* Set in uml_mem_setup and modified in linux_main */
|
||||
long long physmem_size = 32 * 1024 * 1024;
|
||||
|
||||
void set_cmdline(char *cmd)
|
||||
{
|
||||
#ifdef CONFIG_CMDLINE_ON_HOST
|
||||
char *umid, *ptr;
|
||||
|
||||
if(CHOOSE_MODE(honeypot, 0)) return;
|
||||
|
||||
umid = get_umid();
|
||||
if(*umid != '\0'){
|
||||
snprintf(argv1_begin,
|
||||
(argv1_end - argv1_begin) * sizeof(*ptr),
|
||||
"(%s) ", umid);
|
||||
ptr = &argv1_begin[strlen(argv1_begin)];
|
||||
}
|
||||
else ptr = argv1_begin;
|
||||
|
||||
snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
|
||||
memset(argv1_begin + strlen(argv1_begin), '\0',
|
||||
argv1_end - argv1_begin - strlen(argv1_begin));
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *usage_string =
|
||||
"User Mode Linux v%s\n"
|
||||
" available at http://user-mode-linux.sourceforge.net/\n\n";
|
||||
@ -201,13 +168,10 @@ __uml_setup("root=", uml_root_setup,
|
||||
" root=/dev/ubd5\n\n"
|
||||
);
|
||||
|
||||
#ifndef CONFIG_MODE_TT
|
||||
|
||||
static int __init no_skas_debug_setup(char *line, int *add)
|
||||
{
|
||||
printf("'debug' is not necessary to gdb UML in skas mode - run \n");
|
||||
printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
|
||||
printf("doesn't work as expected\n");
|
||||
printf("'gdb linux'");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -217,8 +181,6 @@ __uml_setup("debug", no_skas_debug_setup,
|
||||
" this flag is not needed to run gdb on UML in skas mode\n\n"
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static int __init uml_ncpus_setup(char *line, int *add)
|
||||
{
|
||||
@ -236,52 +198,6 @@ __uml_setup("ncpus=", uml_ncpus_setup,
|
||||
);
|
||||
#endif
|
||||
|
||||
static int force_tt = 0;
|
||||
|
||||
#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
|
||||
#define DEFAULT_TT 0
|
||||
|
||||
static int __init mode_tt_setup(char *line, int *add)
|
||||
{
|
||||
force_tt = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef CONFIG_MODE_SKAS
|
||||
|
||||
#define DEFAULT_TT 0
|
||||
|
||||
static int __init mode_tt_setup(char *line, int *add)
|
||||
{
|
||||
printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef CONFIG_MODE_TT
|
||||
|
||||
#define DEFAULT_TT 1
|
||||
|
||||
static int __init mode_tt_setup(char *line, int *add)
|
||||
{
|
||||
printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__uml_setup("mode=tt", mode_tt_setup,
|
||||
"mode=tt\n"
|
||||
" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
|
||||
" forces UML to run in tt (tracing thread) mode. It is not the default\n"
|
||||
" because it's slower and less secure than skas mode.\n\n"
|
||||
);
|
||||
|
||||
int mode_tt = DEFAULT_TT;
|
||||
|
||||
static int __init Usage(char *line, int *add)
|
||||
{
|
||||
const char **p;
|
||||
@ -357,29 +273,13 @@ int __init linux_main(int argc, char **argv)
|
||||
add_arg(DEFAULT_COMMAND_LINE);
|
||||
|
||||
os_early_checks();
|
||||
if (force_tt)
|
||||
clear_can_do_skas();
|
||||
mode_tt = force_tt ? 1 : !can_do_skas();
|
||||
#ifndef CONFIG_MODE_TT
|
||||
if (mode_tt) {
|
||||
/*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
|
||||
* can_do_skas() returned 0, and the message is correct. */
|
||||
printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_MODE_SKAS
|
||||
mode = "TT";
|
||||
#else
|
||||
/* Show to the user the result of selection */
|
||||
if (mode_tt)
|
||||
mode = "TT";
|
||||
else if (proc_mm && ptrace_faultinfo)
|
||||
can_do_skas();
|
||||
|
||||
if (proc_mm && ptrace_faultinfo)
|
||||
mode = "SKAS3";
|
||||
else
|
||||
mode = "SKAS0";
|
||||
#endif
|
||||
|
||||
printf("UML running in %s mode\n", mode);
|
||||
|
||||
@ -411,11 +311,6 @@ int __init linux_main(int argc, char **argv)
|
||||
|
||||
setup_machinename(init_utsname()->machine);
|
||||
|
||||
#ifdef CONFIG_CMDLINE_ON_HOST
|
||||
argv1_begin = argv[1];
|
||||
argv1_end = &argv[1][strlen(argv[1])];
|
||||
#endif
|
||||
|
||||
highmem = 0;
|
||||
iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
|
||||
max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
|
||||
|
@ -18,13 +18,6 @@ SECTIONS
|
||||
|
||||
. = START + SIZEOF_HEADERS;
|
||||
|
||||
#ifdef MODE_TT
|
||||
.remap_data : { UNMAP_PATH (.data .bss) }
|
||||
.remap : { UNMAP_PATH (.text) }
|
||||
|
||||
. = ALIGN(4096); /* Init code and data */
|
||||
#endif
|
||||
|
||||
_text = .;
|
||||
_stext = .;
|
||||
__init_begin = .;
|
||||
|
Reference in New Issue
Block a user