diff options
Diffstat (limited to 'arch/um/kernel/tt')
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 | |||
6 | extra-y := unmap_fin.o | ||
7 | clean-files := unmap_tmp.o | ||
8 | |||
9 | obj-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 | |||
13 | obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ | ||
14 | |||
15 | USER_OBJS := gdb.o time.o tracer.o | ||
16 | |||
17 | include arch/um/scripts/Makefile.rules | ||
18 | |||
19 | UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) | ||
20 | UNMAP_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 | |||
23 | static 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 | |||
31 | void 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 | |||
68 | void 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 | |||
19 | void 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 | |||
24 | extern int debugger_pid; | ||
25 | extern int debugger_fd; | ||
26 | extern int debugger_parent; | ||
27 | |||
28 | int detach(int pid, int sig) | ||
29 | { | ||
30 | return(ptrace(PTRACE_DETACH, pid, 0, sig)); | ||
31 | } | ||
32 | |||
33 | int 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 | |||
42 | int cont(int pid) | ||
43 | { | ||
44 | return(ptrace(PTRACE_CONT, pid, 0, 0)); | ||
45 | } | ||
46 | |||
47 | #ifdef UML_CONFIG_PT_PROXY | ||
48 | |||
49 | int debugger_signal(int status, pid_t pid) | ||
50 | { | ||
51 | return(debugger_proxy(status, pid)); | ||
52 | } | ||
53 | |||
54 | void child_signal(pid_t pid, int status) | ||
55 | { | ||
56 | child_proxy(pid, status); | ||
57 | } | ||
58 | |||
59 | static void gdb_announce(char *dev_name, int dev) | ||
60 | { | ||
61 | printf("gdb assigned device '%s'\n", dev_name); | ||
62 | } | ||
63 | |||
64 | static 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 */ | ||
73 | static void *xterm_data; | ||
74 | static int xterm_fd; | ||
75 | |||
76 | extern void *xterm_init(char *, int, struct chan_opts *); | ||
77 | extern int xterm_open(int, int, int, void *, char **); | ||
78 | extern void xterm_close(int, void *); | ||
79 | |||
80 | int 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 | |||
90 | static 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 | |||
105 | static void exit_debugger(void) | ||
106 | { | ||
107 | initial_thread_cb(exit_debugger_cb, NULL); | ||
108 | } | ||
109 | |||
110 | __uml_exitcall(exit_debugger); | ||
111 | |||
112 | struct gdb_data { | ||
113 | char *str; | ||
114 | int err; | ||
115 | }; | ||
116 | |||
117 | static 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 | |||
141 | int 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 | |||
151 | void remove_gdb_cb(void *unused) | ||
152 | { | ||
153 | exit_debugger_cb(NULL); | ||
154 | } | ||
155 | |||
156 | int gdb_remove(char *unused) | ||
157 | { | ||
158 | initial_thread_cb(remove_gdb_cb, NULL); | ||
159 | return(0); | ||
160 | } | ||
161 | |||
162 | void 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 | |||
172 | int 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 | |||
186 | int 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 */ | ||
201 | static 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 | |||
212 | static 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 | |||
227 | int debugger_signal(int status, pid_t pid){ return(0); } | ||
228 | void child_signal(pid_t pid, int status){ } | ||
229 | int 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 | |||
236 | void signal_usr1(int sig) | ||
237 | { | ||
238 | printf("debug requested when CONFIG_PT_PROXY is off\n"); | ||
239 | } | ||
240 | |||
241 | int 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 | |||
248 | int config_gdb(char *str) | ||
249 | { | ||
250 | return(-1); | ||
251 | } | ||
252 | |||
253 | int remove_gdb(void) | ||
254 | { | ||
255 | return(-1); | ||
256 | } | ||
257 | |||
258 | int init_parent_proxy(int pid) | ||
259 | { | ||
260 | return(-1); | ||
261 | } | ||
262 | |||
263 | void 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 | |||
12 | extern int gdb_config(char *str); | ||
13 | extern int gdb_remove(char *unused); | ||
14 | |||
15 | static struct mc_device gdb_mc = { | ||
16 | .name = "gdb", | ||
17 | .config = gdb_config, | ||
18 | .remove = gdb_remove, | ||
19 | }; | ||
20 | |||
21 | int 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 | |||
10 | extern int debugger_proxy(int status, pid_t pid); | ||
11 | extern void child_proxy(pid_t pid, int status); | ||
12 | extern void init_proxy (pid_t pid, int waiting, int status); | ||
13 | extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); | ||
14 | extern void fake_child_exit(void); | ||
15 | extern int gdb_config(char *str); | ||
16 | extern 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 | |||
9 | struct 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 | |||
11 | enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; | ||
12 | |||
13 | extern int tracing_pid; | ||
14 | |||
15 | extern int tracer(int (*init_proc)(void *), void *sp); | ||
16 | extern void user_time_init_tt(void); | ||
17 | extern void sig_handler_common_tt(int sig, void *sc); | ||
18 | extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); | ||
19 | extern void reboot_tt(void); | ||
20 | extern void halt_tt(void); | ||
21 | extern int is_tracer_winch(int pid, int fd, void *data); | ||
22 | extern 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 | |||
14 | extern void *switch_to_tt(void *prev, void *next); | ||
15 | extern void flush_thread_tt(void); | ||
16 | extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, | ||
17 | unsigned long esp); | ||
18 | extern 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); | ||
21 | extern void release_thread_tt(struct task_struct *task); | ||
22 | extern void exit_thread_tt(void); | ||
23 | extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); | ||
24 | extern void init_idle_tt(void); | ||
25 | extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); | ||
26 | extern void flush_tlb_kernel_vm_tt(void); | ||
27 | extern void __flush_tlb_one_tt(unsigned long addr); | ||
28 | extern void flush_tlb_range_tt(struct vm_area_struct *vma, | ||
29 | unsigned long start, unsigned long end); | ||
30 | extern void flush_tlb_mm_tt(struct mm_struct *mm); | ||
31 | extern void force_flush_all_tt(void); | ||
32 | extern long execute_syscall_tt(void *r); | ||
33 | extern void before_mem_tt(unsigned long brk_start); | ||
34 | extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, | ||
35 | unsigned long *task_size_out); | ||
36 | extern int start_uml_tt(void); | ||
37 | extern int external_pid_tt(struct task_struct *task); | ||
38 | extern 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 | |||
11 | extern int gdb_pid; | ||
12 | extern int debug; | ||
13 | extern int debug_stop; | ||
14 | extern int debug_trace; | ||
15 | |||
16 | extern int honeypot; | ||
17 | |||
18 | extern int fork_tramp(void *sig_stack); | ||
19 | extern int do_proc_op(void *t, int proc_id); | ||
20 | extern int tracer(int (*init_proc)(void *), void *sp); | ||
21 | extern void attach_process(int pid); | ||
22 | extern void tracer_panic(char *format, ...); | ||
23 | extern void set_init_pid(int pid); | ||
24 | extern int set_user_mode(void *task); | ||
25 | extern void set_tracing(void *t, int tracing); | ||
26 | extern int is_tracing(void *task); | ||
27 | extern void syscall_handler(int sig, union uml_pt_regs *regs); | ||
28 | extern void exit_kernel(int pid, void *task); | ||
29 | extern void do_syscall(void *task, int pid, int local_using_sysemu); | ||
30 | extern void do_sigtrap(void *task); | ||
31 | extern int is_valid_pid(int pid); | ||
32 | extern void remap_data(void *segment_start, void *segment_end, int w); | ||
33 | extern 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 | |||
19 | extern unsigned long end_vm; | ||
20 | extern 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 | |||
36 | static 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 | |||
42 | extern unsigned long get_fault_addr(void); | ||
43 | |||
44 | extern int __do_copy_from_user(void *to, const void *from, int n, | ||
45 | void **fault_addr, void **fault_catcher); | ||
46 | extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, | ||
47 | void **fault_addr, void **fault_catcher); | ||
48 | extern int __do_clear_user(void *mem, size_t len, void **fault_addr, | ||
49 | void **fault_catcher); | ||
50 | extern int __do_strnlen_user(const char *str, unsigned long n, | ||
51 | void **fault_addr, void **fault_catcher); | ||
52 | |||
53 | extern int copy_from_user_tt(void *to, const void *from, int n); | ||
54 | extern int copy_to_user_tt(void *to, const void *from, int n); | ||
55 | extern int strncpy_from_user_tt(char *dst, const char *src, int count); | ||
56 | extern int __clear_user_tt(void *mem, int len); | ||
57 | extern int clear_user_tt(void *mem, int len); | ||
58 | extern 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 | |||
10 | EXPORT_SYMBOL(__do_copy_from_user); | ||
11 | EXPORT_SYMBOL(__do_copy_to_user); | ||
12 | EXPORT_SYMBOL(__do_strncpy_from_user); | ||
13 | EXPORT_SYMBOL(__do_strnlen_user); | ||
14 | EXPORT_SYMBOL(__do_clear_user); | ||
15 | |||
16 | EXPORT_SYMBOL(tracing_pid); | ||
17 | EXPORT_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 | |||
16 | void 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 | |||
33 | unsigned 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 | |||
16 | void 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 | |||
29 | void *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 | |||
100 | void 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 | |||
108 | void 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 | |||
114 | void 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 | |||
125 | void schedule_tail(task_t *prev); | ||
126 | |||
127 | static 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(¤t->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(¤t->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, ¤t->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 | |||
167 | static 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 | |||
200 | void finish_fork_handler(int sig) | ||
201 | { | ||
202 | UPT_SC(¤t->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 | |||
224 | int 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 | |||
235 | int 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(¤t->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 | |||
294 | void reboot_tt(void) | ||
295 | { | ||
296 | current->thread.request.op = OP_REBOOT; | ||
297 | os_usr1_process(os_getpid()); | ||
298 | change_sig(SIGUSR1, 1); | ||
299 | } | ||
300 | |||
301 | void halt_tt(void) | ||
302 | { | ||
303 | current->thread.request.op = OP_HALT; | ||
304 | os_usr1_process(os_getpid()); | ||
305 | change_sig(SIGUSR1, 1); | ||
306 | } | ||
307 | |||
308 | void 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 | |||
322 | void 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 | |||
338 | int 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 | |||
374 | void init_idle_tt(void) | ||
375 | { | ||
376 | default_idle(); | ||
377 | } | ||
378 | |||
379 | extern void start_kernel(void); | ||
380 | |||
381 | static 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 | |||
398 | void set_tracing(void *task, int tracing) | ||
399 | { | ||
400 | ((struct task_struct *) task)->thread.mode.tt.tracing = tracing; | ||
401 | } | ||
402 | |||
403 | int is_tracing(void *t) | ||
404 | { | ||
405 | return (((struct task_struct *) t)->thread.mode.tt.tracing); | ||
406 | } | ||
407 | |||
408 | int 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 | |||
420 | void 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 | |||
431 | int 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 | |||
442 | int external_pid_tt(struct task_struct *task) | ||
443 | { | ||
444 | return(task->thread.mode.tt.extern_pid); | ||
445 | } | ||
446 | |||
447 | int thread_pid_tt(struct task_struct *task) | ||
448 | { | ||
449 | return(task->thread.mode.tt.extern_pid); | ||
450 | } | ||
451 | |||
452 | int 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 | |||
6 | obj-y = proxy.o ptrace.o sysdep.o wait.o | ||
7 | |||
8 | USER_OBJS := $(obj-y) | ||
9 | |||
10 | include 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 | /********************************************************************** | ||
2 | proxy.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | |||
7 | Jeff 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 | |||
34 | static 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 | |||
73 | int 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 */ | ||
128 | static debugger_state parent; | ||
129 | static int parent_syscall(debugger_state *debugger, int pid); | ||
130 | |||
131 | int 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 | |||
144 | int 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 | |||
151 | static 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 | |||
170 | int 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 | |||
177 | void 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 */ | ||
185 | static debugger_state debugger; | ||
186 | static debugee_state debugee; | ||
187 | |||
188 | void 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 | |||
207 | int 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 | |||
245 | void 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 | |||
264 | void 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 | |||
275 | void 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 | |||
300 | char gdb_init_string[] = | ||
301 | "att 1 \n\ | ||
302 | b panic \n\ | ||
303 | b stop \n\ | ||
304 | handle SIGWINCH nostop noprint pass \n\ | ||
305 | "; | ||
306 | |||
307 | int 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 | /********************************************************************** | ||
2 | ptproxy.h | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | **********************************************************************/ | ||
7 | |||
8 | #ifndef __PTPROXY_H | ||
9 | #define __PTPROXY_H | ||
10 | |||
11 | #include <sys/types.h> | ||
12 | |||
13 | typedef struct debugger debugger_state; | ||
14 | typedef struct debugee debugee_state; | ||
15 | |||
16 | struct 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 | |||
29 | struct 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 | |||
43 | extern int debugger_syscall(debugger_state *debugger, pid_t pid); | ||
44 | extern int debugger_normal_return (debugger_state *debugger, pid_t unused); | ||
45 | |||
46 | extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, | ||
47 | int *strace_out); | ||
48 | extern 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 | /********************************************************************** | ||
2 | ptrace.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | |||
7 | Jeff 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 | |||
24 | long 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 | /********************************************************************** | ||
2 | sysdep.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms 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 | |||
19 | int 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 | |||
30 | void 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 | |||
42 | void syscall_set_result(pid_t pid, long result) | ||
43 | { | ||
44 | ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result); | ||
45 | } | ||
46 | |||
47 | void syscall_continue(pid_t pid) | ||
48 | { | ||
49 | ptrace(PTRACE_SYSCALL, pid, 0, 0); | ||
50 | } | ||
51 | |||
52 | int 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 | /********************************************************************** | ||
2 | sysdep.h | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. | ||
5 | Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||
6 | See the file COPYING for licensing terms and conditions. | ||
7 | **********************************************************************/ | ||
8 | |||
9 | extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, | ||
10 | long *arg4, long *arg5); | ||
11 | extern void syscall_cancel (pid_t pid, long result); | ||
12 | extern void syscall_set_result (pid_t pid, long result); | ||
13 | extern void syscall_continue (pid_t pid); | ||
14 | extern 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 | /********************************************************************** | ||
2 | wait.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms 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 | |||
21 | int 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 | |||
49 | int parent_wait_return(struct debugger *debugger, pid_t unused) | ||
50 | { | ||
51 | return(debugger_normal_return(debugger, -1)); | ||
52 | } | ||
53 | |||
54 | int 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 | /********************************************************************** | ||
2 | wait.h | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | **********************************************************************/ | ||
7 | |||
8 | #ifndef __PTPROXY_WAIT_H | ||
9 | #define __PTPROXY_WAIT_H | ||
10 | |||
11 | extern int proxy_wait_return(struct debugger *debugger, pid_t unused); | ||
12 | extern int real_wait_return(struct debugger *debugger); | ||
13 | extern 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 | |||
17 | extern syscall_handler_t *sys_call_table[]; | ||
18 | |||
19 | long 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(®s->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 | |||
20 | void 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 | |||
52 | void do_sigtrap(void *task) | ||
53 | { | ||
54 | UPT_SYSCALL_NR(TASK_REGS(task)) = -1; | ||
55 | } | ||
56 | |||
57 | void 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 | |||
12 | void 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 | |||
20 | static 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 | |||
50 | static 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 | |||
61 | atomic_t vmchange_seq = ATOMIC_INIT(1); | ||
62 | |||
63 | void 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 | |||
69 | static 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 | |||
82 | void 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 | |||
105 | void flush_tlb_kernel_vm_tt(void) | ||
106 | { | ||
107 | flush_tlb_kernel_range(start_vm, end_vm); | ||
108 | } | ||
109 | |||
110 | void __flush_tlb_one_tt(unsigned long addr) | ||
111 | { | ||
112 | flush_tlb_kernel_range(addr, addr + PAGE_SIZE); | ||
113 | } | ||
114 | |||
115 | void 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 | |||
130 | void 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 | |||
145 | void 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 | |||
32 | static int tracer_winch[2]; | ||
33 | |||
34 | int 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 | |||
43 | static 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 | |||
55 | static 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 | |||
67 | void 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 | |||
79 | void 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 | |||
90 | static 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 */ | ||
99 | int debug = 0; | ||
100 | int debug_stop = 1; | ||
101 | int debug_parent = 0; | ||
102 | int honeypot = 0; | ||
103 | |||
104 | static 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 | |||
124 | static 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 */ | ||
161 | int debugger_pid = -1; | ||
162 | int debugger_parent = -1; | ||
163 | int debugger_fd = -1; | ||
164 | int gdb_pid = -1; | ||
165 | |||
166 | struct { | ||
167 | int pid; | ||
168 | int signal; | ||
169 | unsigned long addr; | ||
170 | struct timeval time; | ||
171 | } signal_record[1024][32]; | ||
172 | |||
173 | int signal_index[32]; | ||
174 | int nsignals = 0; | ||
175 | int debug_trace = 0; | ||
176 | extern int io_nsignals, io_count, intr_count; | ||
177 | |||
178 | extern void signal_usr1(int sig); | ||
179 | |||
180 | int tracing_pid = -1; | ||
181 | |||
182 | int 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 | |||
429 | static 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 | |||
458 | static 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 | |||
16 | void 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 | |||
9 | int 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, ¤t->thread.fault_addr, | ||
15 | ¤t->thread.fault_catcher)); | ||
16 | } | ||
17 | |||
18 | int 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, ¤t->thread.fault_addr, | ||
24 | ¤t->thread.fault_catcher)); | ||
25 | } | ||
26 | |||
27 | int 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 | ¤t->thread.fault_addr, | ||
36 | ¤t->thread.fault_catcher); | ||
37 | if(n < 0) return(-EFAULT); | ||
38 | return(n); | ||
39 | } | ||
40 | |||
41 | int __clear_user_tt(void __user *mem, int len) | ||
42 | { | ||
43 | return(__do_clear_user(mem, len, | ||
44 | ¤t->thread.fault_addr, | ||
45 | ¤t->thread.fault_catcher)); | ||
46 | } | ||
47 | |||
48 | int 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, ¤t->thread.fault_addr, | ||
54 | ¤t->thread.fault_catcher)); | ||
55 | } | ||
56 | |||
57 | int strnlen_user_tt(const void __user *str, int len) | ||
58 | { | ||
59 | return(__do_strnlen_user(str, len, | ||
60 | ¤t->thread.fault_addr, | ||
61 | ¤t->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 | |||
14 | int __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 | |||
29 | static void __do_strncpy(void *dst, const void *src, int count) | ||
30 | { | ||
31 | strncpy(dst, src, count); | ||
32 | } | ||
33 | |||
34 | int __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 | |||
49 | static void __do_clear(void *to, const void *from, int n) | ||
50 | { | ||
51 | memset(to, 0, n); | ||
52 | } | ||
53 | |||
54 | int __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 | |||
69 | int __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 | |||
8 | int 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 | */ | ||