Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | |
3 | * Licensed under the GPL | |
4 | */ | |
5 | ||
6 | #include <stdio.h> | |
54f9a398 | 7 | #include <stddef.h> |
1da177e4 LT |
8 | #include <errno.h> |
9 | #include <unistd.h> | |
1da177e4 LT |
10 | #include "ptrace_user.h" |
11 | /* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */ | |
12 | #include <asm/user.h> | |
13 | #include "kern_util.h" | |
14 | #include "sysdep/thread.h" | |
15 | #include "user.h" | |
16 | #include "os.h" | |
972410b0 | 17 | #include "uml-config.h" |
91b165c0 | 18 | #include "user_util.h" |
1da177e4 LT |
19 | |
20 | int ptrace_getregs(long pid, unsigned long *regs_out) | |
21 | { | |
22 | if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) | |
23 | return -errno; | |
24 | return 0; | |
25 | } | |
26 | ||
27 | int ptrace_setregs(long pid, unsigned long *regs) | |
28 | { | |
29 | if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) | |
30 | return -errno; | |
31 | return 0; | |
32 | } | |
33 | ||
34 | int ptrace_getfpregs(long pid, unsigned long *regs) | |
35 | { | |
36 | if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0) | |
37 | return -errno; | |
38 | return 0; | |
39 | } | |
40 | ||
41 | int ptrace_setfpregs(long pid, unsigned long *regs) | |
42 | { | |
43 | if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0) | |
44 | return -errno; | |
45 | return 0; | |
46 | } | |
47 | ||
972410b0 | 48 | /* All the below stuff is of interest for TT mode only */ |
1da177e4 LT |
49 | static void write_debugregs(int pid, unsigned long *regs) |
50 | { | |
51 | struct user *dummy; | |
52 | int nregs, i; | |
53 | ||
54 | dummy = NULL; | |
91b165c0 | 55 | nregs = ARRAY_SIZE(dummy->u_debugreg); |
1da177e4 LT |
56 | for(i = 0; i < nregs; i++){ |
57 | if((i == 4) || (i == 5)) continue; | |
58 | if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], | |
59 | regs[i]) < 0) | |
60 | printk("write_debugregs - ptrace failed on " | |
802e3077 | 61 | "register %d, value = 0x%lx, errno = %d\n", i, |
1da177e4 LT |
62 | regs[i], errno); |
63 | } | |
64 | } | |
65 | ||
66 | static void read_debugregs(int pid, unsigned long *regs) | |
67 | { | |
68 | struct user *dummy; | |
69 | int nregs, i; | |
70 | ||
71 | dummy = NULL; | |
91b165c0 | 72 | nregs = ARRAY_SIZE(dummy->u_debugreg); |
1da177e4 LT |
73 | for(i = 0; i < nregs; i++){ |
74 | regs[i] = ptrace(PTRACE_PEEKUSR, pid, | |
75 | &dummy->u_debugreg[i], 0); | |
76 | } | |
77 | } | |
78 | ||
79 | /* Accessed only by the tracing thread */ | |
80 | static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; | |
1da177e4 LT |
81 | |
82 | void arch_enter_kernel(void *task, int pid) | |
83 | { | |
84 | read_debugregs(pid, TASK_DEBUGREGS(task)); | |
85 | write_debugregs(pid, kernel_debugregs); | |
86 | } | |
87 | ||
88 | void arch_leave_kernel(void *task, int pid) | |
89 | { | |
90 | read_debugregs(pid, kernel_debugregs); | |
91 | write_debugregs(pid, TASK_DEBUGREGS(task)); | |
92 | } | |
93 | ||
972410b0 PBG |
94 | #ifdef UML_CONFIG_PT_PROXY |
95 | /* Accessed only by the tracing thread */ | |
96 | static int debugregs_seq; | |
97 | ||
98 | /* Only called by the ptrace proxy */ | |
1da177e4 LT |
99 | void ptrace_pokeuser(unsigned long addr, unsigned long data) |
100 | { | |
101 | if((addr < offsetof(struct user, u_debugreg[0])) || | |
102 | (addr > offsetof(struct user, u_debugreg[7]))) | |
103 | return; | |
104 | addr -= offsetof(struct user, u_debugreg[0]); | |
105 | addr = addr >> 2; | |
106 | if(kernel_debugregs[addr] == data) return; | |
107 | ||
108 | kernel_debugregs[addr] = data; | |
109 | debugregs_seq++; | |
110 | } | |
111 | ||
112 | static void update_debugregs_cb(void *arg) | |
113 | { | |
114 | int pid = *((int *) arg); | |
115 | ||
116 | write_debugregs(pid, kernel_debugregs); | |
117 | } | |
118 | ||
972410b0 | 119 | /* Optimized out in its header when not defined */ |
1da177e4 LT |
120 | void update_debugregs(int seq) |
121 | { | |
122 | int me; | |
123 | ||
124 | if(seq == debugregs_seq) return; | |
125 | ||
126 | me = os_getpid(); | |
127 | initial_thread_cb(update_debugregs_cb, &me); | |
128 | } | |
972410b0 | 129 | #endif |
1da177e4 LT |
130 | |
131 | /* | |
132 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
133 | * Emacs will notice this stuff at the end of the file and automatically | |
134 | * adjust the settings for this buffer only. This must remain at the end | |
135 | * of the file. | |
136 | * --------------------------------------------------------------------------- | |
137 | * Local variables: | |
138 | * c-file-style: "linux" | |
139 | * End: | |
140 | */ |