aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/tt
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/tt')
-rw-r--r--arch/um/kernel/tt/Makefile28
-rw-r--r--arch/um/kernel/tt/exec_kern.c87
-rw-r--r--arch/um/kernel/tt/exec_user.c57
-rw-r--r--arch/um/kernel/tt/gdb.c278
-rw-r--r--arch/um/kernel/tt/gdb_kern.c40
-rw-r--r--arch/um/kernel/tt/include/debug.h29
-rw-r--r--arch/um/kernel/tt/include/mmu-tt.h23
-rw-r--r--arch/um/kernel/tt/include/mode-tt.h35
-rw-r--r--arch/um/kernel/tt/include/mode_kern-tt.h53
-rw-r--r--arch/um/kernel/tt/include/tt.h46
-rw-r--r--arch/um/kernel/tt/include/uaccess-tt.h71
-rw-r--r--arch/um/kernel/tt/ksyms.c28
-rw-r--r--arch/um/kernel/tt/mem.c51
-rw-r--r--arch/um/kernel/tt/mem_user.c49
-rw-r--r--arch/um/kernel/tt/process_kern.c476
-rw-r--r--arch/um/kernel/tt/ptproxy/Makefile10
-rw-r--r--arch/um/kernel/tt/ptproxy/proxy.c377
-rw-r--r--arch/um/kernel/tt/ptproxy/ptproxy.h61
-rw-r--r--arch/um/kernel/tt/ptproxy/ptrace.c237
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.c70
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.h25
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.c86
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.h15
-rw-r--r--arch/um/kernel/tt/syscall_kern.c47
-rw-r--r--arch/um/kernel/tt/syscall_user.c90
-rw-r--r--arch/um/kernel/tt/time.c28
-rw-r--r--arch/um/kernel/tt/tlb.c149
-rw-r--r--arch/um/kernel/tt/tracer.c480
-rw-r--r--arch/um/kernel/tt/trap_user.c60
-rw-r--r--arch/um/kernel/tt/uaccess.c73
-rw-r--r--arch/um/kernel/tt/uaccess_user.c98
-rw-r--r--arch/um/kernel/tt/unmap.c31
32 files changed, 3288 insertions, 0 deletions
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
new file mode 100644
index 000000000000..3d5177df3504
--- /dev/null
+++ b/arch/um/kernel/tt/Makefile
@@ -0,0 +1,28 @@
1#
2# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3# Licensed under the GPL
4#
5
6extra-y := unmap_fin.o
7clean-files := unmap_tmp.o
8
9obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
10 syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
11 uaccess.o uaccess_user.o
12
13obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
14
15USER_OBJS := gdb.o time.o tracer.o
16
17include arch/um/scripts/Makefile.rules
18
19UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
20UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
21
22#XXX: partially copied from arch/um/scripts/Makefile.rules
23$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
24
25$(obj)/unmap_fin.o : $(obj)/unmap.o
26 $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
27 $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
28
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
new file mode 100644
index 000000000000..065b504a653b
--- /dev/null
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -0,0 +1,87 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/mm.h"
8#include "asm/signal.h"
9#include "asm/ptrace.h"
10#include "asm/uaccess.h"
11#include "asm/pgalloc.h"
12#include "asm/tlbflush.h"
13#include "user_util.h"
14#include "kern_util.h"
15#include "irq_user.h"
16#include "time_user.h"
17#include "signal_user.h"
18#include "mem_user.h"
19#include "os.h"
20#include "tlb.h"
21#include "mode.h"
22
23static int exec_tramp(void *sig_stack)
24{
25 init_new_thread_stack(sig_stack, NULL);
26 init_new_thread_signals(1);
27 os_stop_process(os_getpid());
28 return(0);
29}
30
31void flush_thread_tt(void)
32{
33 unsigned long stack;
34 int new_pid;
35
36 stack = alloc_stack(0, 0);
37 if(stack == 0){
38 printk(KERN_ERR
39 "flush_thread : failed to allocate temporary stack\n");
40 do_exit(SIGKILL);
41 }
42
43 new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp);
44 if(new_pid < 0){
45 printk(KERN_ERR
46 "flush_thread : new thread failed, errno = %d\n",
47 -new_pid);
48 do_exit(SIGKILL);
49 }
50
51 if(current_thread->cpu == 0)
52 forward_interrupts(new_pid);
53 current->thread.request.op = OP_EXEC;
54 current->thread.request.u.exec.pid = new_pid;
55 unprotect_stack((unsigned long) current_thread);
56 os_usr1_process(os_getpid());
57 change_sig(SIGUSR1, 1);
58
59 change_sig(SIGUSR1, 0);
60 enable_timer();
61 free_page(stack);
62 protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
63 task_protections((unsigned long) current_thread);
64 force_flush_all();
65 unblock_signals();
66}
67
68void start_thread_tt(struct pt_regs *regs, unsigned long eip,
69 unsigned long esp)
70{
71 set_fs(USER_DS);
72 flush_tlb_mm(current->mm);
73 PT_REGS_IP(regs) = eip;
74 PT_REGS_SP(regs) = esp;
75 PT_FIX_EXEC_STACK(esp);
76}
77
78/*
79 * Overrides for Emacs so that we follow Linus's tabbing style.
80 * Emacs will notice this stuff at the end of the file and automatically
81 * adjust the settings for this buffer only. This must remain at the end
82 * of the file.
83 * ---------------------------------------------------------------------------
84 * Local variables:
85 * c-file-style: "linux"
86 * End:
87 */
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
new file mode 100644
index 000000000000..a92c02ff2ce3
--- /dev/null
+++ b/arch/um/kernel/tt/exec_user.c
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <stdlib.h>
9#include <sched.h>
10#include <errno.h>
11#include <sys/wait.h>
12#include <signal.h>
13#include "user_util.h"
14#include "kern_util.h"
15#include "user.h"
16#include "ptrace_user.h"
17#include "os.h"
18
19void do_exec(int old_pid, int new_pid)
20{
21 unsigned long regs[FRAME_SIZE];
22 int err;
23
24 if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
25 (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
26 tracer_panic("do_exec failed to attach proc - errno = %d",
27 errno);
28
29 CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
30 if (err < 0)
31 tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
32 errno);
33
34 if(ptrace_getregs(old_pid, regs) < 0)
35 tracer_panic("do_exec failed to get registers - errno = %d",
36 errno);
37
38 os_kill_ptraced_process(old_pid, 0);
39
40 if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
41 tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
42
43 if(ptrace_setregs(new_pid, regs) < 0)
44 tracer_panic("do_exec failed to start new proc - errno = %d",
45 errno);
46}
47
48/*
49 * Overrides for Emacs so that we follow Linus's tabbing style.
50 * Emacs will notice this stuff at the end of the file and automatically
51 * adjust the settings for this buffer only. This must remain at the end
52 * of the file.
53 * ---------------------------------------------------------------------------
54 * Local variables:
55 * c-file-style: "linux"
56 * End:
57 */
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
new file mode 100644
index 000000000000..19a0ad7b35b3
--- /dev/null
+++ b/arch/um/kernel/tt/gdb.c
@@ -0,0 +1,278 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <errno.h>
9#include <string.h>
10#include <signal.h>
11#include <sys/types.h>
12#include "ptrace_user.h"
13#include "uml-config.h"
14#include "kern_constants.h"
15#include "chan_user.h"
16#include "init.h"
17#include "user.h"
18#include "debug.h"
19#include "kern_util.h"
20#include "user_util.h"
21#include "tt.h"
22#include "sysdep/thread.h"
23
24extern int debugger_pid;
25extern int debugger_fd;
26extern int debugger_parent;
27
28int detach(int pid, int sig)
29{
30 return(ptrace(PTRACE_DETACH, pid, 0, sig));
31}
32
33int attach(int pid)
34{
35 int err;
36
37 err = ptrace(PTRACE_ATTACH, pid, 0, 0);
38 if(err < 0) return(-errno);
39 else return(err);
40}
41
42int cont(int pid)
43{
44 return(ptrace(PTRACE_CONT, pid, 0, 0));
45}
46
47#ifdef UML_CONFIG_PT_PROXY
48
49int debugger_signal(int status, pid_t pid)
50{
51 return(debugger_proxy(status, pid));
52}
53
54void child_signal(pid_t pid, int status)
55{
56 child_proxy(pid, status);
57}
58
59static void gdb_announce(char *dev_name, int dev)
60{
61 printf("gdb assigned device '%s'\n", dev_name);
62}
63
64static struct chan_opts opts = {
65 .announce = gdb_announce,
66 .xterm_title = "UML kernel debugger",
67 .raw = 0,
68 .tramp_stack = 0,
69 .in_kernel = 0,
70};
71
72/* Accessed by the tracing thread, which automatically serializes access */
73static void *xterm_data;
74static int xterm_fd;
75
76extern void *xterm_init(char *, int, struct chan_opts *);
77extern int xterm_open(int, int, int, void *, char **);
78extern void xterm_close(int, void *);
79
80int open_gdb_chan(void)
81{
82 char stack[UM_KERN_PAGE_SIZE], *dummy;
83
84 opts.tramp_stack = (unsigned long) stack;
85 xterm_data = xterm_init("", 0, &opts);
86 xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
87 return(xterm_fd);
88}
89
90static void exit_debugger_cb(void *unused)
91{
92 if(debugger_pid != -1){
93 if(gdb_pid != -1){
94 fake_child_exit();
95 gdb_pid = -1;
96 }
97 else kill_child_dead(debugger_pid);
98 debugger_pid = -1;
99 if(debugger_parent != -1)
100 detach(debugger_parent, SIGINT);
101 }
102 if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
103}
104
105static void exit_debugger(void)
106{
107 initial_thread_cb(exit_debugger_cb, NULL);
108}
109
110__uml_exitcall(exit_debugger);
111
112struct gdb_data {
113 char *str;
114 int err;
115};
116
117static void config_gdb_cb(void *arg)
118{
119 struct gdb_data *data = arg;
120 void *task;
121 int pid;
122
123 data->err = -1;
124 if(debugger_pid != -1) exit_debugger_cb(NULL);
125 if(!strncmp(data->str, "pid,", strlen("pid,"))){
126 data->str += strlen("pid,");
127 pid = strtoul(data->str, NULL, 0);
128 task = cpu_tasks[0].task;
129 debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
130 if(debugger_pid != -1){
131 data->err = 0;
132 gdb_pid = pid;
133 }
134 return;
135 }
136 data->err = 0;
137 debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
138 init_proxy(debugger_pid, 0, 0);
139}
140
141int gdb_config(char *str)
142{
143 struct gdb_data data;
144
145 if(*str++ != '=') return(-1);
146 data.str = str;
147 initial_thread_cb(config_gdb_cb, &data);
148 return(data.err);
149}
150
151void remove_gdb_cb(void *unused)
152{
153 exit_debugger_cb(NULL);
154}
155
156int gdb_remove(char *unused)
157{
158 initial_thread_cb(remove_gdb_cb, NULL);
159 return(0);
160}
161
162void signal_usr1(int sig)
163{
164 if(debugger_pid != -1){
165 printf("The debugger is already running\n");
166 return;
167 }
168 debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
169 init_proxy(debugger_pid, 0, 0);
170}
171
172int init_ptrace_proxy(int idle_pid, int startup, int stop)
173{
174 int pid, status;
175
176 pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
177 status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
178 if(pid < 0){
179 cont(idle_pid);
180 return(-1);
181 }
182 init_proxy(pid, 1, status);
183 return(pid);
184}
185
186int attach_debugger(int idle_pid, int pid, int stop)
187{
188 int status = 0, err;
189
190 err = attach(pid);
191 if(err < 0){
192 printf("Failed to attach pid %d, errno = %d\n", pid, -err);
193 return(-1);
194 }
195 if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
196 init_proxy(pid, 1, status);
197 return(pid);
198}
199
200#ifdef notdef /* Put this back in when it does something useful */
201static int __init uml_gdb_init_setup(char *line, int *add)
202{
203 gdb_init = uml_strdup(line);
204 return 0;
205}
206
207__uml_setup("gdb=", uml_gdb_init_setup,
208"gdb=<channel description>\n\n"
209);
210#endif
211
212static int __init uml_gdb_pid_setup(char *line, int *add)
213{
214 gdb_pid = strtoul(line, NULL, 0);
215 *add = 0;
216 return 0;
217}
218
219__uml_setup("gdb-pid=", uml_gdb_pid_setup,
220"gdb-pid=<pid>\n"
221" gdb-pid is used to attach an external debugger to UML. This may be\n"
222" an already-running gdb or a debugger-like process like strace.\n\n"
223);
224
225#else
226
227int debugger_signal(int status, pid_t pid){ return(0); }
228void child_signal(pid_t pid, int status){ }
229int init_ptrace_proxy(int idle_pid, int startup, int stop)
230{
231 printf("debug requested when CONFIG_PT_PROXY is off\n");
232 kill_child_dead(idle_pid);
233 exit(1);
234}
235
236void signal_usr1(int sig)
237{
238 printf("debug requested when CONFIG_PT_PROXY is off\n");
239}
240
241int attach_debugger(int idle_pid, int pid, int stop)
242{
243 printf("attach_debugger called when CONFIG_PT_PROXY "
244 "is off\n");
245 return(-1);
246}
247
248int config_gdb(char *str)
249{
250 return(-1);
251}
252
253int remove_gdb(void)
254{
255 return(-1);
256}
257
258int init_parent_proxy(int pid)
259{
260 return(-1);
261}
262
263void debugger_parent_signal(int status, int pid)
264{
265}
266
267#endif
268
269/*
270 * Overrides for Emacs so that we follow Linus's tabbing style.
271 * Emacs will notice this stuff at the end of the file and automatically
272 * adjust the settings for this buffer only. This must remain at the end
273 * of the file.
274 * ---------------------------------------------------------------------------
275 * Local variables:
276 * c-file-style: "linux"
277 * End:
278 */
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
new file mode 100644
index 000000000000..93fb121f86af
--- /dev/null
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/init.h"
7#include "linux/config.h"
8#include "mconsole_kern.h"
9
10#ifdef CONFIG_MCONSOLE
11
12extern int gdb_config(char *str);
13extern int gdb_remove(char *unused);
14
15static struct mc_device gdb_mc = {
16 .name = "gdb",
17 .config = gdb_config,
18 .remove = gdb_remove,
19};
20
21int gdb_mc_init(void)
22{
23 mconsole_register_dev(&gdb_mc);
24 return(0);
25}
26
27__initcall(gdb_mc_init);
28
29#endif
30
31/*
32 * Overrides for Emacs so that we follow Linus's tabbing style.
33 * Emacs will notice this stuff at the end of the file and automatically
34 * adjust the settings for this buffer only. This must remain at the end
35 * of the file.
36 * ---------------------------------------------------------------------------
37 * Local variables:
38 * c-file-style: "linux"
39 * End:
40 */
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
new file mode 100644
index 000000000000..8eff674107ca
--- /dev/null
+++ b/arch/um/kernel/tt/include/debug.h
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and
3 * Lars Brinkhoff.
4 * Licensed under the GPL
5 */
6
7#ifndef __DEBUG_H
8#define __DEBUG_H
9
10extern int debugger_proxy(int status, pid_t pid);
11extern void child_proxy(pid_t pid, int status);
12extern void init_proxy (pid_t pid, int waiting, int status);
13extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
14extern void fake_child_exit(void);
15extern int gdb_config(char *str);
16extern int gdb_remove(char *unused);
17
18#endif
19
20/*
21 * Overrides for Emacs so that we follow Linus's tabbing style.
22 * Emacs will notice this stuff at the end of the file and automatically
23 * adjust the settings for this buffer only. This must remain at the end
24 * of the file.
25 * ---------------------------------------------------------------------------
26 * Local variables:
27 * c-file-style: "linux"
28 * End:
29 */
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
new file mode 100644
index 000000000000..0440510ab3fe
--- /dev/null
+++ b/arch/um/kernel/tt/include/mmu-tt.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_MMU_H
7#define __TT_MMU_H
8
9struct mmu_context_tt {
10};
11
12#endif
13
14/*
15 * Overrides for Emacs so that we follow Linus's tabbing style.
16 * Emacs will notice this stuff at the end of the file and automatically
17 * adjust the settings for this buffer only. This must remain at the end
18 * of the file.
19 * ---------------------------------------------------------------------------
20 * Local variables:
21 * c-file-style: "linux"
22 * End:
23 */
diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
new file mode 100644
index 000000000000..efe462019069
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode-tt.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MODE_TT_H__
7#define __MODE_TT_H__
8
9#include "sysdep/ptrace.h"
10
11enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
12
13extern int tracing_pid;
14
15extern int tracer(int (*init_proc)(void *), void *sp);
16extern void user_time_init_tt(void);
17extern void sig_handler_common_tt(int sig, void *sc);
18extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
19extern void reboot_tt(void);
20extern void halt_tt(void);
21extern int is_tracer_winch(int pid, int fd, void *data);
22extern void kill_off_processes_tt(void);
23
24#endif
25
26/*
27 * Overrides for Emacs so that we follow Linus's tabbing style.
28 * Emacs will notice this stuff at the end of the file and automatically
29 * adjust the settings for this buffer only. This must remain at the end
30 * of the file.
31 * ---------------------------------------------------------------------------
32 * Local variables:
33 * c-file-style: "linux"
34 * End:
35 */
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
new file mode 100644
index 000000000000..28aaab3448fa
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode_kern-tt.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_MODE_KERN_H__
7#define __TT_MODE_KERN_H__
8
9#include "linux/sched.h"
10#include "asm/page.h"
11#include "asm/ptrace.h"
12#include "asm/uaccess.h"
13
14extern void *switch_to_tt(void *prev, void *next);
15extern void flush_thread_tt(void);
16extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
17 unsigned long esp);
18extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
19 unsigned long stack_top, struct task_struct *p,
20 struct pt_regs *regs);
21extern void release_thread_tt(struct task_struct *task);
22extern void exit_thread_tt(void);
23extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
24extern void init_idle_tt(void);
25extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
26extern void flush_tlb_kernel_vm_tt(void);
27extern void __flush_tlb_one_tt(unsigned long addr);
28extern void flush_tlb_range_tt(struct vm_area_struct *vma,
29 unsigned long start, unsigned long end);
30extern void flush_tlb_mm_tt(struct mm_struct *mm);
31extern void force_flush_all_tt(void);
32extern long execute_syscall_tt(void *r);
33extern void before_mem_tt(unsigned long brk_start);
34extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
35 unsigned long *task_size_out);
36extern int start_uml_tt(void);
37extern int external_pid_tt(struct task_struct *task);
38extern int thread_pid_tt(struct task_struct *task);
39
40#define kmem_end_tt (host_task_size - ABOVE_KMEM)
41
42#endif
43
44/*
45 * Overrides for Emacs so that we follow Linus's tabbing style.
46 * Emacs will notice this stuff at the end of the file and automatically
47 * adjust the settings for this buffer only. This must remain at the end
48 * of the file.
49 * ---------------------------------------------------------------------------
50 * Local variables:
51 * c-file-style: "linux"
52 * End:
53 */
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
new file mode 100644
index 000000000000..c667b67af405
--- /dev/null
+++ b/arch/um/kernel/tt/include/tt.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_H__
7#define __TT_H__
8
9#include "sysdep/ptrace.h"
10
11extern int gdb_pid;
12extern int debug;
13extern int debug_stop;
14extern int debug_trace;
15
16extern int honeypot;
17
18extern int fork_tramp(void *sig_stack);
19extern int do_proc_op(void *t, int proc_id);
20extern int tracer(int (*init_proc)(void *), void *sp);
21extern void attach_process(int pid);
22extern void tracer_panic(char *format, ...);
23extern void set_init_pid(int pid);
24extern int set_user_mode(void *task);
25extern void set_tracing(void *t, int tracing);
26extern int is_tracing(void *task);
27extern void syscall_handler(int sig, union uml_pt_regs *regs);
28extern void exit_kernel(int pid, void *task);
29extern void do_syscall(void *task, int pid, int local_using_sysemu);
30extern void do_sigtrap(void *task);
31extern int is_valid_pid(int pid);
32extern void remap_data(void *segment_start, void *segment_end, int w);
33extern long execute_syscall_tt(void *r);
34
35#endif
36
37/*
38 * Overrides for Emacs so that we follow Linus's tabbing style.
39 * Emacs will notice this stuff at the end of the file and automatically
40 * adjust the settings for this buffer only. This must remain at the end
41 * of the file.
42 * ---------------------------------------------------------------------------
43 * Local variables:
44 * c-file-style: "linux"
45 * End:
46 */
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
new file mode 100644
index 000000000000..f0bad010cebd
--- /dev/null
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_UACCESS_H
7#define __TT_UACCESS_H
8
9#include "linux/string.h"
10#include "linux/sched.h"
11#include "asm/processor.h"
12#include "asm/errno.h"
13#include "asm/current.h"
14#include "asm/a.out.h"
15#include "uml_uaccess.h"
16
17#define ABOVE_KMEM (16 * 1024 * 1024)
18
19extern unsigned long end_vm;
20extern unsigned long uml_physmem;
21
22#define under_task_size(addr, size) \
23 (((unsigned long) (addr) < TASK_SIZE) && \
24 (((unsigned long) (addr) + (size)) < TASK_SIZE))
25
26#define is_stack(addr, size) \
27 (((unsigned long) (addr) < STACK_TOP) && \
28 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
29 (((unsigned long) (addr) + (size)) <= STACK_TOP))
30
31#define access_ok_tt(type, addr, size) \
32 ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
33 (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
34 (under_task_size(addr, size) || is_stack(addr, size))))
35
36static inline int verify_area_tt(int type, const void * addr,
37 unsigned long size)
38{
39 return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
40}
41
42extern unsigned long get_fault_addr(void);
43
44extern int __do_copy_from_user(void *to, const void *from, int n,
45 void **fault_addr, void **fault_catcher);
46extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
47 void **fault_addr, void **fault_catcher);
48extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
49 void **fault_catcher);
50extern int __do_strnlen_user(const char *str, unsigned long n,
51 void **fault_addr, void **fault_catcher);
52
53extern int copy_from_user_tt(void *to, const void *from, int n);
54extern int copy_to_user_tt(void *to, const void *from, int n);
55extern int strncpy_from_user_tt(char *dst, const char *src, int count);
56extern int __clear_user_tt(void *mem, int len);
57extern int clear_user_tt(void *mem, int len);
58extern int strnlen_user_tt(const void *str, int len);
59
60#endif
61
62/*
63 * Overrides for Emacs so that we follow Linus's tabbing style.
64 * Emacs will notice this stuff at the end of the file and automatically
65 * adjust the settings for this buffer only. This must remain at the end
66 * of the file.
67 * ---------------------------------------------------------------------------
68 * Local variables:
69 * c-file-style: "linux"
70 * End:
71 */
diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
new file mode 100644
index 000000000000..92ec85d67c7c
--- /dev/null
+++ b/arch/um/kernel/tt/ksyms.c
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/module.h"
7#include "asm/uaccess.h"
8#include "mode.h"
9
10EXPORT_SYMBOL(__do_copy_from_user);
11EXPORT_SYMBOL(__do_copy_to_user);
12EXPORT_SYMBOL(__do_strncpy_from_user);
13EXPORT_SYMBOL(__do_strnlen_user);
14EXPORT_SYMBOL(__do_clear_user);
15
16EXPORT_SYMBOL(tracing_pid);
17EXPORT_SYMBOL(honeypot);
18
19/*
20 * Overrides for Emacs so that we follow Linus's tabbing style.
21 * Emacs will notice this stuff at the end of the file and automatically
22 * adjust the settings for this buffer only. This must remain at the end
23 * of the file.
24 * ---------------------------------------------------------------------------
25 * Local variables:
26 * c-file-style: "linux"
27 * End:
28 */
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
new file mode 100644
index 000000000000..74346a04a2b2
--- /dev/null
+++ b/arch/um/kernel/tt/mem.c
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/config.h"
8#include "linux/mm.h"
9#include "asm/uaccess.h"
10#include "mem_user.h"
11#include "kern_util.h"
12#include "user_util.h"
13#include "kern.h"
14#include "tt.h"
15
16void before_mem_tt(unsigned long brk_start)
17{
18 if(debug)
19 remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
20 remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
21 remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
22}
23
24#ifdef CONFIG_HOST_2G_2G
25#define TOP 0x80000000
26#else
27#define TOP 0xc0000000
28#endif
29
30#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
31#define START (TOP - SIZE)
32
33unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
34 unsigned long *task_size_out)
35{
36 /* Round up to the nearest 4M */
37 *host_size_out = ROUND_4M((unsigned long) &arg);
38 *task_size_out = START;
39 return(START);
40}
41
42/*
43 * Overrides for Emacs so that we follow Linus's tabbing style.
44 * Emacs will notice this stuff at the end of the file and automatically
45 * adjust the settings for this buffer only. This must remain at the end
46 * of the file.
47 * ---------------------------------------------------------------------------
48 * Local variables:
49 * c-file-style: "linux"
50 * End:
51 */
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
new file mode 100644
index 000000000000..3085267459b1
--- /dev/null
+++ b/arch/um/kernel/tt/mem_user.c
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <sys/mman.h>
12#include "tt.h"
13#include "mem_user.h"
14#include "user_util.h"
15
16void remap_data(void *segment_start, void *segment_end, int w)
17{
18 void *addr;
19 unsigned long size;
20 int data, prot;
21
22 if(w) prot = PROT_WRITE;
23 else prot = 0;
24 prot |= PROT_READ | PROT_EXEC;
25 size = (unsigned long) segment_end -
26 (unsigned long) segment_start;
27 data = create_mem_file(size);
28 addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
29 if(addr == MAP_FAILED){
30 perror("mapping new data segment");
31 exit(1);
32 }
33 memcpy(addr, segment_start, size);
34 if(switcheroo(data, prot, addr, segment_start, size) < 0){
35 printf("switcheroo failed\n");
36 exit(1);
37 }
38}
39
40/*
41 * Overrides for Emacs so that we follow Linus's tabbing style.
42 * Emacs will notice this stuff at the end of the file and automatically
43 * adjust the settings for this buffer only. This must remain at the end
44 * of the file.
45 * ---------------------------------------------------------------------------
46 * Local variables:
47 * c-file-style: "linux"
48 * End:
49 */
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
new file mode 100644
index 000000000000..f19f7c18febe
--- /dev/null
+++ b/arch/um/kernel/tt/process_kern.c
@@ -0,0 +1,476 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/signal.h"
8#include "linux/kernel.h"
9#include "linux/interrupt.h"
10#include "linux/ptrace.h"
11#include "asm/system.h"
12#include "asm/pgalloc.h"
13#include "asm/ptrace.h"
14#include "asm/tlbflush.h"
15#include "irq_user.h"
16#include "signal_user.h"
17#include "kern_util.h"
18#include "user_util.h"
19#include "os.h"
20#include "kern.h"
21#include "sigcontext.h"
22#include "time_user.h"
23#include "mem_user.h"
24#include "tlb.h"
25#include "mode.h"
26#include "init.h"
27#include "tt.h"
28
29void *switch_to_tt(void *prev, void *next, void *last)
30{
31 struct task_struct *from, *to, *prev_sched;
32 unsigned long flags;
33 int err, vtalrm, alrm, prof, cpu;
34 char c;
35 /* jailing and SMP are incompatible, so this doesn't need to be
36 * made per-cpu
37 */
38 static int reading;
39
40 from = prev;
41 to = next;
42
43 to->thread.prev_sched = from;
44
45 cpu = from->thread_info->cpu;
46 if(cpu == 0)
47 forward_interrupts(to->thread.mode.tt.extern_pid);
48#ifdef CONFIG_SMP
49 forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
50#endif
51 local_irq_save(flags);
52
53 vtalrm = change_sig(SIGVTALRM, 0);
54 alrm = change_sig(SIGALRM, 0);
55 prof = change_sig(SIGPROF, 0);
56
57 forward_pending_sigio(to->thread.mode.tt.extern_pid);
58
59 c = 0;
60 set_current(to);
61
62 reading = 0;
63 err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
64 if(err != sizeof(c))
65 panic("write of switch_pipe failed, err = %d", -err);
66
67 reading = 1;
68 if((from->exit_state == EXIT_ZOMBIE) ||
69 (from->exit_state == EXIT_DEAD))
70 os_kill_process(os_getpid(), 0);
71
72 err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
73 if(err != sizeof(c))
74 panic("read of switch_pipe failed, errno = %d", -err);
75
76 /* If the process that we have just scheduled away from has exited,
77 * then it needs to be killed here. The reason is that, even though
78 * it will kill itself when it next runs, that may be too late. Its
79 * stack will be freed, possibly before then, and if that happens,
80 * we have a use-after-free situation. So, it gets killed here
81 * in case it has not already killed itself.
82 */
83 prev_sched = current->thread.prev_sched;
84 if((prev_sched->exit_state == EXIT_ZOMBIE) ||
85 (prev_sched->exit_state == EXIT_DEAD))
86 os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
87
88 change_sig(SIGVTALRM, vtalrm);
89 change_sig(SIGALRM, alrm);
90 change_sig(SIGPROF, prof);
91
92 arch_switch();
93
94 flush_tlb_all();
95 local_irq_restore(flags);
96
97 return(current->thread.prev_sched);
98}
99
100void release_thread_tt(struct task_struct *task)
101{
102 int pid = task->thread.mode.tt.extern_pid;
103
104 if(os_getpid() != pid)
105 os_kill_process(pid, 0);
106}
107
108void exit_thread_tt(void)
109{
110 os_close_file(current->thread.mode.tt.switch_pipe[0]);
111 os_close_file(current->thread.mode.tt.switch_pipe[1]);
112}
113
114void suspend_new_thread(int fd)
115{
116 int err;
117 char c;
118
119 os_stop_process(os_getpid());
120 err = os_read_file(fd, &c, sizeof(c));
121 if(err != sizeof(c))
122 panic("read failed in suspend_new_thread, err = %d", -err);
123}
124
125void schedule_tail(task_t *prev);
126
127static void new_thread_handler(int sig)
128{
129 unsigned long disable;
130 int (*fn)(void *);
131 void *arg;
132
133 fn = current->thread.request.u.thread.proc;
134 arg = current->thread.request.u.thread.arg;
135
136 UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
137 disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
138 (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
139 SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
140
141 suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
142
143 force_flush_all();
144 if(current->thread.prev_sched != NULL)
145 schedule_tail(current->thread.prev_sched);
146 current->thread.prev_sched = NULL;
147
148 init_new_thread_signals(1);
149 enable_timer();
150 free_page(current->thread.temp_stack);
151 set_cmdline("(kernel thread)");
152
153 change_sig(SIGUSR1, 1);
154 change_sig(SIGVTALRM, 1);
155 change_sig(SIGPROF, 1);
156 local_irq_enable();
157 if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
158 do_exit(0);
159
160 /* XXX No set_user_mode here because a newly execed process will
161 * immediately segfault on its non-existent IP, coming straight back
162 * to the signal handler, which will call set_user_mode on its way
163 * out. This should probably change since it's confusing.
164 */
165}
166
167static int new_thread_proc(void *stack)
168{
169 /* local_irq_disable is needed to block out signals until this thread is
170 * properly scheduled. Otherwise, the tracing thread will get mighty
171 * upset about any signals that arrive before that.
172 * This has the complication that it sets the saved signal mask in
173 * the sigcontext to block signals. This gets restored when this
174 * thread (or a descendant, since they get a copy of this sigcontext)
175 * returns to userspace.
176 * So, this is compensated for elsewhere.
177 * XXX There is still a small window until local_irq_disable() actually
178 * finishes where signals are possible - shouldn't be a problem in
179 * practice since SIGIO hasn't been forwarded here yet, and the
180 * local_irq_disable should finish before a SIGVTALRM has time to be
181 * delivered.
182 */
183
184 local_irq_disable();
185 init_new_thread_stack(stack, new_thread_handler);
186 os_usr1_process(os_getpid());
187 change_sig(SIGUSR1, 1);
188 return(0);
189}
190
191/* Signal masking - signals are blocked at the start of fork_tramp. They
192 * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
193 * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
194 * so it is blocked before it's called. They are re-enabled on sigreturn
195 * despite the fact that they were blocked when the SIGUSR1 was issued because
196 * copy_thread copies the parent's sigcontext, including the signal mask
197 * onto the signal frame.
198 */
199
200void finish_fork_handler(int sig)
201{
202 UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
203 suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
204
205 force_flush_all();
206 if(current->thread.prev_sched != NULL)
207 schedule_tail(current->thread.prev_sched);
208 current->thread.prev_sched = NULL;
209
210 enable_timer();
211 change_sig(SIGVTALRM, 1);
212 local_irq_enable();
213 if(current->mm != current->parent->mm)
214 protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
215 1, 0, 1);
216 task_protections((unsigned long) current_thread);
217
218 free_page(current->thread.temp_stack);
219 local_irq_disable();
220 change_sig(SIGUSR1, 0);
221 set_user_mode(current);
222}
223
224int fork_tramp(void *stack)
225{
226 local_irq_disable();
227 arch_init_thread();
228 init_new_thread_stack(stack, finish_fork_handler);
229
230 os_usr1_process(os_getpid());
231 change_sig(SIGUSR1, 1);
232 return(0);
233}
234
235int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
236 unsigned long stack_top, struct task_struct * p,
237 struct pt_regs *regs)
238{
239 int (*tramp)(void *);
240 int new_pid, err;
241 unsigned long stack;
242
243 if(current->thread.forking)
244 tramp = fork_tramp;
245 else {
246 tramp = new_thread_proc;
247 p->thread.request.u.thread = current->thread.request.u.thread;
248 }
249
250 err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
251 if(err < 0){
252 printk("copy_thread : pipe failed, err = %d\n", -err);
253 return(err);
254 }
255
256 stack = alloc_stack(0, 0);
257 if(stack == 0){
258 printk(KERN_ERR "copy_thread : failed to allocate "
259 "temporary stack\n");
260 return(-ENOMEM);
261 }
262
263 clone_flags &= CLONE_VM;
264 p->thread.temp_stack = stack;
265 new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp);
266 if(new_pid < 0){
267 printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
268 -new_pid);
269 return(new_pid);
270 }
271
272 if(current->thread.forking){
273 sc_to_sc(UPT_SC(&p->thread.regs.regs),
274 UPT_SC(&current->thread.regs.regs));
275 SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
276 if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
277 }
278 p->thread.mode.tt.extern_pid = new_pid;
279
280 current->thread.request.op = OP_FORK;
281 current->thread.request.u.fork.pid = new_pid;
282 os_usr1_process(os_getpid());
283
284 /* Enable the signal and then disable it to ensure that it is handled
285 * here, and nowhere else.
286 */
287 change_sig(SIGUSR1, 1);
288
289 change_sig(SIGUSR1, 0);
290 err = 0;
291 return(err);
292}
293
294void reboot_tt(void)
295{
296 current->thread.request.op = OP_REBOOT;
297 os_usr1_process(os_getpid());
298 change_sig(SIGUSR1, 1);
299}
300
301void halt_tt(void)
302{
303 current->thread.request.op = OP_HALT;
304 os_usr1_process(os_getpid());
305 change_sig(SIGUSR1, 1);
306}
307
308void kill_off_processes_tt(void)
309{
310 struct task_struct *p;
311 int me;
312
313 me = os_getpid();
314 for_each_process(p){
315 if(p->thread.mode.tt.extern_pid != me)
316 os_kill_process(p->thread.mode.tt.extern_pid, 0);
317 }
318 if(init_task.thread.mode.tt.extern_pid != me)
319 os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
320}
321
322void initial_thread_cb_tt(void (*proc)(void *), void *arg)
323{
324 if(os_getpid() == tracing_pid){
325 (*proc)(arg);
326 }
327 else {
328 current->thread.request.op = OP_CB;
329 current->thread.request.u.cb.proc = proc;
330 current->thread.request.u.cb.arg = arg;
331 os_usr1_process(os_getpid());
332 change_sig(SIGUSR1, 1);
333
334 change_sig(SIGUSR1, 0);
335 }
336}
337
338int do_proc_op(void *t, int proc_id)
339{
340 struct task_struct *task;
341 struct thread_struct *thread;
342 int op, pid;
343
344 task = t;
345 thread = &task->thread;
346 op = thread->request.op;
347 switch(op){
348 case OP_NONE:
349 case OP_TRACE_ON:
350 break;
351 case OP_EXEC:
352 pid = thread->request.u.exec.pid;
353 do_exec(thread->mode.tt.extern_pid, pid);
354 thread->mode.tt.extern_pid = pid;
355 cpu_tasks[task->thread_info->cpu].pid = pid;
356 break;
357 case OP_FORK:
358 attach_process(thread->request.u.fork.pid);
359 break;
360 case OP_CB:
361 (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
362 break;
363 case OP_REBOOT:
364 case OP_HALT:
365 break;
366 default:
367 tracer_panic("Bad op in do_proc_op");
368 break;
369 }
370 thread->request.op = OP_NONE;
371 return(op);
372}
373
374void init_idle_tt(void)
375{
376 default_idle();
377}
378
379extern void start_kernel(void);
380
381static int start_kernel_proc(void *unused)
382{
383 int pid;
384
385 block_signals();
386 pid = os_getpid();
387
388 cpu_tasks[0].pid = pid;
389 cpu_tasks[0].task = current;
390#ifdef CONFIG_SMP
391 cpu_online_map = cpumask_of_cpu(0);
392#endif
393 if(debug) os_stop_process(pid);
394 start_kernel();
395 return(0);
396}
397
398void set_tracing(void *task, int tracing)
399{
400 ((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
401}
402
403int is_tracing(void *t)
404{
405 return (((struct task_struct *) t)->thread.mode.tt.tracing);
406}
407
408int set_user_mode(void *t)
409{
410 struct task_struct *task;
411
412 task = t ? t : current;
413 if(task->thread.mode.tt.tracing)
414 return(1);
415 task->thread.request.op = OP_TRACE_ON;
416 os_usr1_process(os_getpid());
417 return(0);
418}
419
420void set_init_pid(int pid)
421{
422 int err;
423
424 init_task.thread.mode.tt.extern_pid = pid;
425 err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
426 if(err)
427 panic("Can't create switch pipe for init_task, errno = %d",
428 -err);
429}
430
431int start_uml_tt(void)
432{
433 void *sp;
434 int pages;
435
436 pages = (1 << CONFIG_KERNEL_STACK_ORDER);
437 sp = (void *) ((unsigned long) init_task.thread_info) +
438 pages * PAGE_SIZE - sizeof(unsigned long);
439 return(tracer(start_kernel_proc, sp));
440}
441
442int external_pid_tt(struct task_struct *task)
443{
444 return(task->thread.mode.tt.extern_pid);
445}
446
447int thread_pid_tt(struct task_struct *task)
448{
449 return(task->thread.mode.tt.extern_pid);
450}
451
452int is_valid_pid(int pid)
453{
454 struct task_struct *task;
455
456 read_lock(&tasklist_lock);
457 for_each_process(task){
458 if(task->thread.mode.tt.extern_pid == pid){
459 read_unlock(&tasklist_lock);
460 return(1);
461 }
462 }
463 read_unlock(&tasklist_lock);
464 return(0);
465}
466
467/*
468 * Overrides for Emacs so that we follow Linus's tabbing style.
469 * Emacs will notice this stuff at the end of the file and automatically
470 * adjust the settings for this buffer only. This must remain at the end
471 * of the file.
472 * ---------------------------------------------------------------------------
473 * Local variables:
474 * c-file-style: "linux"
475 * End:
476 */
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
new file mode 100644
index 000000000000..3ad5b774de59
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -0,0 +1,10 @@
1#
2# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6obj-y = proxy.o ptrace.o sysdep.o wait.o
7
8USER_OBJS := $(obj-y)
9
10include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
new file mode 100644
index 000000000000..58800c50b10e
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -0,0 +1,377 @@
1/**********************************************************************
2proxy.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6
7Jeff Dike (jdike@karaya.com) : Modified for integration into uml
8**********************************************************************/
9
10/* XXX This file shouldn't refer to CONFIG_* */
11
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <signal.h>
17#include <string.h>
18#include <termios.h>
19#include <sys/wait.h>
20#include <sys/types.h>
21#include <sys/ioctl.h>
22#include <asm/unistd.h>
23#include "ptrace_user.h"
24
25#include "ptproxy.h"
26#include "sysdep.h"
27#include "wait.h"
28
29#include "user_util.h"
30#include "user.h"
31#include "os.h"
32#include "tempfile.h"
33
34static int debugger_wait(debugger_state *debugger, int *status, int options,
35 int (*syscall)(debugger_state *debugger, pid_t child),
36 int (*normal_return)(debugger_state *debugger,
37 pid_t unused),
38 int (*wait_return)(debugger_state *debugger,
39 pid_t unused))
40{
41 if(debugger->real_wait){
42 debugger->handle_trace = normal_return;
43 syscall_continue(debugger->pid);
44 debugger->real_wait = 0;
45 return(1);
46 }
47 debugger->wait_status_ptr = status;
48 debugger->wait_options = options;
49 if((debugger->debugee != NULL) && debugger->debugee->event){
50 syscall_continue(debugger->pid);
51 wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
52 NULL);
53 (*wait_return)(debugger, -1);
54 return(0);
55 }
56 else if(debugger->wait_options & WNOHANG){
57 syscall_cancel(debugger->pid, 0);
58 debugger->handle_trace = syscall;
59 return(0);
60 }
61 else {
62 syscall_pause(debugger->pid);
63 debugger->handle_trace = wait_return;
64 debugger->waiting = 1;
65 }
66 return(1);
67}
68
69/*
70 * Handle debugger trap, i.e. syscall.
71 */
72
73int debugger_syscall(debugger_state *debugger, pid_t child)
74{
75 long arg1, arg2, arg3, arg4, arg5, result;
76 int syscall, ret = 0;
77
78 syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
79 &arg5);
80
81 switch(syscall){
82 case __NR_execve:
83 /* execve never returns */
84 debugger->handle_trace = debugger_syscall;
85 break;
86
87 case __NR_ptrace:
88 if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
89 if(!debugger->debugee->in_context)
90 child = debugger->debugee->pid;
91 result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
92 &ret);
93 syscall_cancel(debugger->pid, result);
94 debugger->handle_trace = debugger_syscall;
95 return(ret);
96
97#ifdef __NR_waitpid
98 case __NR_waitpid:
99#endif
100 case __NR_wait4:
101 if(!debugger_wait(debugger, (int *) arg2, arg3,
102 debugger_syscall, debugger_normal_return,
103 proxy_wait_return))
104 return(0);
105 break;
106
107 case __NR_kill:
108 if(!debugger->debugee->in_context)
109 child = debugger->debugee->pid;
110 if(arg1 == debugger->debugee->pid){
111 result = kill(child, arg2);
112 syscall_cancel(debugger->pid, result);
113 debugger->handle_trace = debugger_syscall;
114 return(0);
115 }
116 else debugger->handle_trace = debugger_normal_return;
117 break;
118
119 default:
120 debugger->handle_trace = debugger_normal_return;
121 }
122
123 syscall_continue(debugger->pid);
124 return(0);
125}
126
127/* Used by the tracing thread */
128static debugger_state parent;
129static int parent_syscall(debugger_state *debugger, int pid);
130
131int init_parent_proxy(int pid)
132{
133 parent = ((debugger_state) { .pid = pid,
134 .wait_options = 0,
135 .wait_status_ptr = NULL,
136 .waiting = 0,
137 .real_wait = 0,
138 .expecting_child = 0,
139 .handle_trace = parent_syscall,
140 .debugee = NULL } );
141 return(0);
142}
143
144int parent_normal_return(debugger_state *debugger, pid_t unused)
145{
146 debugger->handle_trace = parent_syscall;
147 syscall_continue(debugger->pid);
148 return(0);
149}
150
151static int parent_syscall(debugger_state *debugger, int pid)
152{
153 long arg1, arg2, arg3, arg4, arg5;
154 int syscall;
155
156 syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
157
158 if((syscall == __NR_wait4)
159#ifdef __NR_waitpid
160 || (syscall == __NR_waitpid)
161#endif
162 ){
163 debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
164 parent_normal_return, parent_wait_return);
165 }
166 else ptrace(PTRACE_SYSCALL, pid, 0, 0);
167 return(0);
168}
169
170int debugger_normal_return(debugger_state *debugger, pid_t unused)
171{
172 debugger->handle_trace = debugger_syscall;
173 syscall_continue(debugger->pid);
174 return(0);
175}
176
177void debugger_cancelled_return(debugger_state *debugger, int result)
178{
179 debugger->handle_trace = debugger_syscall;
180 syscall_set_result(debugger->pid, result);
181 syscall_continue(debugger->pid);
182}
183
184/* Used by the tracing thread */
185static debugger_state debugger;
186static debugee_state debugee;
187
188void init_proxy (pid_t debugger_pid, int stopped, int status)
189{
190 debugger.pid = debugger_pid;
191 debugger.handle_trace = debugger_syscall;
192 debugger.debugee = &debugee;
193 debugger.waiting = 0;
194 debugger.real_wait = 0;
195 debugger.expecting_child = 0;
196
197 debugee.pid = 0;
198 debugee.traced = 0;
199 debugee.stopped = stopped;
200 debugee.event = 0;
201 debugee.zombie = 0;
202 debugee.died = 0;
203 debugee.wait_status = status;
204 debugee.in_context = 1;
205}
206
207int debugger_proxy(int status, int pid)
208{
209 int ret = 0, sig;
210
211 if(WIFSTOPPED(status)){
212 sig = WSTOPSIG(status);
213 if (sig == SIGTRAP)
214 ret = (*debugger.handle_trace)(&debugger, pid);
215
216 else if(sig == SIGCHLD){
217 if(debugger.expecting_child){
218 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
219 debugger.expecting_child = 0;
220 }
221 else if(debugger.waiting)
222 real_wait_return(&debugger);
223 else {
224 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
225 debugger.real_wait = 1;
226 }
227 }
228 else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
229 }
230 else if(WIFEXITED(status)){
231 tracer_panic("debugger (pid %d) exited with status %d",
232 debugger.pid, WEXITSTATUS(status));
233 }
234 else if(WIFSIGNALED(status)){
235 tracer_panic("debugger (pid %d) exited with signal %d",
236 debugger.pid, WTERMSIG(status));
237 }
238 else {
239 tracer_panic("proxy got unknown status (0x%x) on debugger "
240 "(pid %d)", status, debugger.pid);
241 }
242 return(ret);
243}
244
245void child_proxy(pid_t pid, int status)
246{
247 debugee.event = 1;
248 debugee.wait_status = status;
249
250 if(WIFSTOPPED(status)){
251 debugee.stopped = 1;
252 debugger.expecting_child = 1;
253 kill(debugger.pid, SIGCHLD);
254 }
255 else if(WIFEXITED(status) || WIFSIGNALED(status)){
256 debugee.zombie = 1;
257 debugger.expecting_child = 1;
258 kill(debugger.pid, SIGCHLD);
259 }
260 else panic("proxy got unknown status (0x%x) on child (pid %d)",
261 status, pid);
262}
263
264void debugger_parent_signal(int status, int pid)
265{
266 int sig;
267
268 if(WIFSTOPPED(status)){
269 sig = WSTOPSIG(status);
270 if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
271 else ptrace(PTRACE_SYSCALL, pid, 0, sig);
272 }
273}
274
275void fake_child_exit(void)
276{
277 int status, pid;
278
279 child_proxy(1, W_EXITCODE(0, 0));
280 while(debugger.waiting == 1){
281 CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
282 if(pid != debugger.pid){
283 printk("fake_child_exit - waitpid failed, "
284 "errno = %d\n", errno);
285 return;
286 }
287 debugger_proxy(status, debugger.pid);
288 }
289 CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
290 if(pid != debugger.pid){
291 printk("fake_child_exit - waitpid failed, "
292 "errno = %d\n", errno);
293 return;
294 }
295 if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
296 printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
297 errno);
298}
299
300char gdb_init_string[] =
301"att 1 \n\
302b panic \n\
303b stop \n\
304handle SIGWINCH nostop noprint pass \n\
305";
306
307int start_debugger(char *prog, int startup, int stop, int *fd_out)
308{
309 int slave, child;
310
311 slave = open_gdb_chan();
312 child = fork();
313 if(child == 0){
314 char *tempname = NULL;
315 int fd;
316
317 if(setsid() < 0) perror("setsid");
318 if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
319 (dup2(slave, 2) < 0)){
320 printk("start_debugger : dup2 failed, errno = %d\n",
321 errno);
322 exit(1);
323 }
324 if(ioctl(0, TIOCSCTTY, 0) < 0){
325 printk("start_debugger : TIOCSCTTY failed, "
326 "errno = %d\n", errno);
327 exit(1);
328 }
329 if(tcsetpgrp (1, os_getpid()) < 0){
330 printk("start_debugger : tcsetpgrp failed, "
331 "errno = %d\n", errno);
332#ifdef notdef
333 exit(1);
334#endif
335 }
336 fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
337 if(fd < 0){
338 printk("start_debugger : make_tempfile failed,"
339 "err = %d\n", -fd);
340 exit(1);
341 }
342 os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
343 if(startup){
344 if(stop){
345 os_write_file(fd, "b start_kernel\n",
346 strlen("b start_kernel\n"));
347 }
348 os_write_file(fd, "c\n", strlen("c\n"));
349 }
350 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
351 printk("start_debugger : PTRACE_TRACEME failed, "
352 "errno = %d\n", errno);
353 exit(1);
354 }
355 execlp("gdb", "gdb", "--command", tempname, prog, NULL);
356 printk("start_debugger : exec of gdb failed, errno = %d\n",
357 errno);
358 }
359 if(child < 0){
360 printk("start_debugger : fork for gdb failed, errno = %d\n",
361 errno);
362 return(-1);
363 }
364 *fd_out = slave;
365 return(child);
366}
367
368/*
369 * Overrides for Emacs so that we follow Linus's tabbing style.
370 * Emacs will notice this stuff at the end of the file and automatically
371 * adjust the settings for this buffer only. This must remain at the end
372 * of the file.
373 * ---------------------------------------------------------------------------
374 * Local variables:
375 * c-file-style: "linux"
376 * End:
377 */
diff --git a/arch/um/kernel/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h
new file mode 100644
index 000000000000..5eb0285b1968
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptproxy.h
@@ -0,0 +1,61 @@
1/**********************************************************************
2ptproxy.h
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6**********************************************************************/
7
8#ifndef __PTPROXY_H
9#define __PTPROXY_H
10
11#include <sys/types.h>
12
13typedef struct debugger debugger_state;
14typedef struct debugee debugee_state;
15
16struct debugger
17{
18 pid_t pid;
19 int wait_options;
20 int *wait_status_ptr;
21 unsigned int waiting : 1;
22 unsigned int real_wait : 1;
23 unsigned int expecting_child : 1;
24 int (*handle_trace) (debugger_state *, pid_t);
25
26 debugee_state *debugee;
27};
28
29struct debugee
30{
31 pid_t pid;
32 int wait_status;
33 unsigned int died : 1;
34 unsigned int event : 1;
35 unsigned int stopped : 1;
36 unsigned int trace_singlestep : 1;
37 unsigned int trace_syscall : 1;
38 unsigned int traced : 1;
39 unsigned int zombie : 1;
40 unsigned int in_context : 1;
41};
42
43extern int debugger_syscall(debugger_state *debugger, pid_t pid);
44extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
45
46extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
47 int *strace_out);
48extern void debugger_cancelled_return(debugger_state *debugger, int result);
49
50#endif
51
52/*
53 * Overrides for Emacs so that we follow Linus's tabbing style.
54 * Emacs will notice this stuff at the end of the file and automatically
55 * adjust the settings for this buffer only. This must remain at the end
56 * of the file.
57 * ---------------------------------------------------------------------------
58 * Local variables:
59 * c-file-style: "linux"
60 * End:
61 */
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
new file mode 100644
index 000000000000..528a5fc8d887
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -0,0 +1,237 @@
1/**********************************************************************
2ptrace.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6
7Jeff Dike (jdike@karaya.com) : Modified for integration into uml
8**********************************************************************/
9
10#include <errno.h>
11#include <unistd.h>
12#include <signal.h>
13#include <sys/types.h>
14#include <sys/time.h>
15#include <sys/wait.h>
16
17#include "ptproxy.h"
18#include "debug.h"
19#include "user_util.h"
20#include "kern_util.h"
21#include "ptrace_user.h"
22#include "tt.h"
23
24long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
25 long arg3, long arg4, pid_t child, int *ret)
26{
27 sigset_t relay;
28 long result;
29 int status;
30
31 *ret = 0;
32 if(debugger->debugee->died) return(-ESRCH);
33
34 switch(arg1){
35 case PTRACE_ATTACH:
36 if(debugger->debugee->traced) return(-EPERM);
37
38 debugger->debugee->pid = arg2;
39 debugger->debugee->traced = 1;
40
41 if(is_valid_pid(arg2) && (arg2 != child)){
42 debugger->debugee->in_context = 0;
43 kill(arg2, SIGSTOP);
44 debugger->debugee->event = 1;
45 debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
46 }
47 else {
48 debugger->debugee->in_context = 1;
49 if(debugger->debugee->stopped)
50 child_proxy(child, W_STOPCODE(SIGSTOP));
51 else kill(child, SIGSTOP);
52 }
53
54 return(0);
55
56 case PTRACE_DETACH:
57 if(!debugger->debugee->traced) return(-EPERM);
58
59 debugger->debugee->traced = 0;
60 debugger->debugee->pid = 0;
61 if(!debugger->debugee->in_context)
62 kill(child, SIGCONT);
63
64 return(0);
65
66 case PTRACE_CONT:
67 if(!debugger->debugee->in_context) return(-EPERM);
68 *ret = PTRACE_CONT;
69 return(ptrace(PTRACE_CONT, child, arg3, arg4));
70
71#ifdef UM_HAVE_GETFPREGS
72 case PTRACE_GETFPREGS:
73 {
74 long regs[FP_FRAME_SIZE];
75 int i, result;
76
77 result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
78 if(result == -1) return(-errno);
79
80 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
81 ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
82 regs[i]);
83 return(result);
84 }
85#endif
86
87#ifdef UM_HAVE_GETFPXREGS
88 case PTRACE_GETFPXREGS:
89 {
90 long regs[FPX_FRAME_SIZE];
91 int i, result;
92
93 result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
94 if(result == -1) return(-errno);
95
96 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
97 ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
98 regs[i]);
99 return(result);
100 }
101#endif
102
103#ifdef UM_HAVE_GETREGS
104 case PTRACE_GETREGS:
105 {
106 long regs[FRAME_SIZE];
107 int i, result;
108
109 result = ptrace(PTRACE_GETREGS, child, 0, regs);
110 if(result == -1) return(-errno);
111
112 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
113 ptrace (PTRACE_POKEDATA, debugger->pid,
114 arg4 + 4 * i, regs[i]);
115 return(result);
116 }
117 break;
118#endif
119
120 case PTRACE_KILL:
121 result = ptrace(PTRACE_KILL, child, arg3, arg4);
122 if(result == -1) return(-errno);
123
124 return(result);
125
126 case PTRACE_PEEKDATA:
127 case PTRACE_PEEKTEXT:
128 case PTRACE_PEEKUSR:
129 /* The value being read out could be -1, so we have to
130 * check errno to see if there's an error, and zero it
131 * beforehand so we're not faked out by an old error
132 */
133
134 errno = 0;
135 result = ptrace(arg1, child, arg3, 0);
136 if((result == -1) && (errno != 0)) return(-errno);
137
138 result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
139 if(result == -1) return(-errno);
140
141 return(result);
142
143 case PTRACE_POKEDATA:
144 case PTRACE_POKETEXT:
145 case PTRACE_POKEUSR:
146 result = ptrace(arg1, child, arg3, arg4);
147 if(result == -1) return(-errno);
148
149 if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
150 return(result);
151
152#ifdef UM_HAVE_SETFPREGS
153 case PTRACE_SETFPREGS:
154 {
155 long regs[FP_FRAME_SIZE];
156 int i;
157
158 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
159 regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
160 arg4 + 4 * i, 0);
161 result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
162 if(result == -1) return(-errno);
163
164 return(result);
165 }
166#endif
167
168#ifdef UM_HAVE_SETFPXREGS
169 case PTRACE_SETFPXREGS:
170 {
171 long regs[FPX_FRAME_SIZE];
172 int i;
173
174 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
175 regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
176 arg4 + 4 * i, 0);
177 result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
178 if(result == -1) return(-errno);
179
180 return(result);
181 }
182#endif
183
184#ifdef UM_HAVE_SETREGS
185 case PTRACE_SETREGS:
186 {
187 long regs[FRAME_SIZE];
188 int i;
189
190 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
191 regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
192 arg4 + 4 * i, 0);
193 result = ptrace(PTRACE_SETREGS, child, 0, regs);
194 if(result == -1) return(-errno);
195
196 return(result);
197 }
198#endif
199
200 case PTRACE_SINGLESTEP:
201 if(!debugger->debugee->in_context) return(-EPERM);
202 sigemptyset(&relay);
203 sigaddset(&relay, SIGSEGV);
204 sigaddset(&relay, SIGILL);
205 sigaddset(&relay, SIGBUS);
206 result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
207 if(result == -1) return(-errno);
208
209 status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
210 &relay);
211 child_proxy(child, status);
212 return(result);
213
214 case PTRACE_SYSCALL:
215 if(!debugger->debugee->in_context) return(-EPERM);
216 result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
217 if(result == -1) return(-errno);
218
219 *ret = PTRACE_SYSCALL;
220 return(result);
221
222 case PTRACE_TRACEME:
223 default:
224 return(-EINVAL);
225 }
226}
227
228/*
229 * Overrides for Emacs so that we follow Linus's tabbing style.
230 * Emacs will notice this stuff at the end of the file and automatically
231 * adjust the settings for this buffer only. This must remain at the end
232 * of the file.
233 * ---------------------------------------------------------------------------
234 * Local variables:
235 * c-file-style: "linux"
236 * End:
237 */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
new file mode 100644
index 000000000000..a5f0e01e214e
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -0,0 +1,70 @@
1/**********************************************************************
2sysdep.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6**********************************************************************/
7
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <signal.h>
12#include <errno.h>
13#include <sys/types.h>
14#include <linux/unistd.h>
15#include "ptrace_user.h"
16#include "user_util.h"
17#include "user.h"
18
19int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
20 long *arg5)
21{
22 *arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
23 *arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
24 *arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
25 *arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
26 *arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
27 return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
28}
29
30void syscall_cancel(pid_t pid, int result)
31{
32 if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
33 __NR_getpid) < 0) ||
34 (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
35 (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
36 (ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
37 (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
38 printk("ptproxy: couldn't cancel syscall: errno = %d\n",
39 errno);
40}
41
42void syscall_set_result(pid_t pid, long result)
43{
44 ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
45}
46
47void syscall_continue(pid_t pid)
48{
49 ptrace(PTRACE_SYSCALL, pid, 0, 0);
50}
51
52int syscall_pause(pid_t pid)
53{
54 if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
55 printk("syscall_change - ptrace failed, errno = %d\n", errno);
56 return(-1);
57 }
58 return(0);
59}
60
61/*
62 * Overrides for Emacs so that we follow Linus's tabbing style.
63 * Emacs will notice this stuff at the end of the file and automatically
64 * adjust the settings for this buffer only. This must remain at the end
65 * of the file.
66 * ---------------------------------------------------------------------------
67 * Local variables:
68 * c-file-style: "linux"
69 * End:
70 */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h
new file mode 100644
index 000000000000..735f488049aa
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.h
@@ -0,0 +1,25 @@
1/**********************************************************************
2sysdep.h
3
4Copyright (C) 1999 Lars Brinkhoff.
5Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
6See the file COPYING for licensing terms and conditions.
7**********************************************************************/
8
9extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,
10 long *arg4, long *arg5);
11extern void syscall_cancel (pid_t pid, long result);
12extern void syscall_set_result (pid_t pid, long result);
13extern void syscall_continue (pid_t pid);
14extern int syscall_pause(pid_t pid);
15
16/*
17 * Overrides for Emacs so that we follow Linus's tabbing style.
18 * Emacs will notice this stuff at the end of the file and automatically
19 * adjust the settings for this buffer only. This must remain at the end
20 * of the file.
21 * ---------------------------------------------------------------------------
22 * Local variables:
23 * c-file-style: "linux"
24 * End:
25 */
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
new file mode 100644
index 000000000000..12f6319d8d76
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -0,0 +1,86 @@
1/**********************************************************************
2wait.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6
7**********************************************************************/
8
9#include <errno.h>
10#include <signal.h>
11#include <sys/wait.h>
12
13#include "ptproxy.h"
14#include "sysdep.h"
15#include "wait.h"
16#include "user_util.h"
17#include "ptrace_user.h"
18#include "sysdep/ptrace.h"
19#include "sysdep/sigcontext.h"
20
21int proxy_wait_return(struct debugger *debugger, pid_t unused)
22{
23 debugger->waiting = 0;
24
25 if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
26 debugger_cancelled_return(debugger, -ECHILD);
27 return(0);
28 }
29
30 if(debugger->debugee->zombie && debugger->debugee->event)
31 debugger->debugee->died = 1;
32
33 if(debugger->debugee->event){
34 debugger->debugee->event = 0;
35 ptrace(PTRACE_POKEDATA, debugger->pid,
36 debugger->wait_status_ptr,
37 debugger->debugee->wait_status);
38 /* if (wait4)
39 ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
40 debugger_cancelled_return(debugger, debugger->debugee->pid);
41 return(0);
42 }
43
44 /* pause will return -EINTR, which happens to be right for wait */
45 debugger_normal_return(debugger, -1);
46 return(0);
47}
48
49int parent_wait_return(struct debugger *debugger, pid_t unused)
50{
51 return(debugger_normal_return(debugger, -1));
52}
53
54int real_wait_return(struct debugger *debugger)
55{
56 unsigned long ip;
57 int pid;
58
59 pid = debugger->pid;
60
61 ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
62 IP_RESTART_SYSCALL(ip);
63
64 if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
65 tracer_panic("real_wait_return : Failed to restart system "
66 "call, errno = %d\n", errno);
67
68 if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
69 (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
70 (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
71 debugger_normal_return(debugger, -1))
72 tracer_panic("real_wait_return : gdb failed to wait, "
73 "errno = %d\n", errno);
74 return(0);
75}
76
77/*
78 * Overrides for Emacs so that we follow Linus's tabbing style.
79 * Emacs will notice this stuff at the end of the file and automatically
80 * adjust the settings for this buffer only. This must remain at the end
81 * of the file.
82 * ---------------------------------------------------------------------------
83 * Local variables:
84 * c-file-style: "linux"
85 * End:
86 */
diff --git a/arch/um/kernel/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h
new file mode 100644
index 000000000000..542e73ee2cee
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.h
@@ -0,0 +1,15 @@
1/**********************************************************************
2wait.h
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6**********************************************************************/
7
8#ifndef __PTPROXY_WAIT_H
9#define __PTPROXY_WAIT_H
10
11extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
12extern int real_wait_return(struct debugger *debugger);
13extern int parent_wait_return(struct debugger *debugger, pid_t unused);
14
15#endif
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
new file mode 100644
index 000000000000..2650a628719e
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/types.h"
7#include "linux/utime.h"
8#include "linux/sys.h"
9#include "linux/ptrace.h"
10#include "asm/unistd.h"
11#include "asm/ptrace.h"
12#include "asm/uaccess.h"
13#include "asm/stat.h"
14#include "sysdep/syscalls.h"
15#include "kern_util.h"
16
17extern syscall_handler_t *sys_call_table[];
18
19long execute_syscall_tt(void *r)
20{
21 struct pt_regs *regs = r;
22 long res;
23 int syscall;
24
25#ifdef CONFIG_SYSCALL_DEBUG
26 current->thread.nsyscalls++;
27 nsyscalls++;
28#endif
29 syscall = UPT_SYSCALL_NR(&regs->regs);
30
31 if((syscall >= NR_syscalls) || (syscall < 0))
32 res = -ENOSYS;
33 else res = EXECUTE_SYSCALL(syscall, regs);
34
35 return(res);
36}
37
38/*
39 * Overrides for Emacs so that we follow Linus's tabbing style.
40 * Emacs will notice this stuff at the end of the file and automatically
41 * adjust the settings for this buffer only. This must remain at the end
42 * of the file.
43 * ---------------------------------------------------------------------------
44 * Local variables:
45 * c-file-style: "linux"
46 * End:
47 */
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
new file mode 100644
index 000000000000..e4e7e9c2224c
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <signal.h>
8#include <errno.h>
9#include <asm/unistd.h>
10#include "sysdep/ptrace.h"
11#include "sigcontext.h"
12#include "ptrace_user.h"
13#include "task.h"
14#include "user_util.h"
15#include "kern_util.h"
16#include "syscall_user.h"
17#include "tt.h"
18
19
20void syscall_handler_tt(int sig, union uml_pt_regs *regs)
21{
22 void *sc;
23 long result;
24 int syscall;
25#ifdef UML_CONFIG_DEBUG_SYSCALL
26 int index;
27#endif
28
29 syscall = UPT_SYSCALL_NR(regs);
30 sc = UPT_SC(regs);
31 SC_START_SYSCALL(sc);
32
33#ifdef UML_CONFIG_DEBUG_SYSCALL
34 index = record_syscall_start(syscall);
35#endif
36 syscall_trace(regs, 0);
37 result = execute_syscall_tt(regs);
38
39 /* regs->sc may have changed while the system call ran (there may
40 * have been an interrupt or segfault), so it needs to be refreshed.
41 */
42 UPT_SC(regs) = sc;
43
44 SC_SET_SYSCALL_RETURN(sc, result);
45
46 syscall_trace(regs, 1);
47#ifdef UML_CONFIG_DEBUG_SYSCALL
48 record_syscall_end(index, result);
49#endif
50}
51
52void do_sigtrap(void *task)
53{
54 UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
55}
56
57void do_syscall(void *task, int pid, int local_using_sysemu)
58{
59 unsigned long proc_regs[FRAME_SIZE];
60
61 if(ptrace_getregs(pid, proc_regs) < 0)
62 tracer_panic("Couldn't read registers");
63
64 UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
65
66 if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
67 ((unsigned long *) PT_IP(proc_regs) <= &_etext))
68 tracer_panic("I'm tracing myself and I can't get out");
69
70 /* advanced sysemu mode set syscall number to -1 automatically */
71 if (local_using_sysemu==2)
72 return;
73
74 /* syscall number -1 in sysemu skips syscall restarting in host */
75 if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
76 local_using_sysemu ? -1 : __NR_getpid) < 0)
77 tracer_panic("do_syscall : Nullifying syscall failed, "
78 "errno = %d", errno);
79}
80
81/*
82 * Overrides for Emacs so that we follow Linus's tabbing style.
83 * Emacs will notice this stuff at the end of the file and automatically
84 * adjust the settings for this buffer only. This must remain at the end
85 * of the file.
86 * ---------------------------------------------------------------------------
87 * Local variables:
88 * c-file-style: "linux"
89 * End:
90 */
diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
new file mode 100644
index 000000000000..8565b71b07cd
--- /dev/null
+++ b/arch/um/kernel/tt/time.c
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include <sys/time.h>
8#include <time_user.h>
9#include "process.h"
10#include "user.h"
11
12void user_time_init_tt(void)
13{
14 if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
15 panic("Couldn't set SIGVTALRM handler");
16 set_interval(ITIMER_VIRTUAL);
17}
18
19/*
20 * Overrides for Emacs so that we follow Linus's tabbing style.
21 * Emacs will notice this stuff at the end of the file and automatically
22 * adjust the settings for this buffer only. This must remain at the end
23 * of the file.
24 * ---------------------------------------------------------------------------
25 * Local variables:
26 * c-file-style: "linux"
27 * End:
28 */
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
new file mode 100644
index 000000000000..203216ad86f1
--- /dev/null
+++ b/arch/um/kernel/tt/tlb.c
@@ -0,0 +1,149 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL
5 */
6
7#include "linux/stddef.h"
8#include "linux/kernel.h"
9#include "linux/sched.h"
10#include "linux/mm.h"
11#include "asm/page.h"
12#include "asm/pgtable.h"
13#include "asm/uaccess.h"
14#include "asm/tlbflush.h"
15#include "user_util.h"
16#include "mem_user.h"
17#include "os.h"
18#include "tlb.h"
19
20static void do_ops(int unused, struct host_vm_op *ops, int last)
21{
22 struct host_vm_op *op;
23 int i;
24
25 for(i = 0; i <= last; i++){
26 op = &ops[i];
27 switch(op->type){
28 case MMAP:
29 os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
30 op->u.mmap.offset, op->u.mmap.len,
31 op->u.mmap.r, op->u.mmap.w,
32 op->u.mmap.x);
33 break;
34 case MUNMAP:
35 os_unmap_memory((void *) op->u.munmap.addr,
36 op->u.munmap.len);
37 break;
38 case MPROTECT:
39 protect_memory(op->u.mprotect.addr, op->u.munmap.len,
40 op->u.mprotect.r, op->u.mprotect.w,
41 op->u.mprotect.x, 1);
42 break;
43 default:
44 printk("Unknown op type %d in do_ops\n", op->type);
45 break;
46 }
47 }
48}
49
50static void fix_range(struct mm_struct *mm, unsigned long start_addr,
51 unsigned long end_addr, int force)
52{
53 if((current->thread.mode.tt.extern_pid != -1) &&
54 (current->thread.mode.tt.extern_pid != os_getpid()))
55 panic("fix_range fixing wrong address space, current = 0x%p",
56 current);
57
58 fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
59}
60
61atomic_t vmchange_seq = ATOMIC_INIT(1);
62
63void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
64{
65 if(flush_tlb_kernel_range_common(start, end))
66 atomic_inc(&vmchange_seq);
67}
68
69static void protect_vm_page(unsigned long addr, int w, int must_succeed)
70{
71 int err;
72
73 err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed);
74 if(err == 0) return;
75 else if((err == -EFAULT) || (err == -ENOMEM)){
76 flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
77 protect_vm_page(addr, w, 1);
78 }
79 else panic("protect_vm_page : protect failed, errno = %d\n", err);
80}
81
82void mprotect_kernel_vm(int w)
83{
84 struct mm_struct *mm;
85 pgd_t *pgd;
86 pud_t *pud;
87 pmd_t *pmd;
88 pte_t *pte;
89 unsigned long addr;
90
91 mm = &init_mm;
92 for(addr = start_vm; addr < end_vm;){
93 pgd = pgd_offset(mm, addr);
94 pud = pud_offset(pgd, addr);
95 pmd = pmd_offset(pud, addr);
96 if(pmd_present(*pmd)){
97 pte = pte_offset_kernel(pmd, addr);
98 if(pte_present(*pte)) protect_vm_page(addr, w, 0);
99 addr += PAGE_SIZE;
100 }
101 else addr += PMD_SIZE;
102 }
103}
104
105void flush_tlb_kernel_vm_tt(void)
106{
107 flush_tlb_kernel_range(start_vm, end_vm);
108}
109
110void __flush_tlb_one_tt(unsigned long addr)
111{
112 flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
113}
114
115void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,
116 unsigned long end)
117{
118 if(vma->vm_mm != current->mm) return;
119
120 /* Assumes that the range start ... end is entirely within
121 * either process memory or kernel vm
122 */
123 if((start >= start_vm) && (start < end_vm)){
124 if(flush_tlb_kernel_range_common(start, end))
125 atomic_inc(&vmchange_seq);
126 }
127 else fix_range(vma->vm_mm, start, end, 0);
128}
129
130void flush_tlb_mm_tt(struct mm_struct *mm)
131{
132 unsigned long seq;
133
134 if(mm != current->mm) return;
135
136 fix_range(mm, 0, STACK_TOP, 0);
137
138 seq = atomic_read(&vmchange_seq);
139 if(current->thread.mode.tt.vm_seq == seq)
140 return;
141 current->thread.mode.tt.vm_seq = seq;
142 flush_tlb_kernel_range_common(start_vm, end_vm);
143}
144
145void force_flush_all_tt(void)
146{
147 fix_range(current->mm, 0, STACK_TOP, 1);
148 flush_tlb_kernel_range_common(start_vm, end_vm);
149}
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
new file mode 100644
index 000000000000..7b5d937e5955
--- /dev/null
+++ b/arch/um/kernel/tt/tracer.c
@@ -0,0 +1,480 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdarg.h>
9#include <unistd.h>
10#include <signal.h>
11#include <errno.h>
12#include <sched.h>
13#include <string.h>
14#include <sys/mman.h>
15#include <sys/time.h>
16#include <sys/wait.h>
17#include "user.h"
18#include "sysdep/ptrace.h"
19#include "sigcontext.h"
20#include "sysdep/sigcontext.h"
21#include "os.h"
22#include "signal_user.h"
23#include "user_util.h"
24#include "mem_user.h"
25#include "process.h"
26#include "kern_util.h"
27#include "chan_user.h"
28#include "ptrace_user.h"
29#include "mode.h"
30#include "tt.h"
31
32static int tracer_winch[2];
33
34int is_tracer_winch(int pid, int fd, void *data)
35{
36 if(pid != tracing_pid)
37 return(0);
38
39 register_winch_irq(tracer_winch[0], fd, -1, data);
40 return(1);
41}
42
43static void tracer_winch_handler(int sig)
44{
45 int n;
46 char c = 1;
47
48 n = os_write_file(tracer_winch[1], &c, sizeof(c));
49 if(n != sizeof(c))
50 printk("tracer_winch_handler - write failed, err = %d\n", -n);
51}
52
53/* Called only by the tracing thread during initialization */
54
55static void setup_tracer_winch(void)
56{
57 int err;
58
59 err = os_pipe(tracer_winch, 1, 1);
60 if(err < 0){
61 printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
62 return;
63 }
64 signal(SIGWINCH, tracer_winch_handler);
65}
66
67void attach_process(int pid)
68{
69 if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
70 (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
71 tracer_panic("OP_FORK failed to attach pid");
72 wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
73 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
74 tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
75 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
76 tracer_panic("OP_FORK failed to continue process");
77}
78
79void tracer_panic(char *format, ...)
80{
81 va_list ap;
82
83 va_start(ap, format);
84 vprintf(format, ap);
85 va_end(ap);
86 printf("\n");
87 while(1) pause();
88}
89
90static void tracer_segv(int sig, struct sigcontext sc)
91{
92 printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
93 SC_FAULT_ADDR(&sc), SC_IP(&sc));
94 while(1)
95 pause();
96}
97
98/* Changed early in boot, and then only read */
99int debug = 0;
100int debug_stop = 1;
101int debug_parent = 0;
102int honeypot = 0;
103
104static int signal_tramp(void *arg)
105{
106 int (*proc)(void *);
107
108 if(honeypot && munmap((void *) (host_task_size - 0x10000000),
109 0x10000000))
110 panic("Unmapping stack failed");
111 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
112 panic("ptrace PTRACE_TRACEME failed");
113 os_stop_process(os_getpid());
114 change_sig(SIGWINCH, 0);
115 signal(SIGUSR1, SIG_IGN);
116 change_sig(SIGCHLD, 0);
117 signal(SIGSEGV, (__sighandler_t) sig_handler);
118 set_cmdline("(idle thread)");
119 set_init_pid(os_getpid());
120 proc = arg;
121 return((*proc)(NULL));
122}
123
124static void sleeping_process_signal(int pid, int sig)
125{
126 switch(sig){
127 /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
128 * right because the process must be in the kernel already.
129 */
130 case SIGCONT:
131 case SIGTSTP:
132 if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
133 tracer_panic("sleeping_process_signal : Failed to "
134 "continue pid %d, signal = %d, "
135 "errno = %d\n", pid, sig, errno);
136 break;
137
138 /* This happens when the debugger (e.g. strace) is doing system call
139 * tracing on the kernel. During a context switch, the current task
140 * will be set to the incoming process and the outgoing process will
141 * hop into write and then read. Since it's not the current process
142 * any more, the trace of those will land here. So, we need to just
143 * PTRACE_SYSCALL it.
144 */
145 case (SIGTRAP + 0x80):
146 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
147 tracer_panic("sleeping_process_signal : Failed to "
148 "PTRACE_SYSCALL pid %d, errno = %d\n",
149 pid, errno);
150 break;
151 case SIGSTOP:
152 break;
153 default:
154 tracer_panic("sleeping process %d got unexpected "
155 "signal : %d\n", pid, sig);
156 break;
157 }
158}
159
160/* Accessed only by the tracing thread */
161int debugger_pid = -1;
162int debugger_parent = -1;
163int debugger_fd = -1;
164int gdb_pid = -1;
165
166struct {
167 int pid;
168 int signal;
169 unsigned long addr;
170 struct timeval time;
171} signal_record[1024][32];
172
173int signal_index[32];
174int nsignals = 0;
175int debug_trace = 0;
176extern int io_nsignals, io_count, intr_count;
177
178extern void signal_usr1(int sig);
179
180int tracing_pid = -1;
181
182int tracer(int (*init_proc)(void *), void *sp)
183{
184 void *task = NULL;
185 int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
186 int proc_id = 0, n, err, old_tracing = 0, strace = 0;
187 int local_using_sysemu = 0;
188#ifdef UML_CONFIG_SYSCALL_DEBUG
189 unsigned long eip = 0;
190 int last_index;
191#endif
192 signal(SIGPIPE, SIG_IGN);
193 setup_tracer_winch();
194 tracing_pid = os_getpid();
195 printf("tracing thread pid = %d\n", tracing_pid);
196
197 pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
198 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
199 if(n < 0){
200 printf("waitpid on idle thread failed, errno = %d\n", errno);
201 exit(1);
202 }
203 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
204 printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
205 exit(1);
206 }
207 if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
208 printf("Failed to continue idle thread, errno = %d\n", errno);
209 exit(1);
210 }
211
212 signal(SIGSEGV, (sighandler_t) tracer_segv);
213 signal(SIGUSR1, signal_usr1);
214 if(debug_trace){
215 printf("Tracing thread pausing to be attached\n");
216 stop();
217 }
218 if(debug){
219 if(gdb_pid != -1)
220 debugger_pid = attach_debugger(pid, gdb_pid, 1);
221 else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
222 if(debug_parent){
223 debugger_parent = os_process_parent(debugger_pid);
224 init_parent_proxy(debugger_parent);
225 err = attach(debugger_parent);
226 if(err){
227 printf("Failed to attach debugger parent %d, "
228 "errno = %d\n", debugger_parent, -err);
229 debugger_parent = -1;
230 }
231 else {
232 if(ptrace(PTRACE_SYSCALL, debugger_parent,
233 0, 0) < 0){
234 printf("Failed to continue debugger "
235 "parent, errno = %d\n", errno);
236 debugger_parent = -1;
237 }
238 }
239 }
240 }
241 set_cmdline("(tracing thread)");
242 while(1){
243 CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
244 if(pid <= 0){
245 if(errno != ECHILD){
246 printf("wait failed - errno = %d\n", errno);
247 }
248 continue;
249 }
250 if(pid == debugger_pid){
251 int cont = 0;
252
253 if(WIFEXITED(status) || WIFSIGNALED(status))
254 debugger_pid = -1;
255 /* XXX Figure out how to deal with gdb and SMP */
256 else cont = debugger_signal(status, cpu_tasks[0].pid);
257 if(cont == PTRACE_SYSCALL) strace = 1;
258 continue;
259 }
260 else if(pid == debugger_parent){
261 debugger_parent_signal(status, pid);
262 continue;
263 }
264 nsignals++;
265 if(WIFEXITED(status)) ;
266#ifdef notdef
267 {
268 printf("Child %d exited with status %d\n", pid,
269 WEXITSTATUS(status));
270 }
271#endif
272 else if(WIFSIGNALED(status)){
273 sig = WTERMSIG(status);
274 if(sig != 9){
275 printf("Child %d exited with signal %d\n", pid,
276 sig);
277 }
278 }
279 else if(WIFSTOPPED(status)){
280 proc_id = pid_to_processor_id(pid);
281 sig = WSTOPSIG(status);
282#ifdef UML_CONFIG_SYSCALL_DEBUG
283 if(signal_index[proc_id] == 1024){
284 signal_index[proc_id] = 0;
285 last_index = 1023;
286 }
287 else last_index = signal_index[proc_id] - 1;
288 if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
289 (sig == SIGALRM)) &&
290 (signal_record[proc_id][last_index].signal == sig)&&
291 (signal_record[proc_id][last_index].pid == pid))
292 signal_index[proc_id] = last_index;
293 signal_record[proc_id][signal_index[proc_id]].pid = pid;
294 gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
295 eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
296 signal_record[proc_id][signal_index[proc_id]].addr = eip;
297 signal_record[proc_id][signal_index[proc_id]++].signal = sig;
298#endif
299 if(proc_id == -1){
300 sleeping_process_signal(pid, sig);
301 continue;
302 }
303
304 task = cpu_tasks[proc_id].task;
305 tracing = is_tracing(task);
306 old_tracing = tracing;
307
308 /* Assume: no syscall, when coming from user */
309 if ( tracing )
310 do_sigtrap(task);
311
312 switch(sig){
313 case SIGUSR1:
314 sig = 0;
315 op = do_proc_op(task, proc_id);
316 switch(op){
317 /*
318 * This is called when entering user mode; after
319 * this, we start intercepting syscalls.
320 *
321 * In fact, a process is started in kernel mode,
322 * so with is_tracing() == 0 (and that is reset
323 * when executing syscalls, since UML kernel has
324 * the right to do syscalls);
325 */
326 case OP_TRACE_ON:
327 arch_leave_kernel(task, pid);
328 tracing = 1;
329 break;
330 case OP_REBOOT:
331 case OP_HALT:
332 unmap_physmem();
333 kmalloc_ok = 0;
334 os_kill_ptraced_process(pid, 0);
335 /* Now let's reap remaining zombies */
336 errno = 0;
337 do {
338 waitpid(-1, &status,
339 WUNTRACED);
340 } while (errno != ECHILD);
341 return(op == OP_REBOOT);
342 case OP_NONE:
343 printf("Detaching pid %d\n", pid);
344 detach(pid, SIGSTOP);
345 continue;
346 default:
347 break;
348 }
349 /* OP_EXEC switches host processes on us,
350 * we want to continue the new one.
351 */
352 pid = cpu_tasks[proc_id].pid;
353 break;
354 case (SIGTRAP + 0x80):
355 if(!tracing && (debugger_pid != -1)){
356 child_signal(pid, status & 0x7fff);
357 continue;
358 }
359 tracing = 0;
360 /* local_using_sysemu has been already set
361 * below, since if we are here, is_tracing() on
362 * the traced task was 1, i.e. the process had
363 * already run through one iteration of the
364 * loop which executed a OP_TRACE_ON request.*/
365 do_syscall(task, pid, local_using_sysemu);
366 sig = SIGUSR2;
367 break;
368 case SIGTRAP:
369 if(!tracing && (debugger_pid != -1)){
370 child_signal(pid, status);
371 continue;
372 }
373 tracing = 0;
374 break;
375 case SIGPROF:
376 if(tracing) sig = 0;
377 break;
378 case SIGCHLD:
379 case SIGHUP:
380 sig = 0;
381 break;
382 case SIGSEGV:
383 case SIGIO:
384 case SIGALRM:
385 case SIGVTALRM:
386 case SIGFPE:
387 case SIGBUS:
388 case SIGILL:
389 case SIGWINCH:
390
391 default:
392 tracing = 0;
393 break;
394 }
395 set_tracing(task, tracing);
396
397 if(!tracing && old_tracing)
398 arch_enter_kernel(task, pid);
399
400 if(!tracing && (debugger_pid != -1) && (sig != 0) &&
401 (sig != SIGALRM) && (sig != SIGVTALRM) &&
402 (sig != SIGSEGV) && (sig != SIGTRAP) &&
403 (sig != SIGUSR2) && (sig != SIGIO) &&
404 (sig != SIGFPE)){
405 child_signal(pid, status);
406 continue;
407 }
408
409 local_using_sysemu = get_using_sysemu();
410
411 if(tracing)
412 cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
413 singlestepping(task));
414 else if((debugger_pid != -1) && strace)
415 cont_type = PTRACE_SYSCALL;
416 else
417 cont_type = PTRACE_CONT;
418
419 if(ptrace(cont_type, pid, 0, sig) != 0){
420 tracer_panic("ptrace failed to continue "
421 "process - errno = %d\n",
422 errno);
423 }
424 }
425 }
426 return(0);
427}
428
429static int __init uml_debug_setup(char *line, int *add)
430{
431 char *next;
432
433 debug = 1;
434 *add = 0;
435 if(*line != '=') return(0);
436 line++;
437
438 while(line != NULL){
439 next = strchr(line, ',');
440 if(next) *next++ = '\0';
441
442 if(!strcmp(line, "go")) debug_stop = 0;
443 else if(!strcmp(line, "parent")) debug_parent = 1;
444 else printf("Unknown debug option : '%s'\n", line);
445
446 line = next;
447 }
448 return(0);
449}
450
451__uml_setup("debug", uml_debug_setup,
452"debug\n"
453" Starts up the kernel under the control of gdb. See the \n"
454" kernel debugging tutorial and the debugging session pages\n"
455" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
456);
457
458static int __init uml_debugtrace_setup(char *line, int *add)
459{
460 debug_trace = 1;
461 return 0;
462}
463__uml_setup("debugtrace", uml_debugtrace_setup,
464"debugtrace\n"
465" Causes the tracing thread to pause until it is attached by a\n"
466" debugger and continued. This is mostly for debugging crashes\n"
467" early during boot, and should be pretty much obsoleted by\n"
468" the debug switch.\n\n"
469);
470
471/*
472 * Overrides for Emacs so that we follow Linus's tabbing style.
473 * Emacs will notice this stuff at the end of the file and automatically
474 * adjust the settings for this buffer only. This must remain at the end
475 * of the file.
476 * ---------------------------------------------------------------------------
477 * Local variables:
478 * c-file-style: "linux"
479 * End:
480 */
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
new file mode 100644
index 000000000000..92a3820ca543
--- /dev/null
+++ b/arch/um/kernel/tt/trap_user.c
@@ -0,0 +1,60 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <errno.h>
8#include <signal.h>
9#include "sysdep/ptrace.h"
10#include "signal_user.h"
11#include "user_util.h"
12#include "kern_util.h"
13#include "task.h"
14#include "tt.h"
15
16void sig_handler_common_tt(int sig, void *sc_ptr)
17{
18 struct sigcontext *sc = sc_ptr;
19 struct tt_regs save_regs, *r;
20 struct signal_info *info;
21 int save_errno = errno, is_user;
22
23 /* This is done because to allow SIGSEGV to be delivered inside a SEGV
24 * handler. This can happen in copy_user, and if SEGV is disabled,
25 * the process will die.
26 */
27 if(sig == SIGSEGV)
28 change_sig(SIGSEGV, 1);
29
30 r = &TASK_REGS(get_current())->tt;
31 save_regs = *r;
32 is_user = user_context(SC_SP(sc));
33 r->sc = sc;
34 if(sig != SIGUSR2)
35 r->syscall = -1;
36
37 info = &sig_info[sig];
38 if(!info->is_irq) unblock_signals();
39
40 (*info->handler)(sig, (union uml_pt_regs *) r);
41
42 if(is_user){
43 interrupt_end();
44 block_signals();
45 set_user_mode(NULL);
46 }
47 *r = save_regs;
48 errno = save_errno;
49}
50
51/*
52 * Overrides for Emacs so that we follow Linus's tabbing style.
53 * Emacs will notice this stuff at the end of the file and automatically
54 * adjust the settings for this buffer only. This must remain at the end
55 * of the file.
56 * ---------------------------------------------------------------------------
57 * Local variables:
58 * c-file-style: "linux"
59 * End:
60 */
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
new file mode 100644
index 000000000000..a72aa632972f
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess.c
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "asm/uaccess.h"
8
9int copy_from_user_tt(void *to, const void __user *from, int n)
10{
11 if(!access_ok_tt(VERIFY_READ, from, n))
12 return(n);
13
14 return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
15 &current->thread.fault_catcher));
16}
17
18int copy_to_user_tt(void __user *to, const void *from, int n)
19{
20 if(!access_ok_tt(VERIFY_WRITE, to, n))
21 return(n);
22
23 return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
24 &current->thread.fault_catcher));
25}
26
27int strncpy_from_user_tt(char *dst, const char __user *src, int count)
28{
29 int n;
30
31 if(!access_ok_tt(VERIFY_READ, src, 1))
32 return(-EFAULT);
33
34 n = __do_strncpy_from_user(dst, src, count,
35 &current->thread.fault_addr,
36 &current->thread.fault_catcher);
37 if(n < 0) return(-EFAULT);
38 return(n);
39}
40
41int __clear_user_tt(void __user *mem, int len)
42{
43 return(__do_clear_user(mem, len,
44 &current->thread.fault_addr,
45 &current->thread.fault_catcher));
46}
47
48int clear_user_tt(void __user *mem, int len)
49{
50 if(!access_ok_tt(VERIFY_WRITE, mem, len))
51 return(len);
52
53 return(__do_clear_user(mem, len, &current->thread.fault_addr,
54 &current->thread.fault_catcher));
55}
56
57int strnlen_user_tt(const void __user *str, int len)
58{
59 return(__do_strnlen_user(str, len,
60 &current->thread.fault_addr,
61 &current->thread.fault_catcher));
62}
63
64/*
65 * Overrides for Emacs so that we follow Linus's tabbing style.
66 * Emacs will notice this stuff at the end of the file and automatically
67 * adjust the settings for this buffer only. This must remain at the end
68 * of the file.
69 * ---------------------------------------------------------------------------
70 * Local variables:
71 * c-file-style: "linux"
72 * End:
73 */
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
new file mode 100644
index 000000000000..f01475512ecb
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
3 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
4 * Licensed under the GPL
5 */
6
7#include <setjmp.h>
8#include <string.h>
9#include "user_util.h"
10#include "uml_uaccess.h"
11#include "task.h"
12#include "kern_util.h"
13
14int __do_copy_from_user(void *to, const void *from, int n,
15 void **fault_addr, void **fault_catcher)
16{
17 struct tt_regs save = TASK_REGS(get_current())->tt;
18 unsigned long fault;
19 int faulted;
20
21 fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
22 __do_copy, &faulted);
23 TASK_REGS(get_current())->tt = save;
24
25 if(!faulted) return(0);
26 else return(n - (fault - (unsigned long) from));
27}
28
29static void __do_strncpy(void *dst, const void *src, int count)
30{
31 strncpy(dst, src, count);
32}
33
34int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
35 void **fault_addr, void **fault_catcher)
36{
37 struct tt_regs save = TASK_REGS(get_current())->tt;
38 unsigned long fault;
39 int faulted;
40
41 fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
42 __do_strncpy, &faulted);
43 TASK_REGS(get_current())->tt = save;
44
45 if(!faulted) return(strlen(dst));
46 else return(-1);
47}
48
49static void __do_clear(void *to, const void *from, int n)
50{
51 memset(to, 0, n);
52}
53
54int __do_clear_user(void *mem, unsigned long len,
55 void **fault_addr, void **fault_catcher)
56{
57 struct tt_regs save = TASK_REGS(get_current())->tt;
58 unsigned long fault;
59 int faulted;
60
61 fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
62 __do_clear, &faulted);
63 TASK_REGS(get_current())->tt = save;
64
65 if(!faulted) return(0);
66 else return(len - (fault - (unsigned long) mem));
67}
68
69int __do_strnlen_user(const char *str, unsigned long n,
70 void **fault_addr, void **fault_catcher)
71{
72 struct tt_regs save = TASK_REGS(get_current())->tt;
73 int ret;
74 unsigned long *faddrp = (unsigned long *)fault_addr;
75 sigjmp_buf jbuf;
76
77 *fault_catcher = &jbuf;
78 if(sigsetjmp(jbuf, 1) == 0)
79 ret = strlen(str) + 1;
80 else ret = *faddrp - (unsigned long) str;
81
82 *fault_addr = NULL;
83 *fault_catcher = NULL;
84
85 TASK_REGS(get_current())->tt = save;
86 return ret;
87}
88
89/*
90 * Overrides for Emacs so that we follow Linus's tabbing style.
91 * Emacs will notice this stuff at the end of the file and automatically
92 * adjust the settings for this buffer only. This must remain at the end
93 * of the file.
94 * ---------------------------------------------------------------------------
95 * Local variables:
96 * c-file-style: "linux"
97 * End:
98 */
diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c
new file mode 100644
index 000000000000..3f7aecdbe532
--- /dev/null
+++ b/arch/um/kernel/tt/unmap.c
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <sys/mman.h>
7
8int switcheroo(int fd, int prot, void *from, void *to, int size)
9{
10 if(munmap(to, size) < 0){
11 return(-1);
12 }
13 if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
14 return(-1);
15 }
16 if(munmap(from, size) < 0){
17 return(-1);
18 }
19 return(0);
20}
21
22/*
23 * Overrides for Emacs so that we follow Linus's tabbing style.
24 * Emacs will notice this stuff at the end of the file and automatically
25 * adjust the settings for this buffer only. This must remain at the end
26 * of the file.
27 * ---------------------------------------------------------------------------
28 * Local variables:
29 * c-file-style: "linux"
30 * End:
31 */