diff options
author | Roland McGrath <roland@redhat.com> | 2008-01-30 07:30:58 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:58 -0500 |
commit | ce90f340855d7a9b3bec24f0fe49a76904242387 (patch) | |
tree | deba4e16ad9f65e7cc80e84f3c2fc0694a4c9f73 /arch | |
parent | 9e714bed644cb463489b9250774a4b0fb352cabc (diff) |
x86: x86-64 ptrace get/putreg current task
This generalizes the getreg and putreg functions so they can be used on the
current task, as well as on a task stopped in TASK_TRACED and switched off.
This lays the groundwork to share this code for all kinds of user-mode
machine state access, not just ptrace.
Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/ptrace_64.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c index 2427548f2a01..5979dbe8e0a2 100644 --- a/arch/x86/kernel/ptrace_64.c +++ b/arch/x86/kernel/ptrace_64.c | |||
@@ -67,21 +67,29 @@ static int putreg(struct task_struct *child, | |||
67 | if (value && (value & 3) != 3) | 67 | if (value && (value & 3) != 3) |
68 | return -EIO; | 68 | return -EIO; |
69 | child->thread.fsindex = value & 0xffff; | 69 | child->thread.fsindex = value & 0xffff; |
70 | if (child == current) | ||
71 | loadsegment(fs, child->thread.fsindex); | ||
70 | return 0; | 72 | return 0; |
71 | case offsetof(struct user_regs_struct,gs): | 73 | case offsetof(struct user_regs_struct,gs): |
72 | if (value && (value & 3) != 3) | 74 | if (value && (value & 3) != 3) |
73 | return -EIO; | 75 | return -EIO; |
74 | child->thread.gsindex = value & 0xffff; | 76 | child->thread.gsindex = value & 0xffff; |
77 | if (child == current) | ||
78 | load_gs_index(child->thread.gsindex); | ||
75 | return 0; | 79 | return 0; |
76 | case offsetof(struct user_regs_struct,ds): | 80 | case offsetof(struct user_regs_struct,ds): |
77 | if (value && (value & 3) != 3) | 81 | if (value && (value & 3) != 3) |
78 | return -EIO; | 82 | return -EIO; |
79 | child->thread.ds = value & 0xffff; | 83 | child->thread.ds = value & 0xffff; |
84 | if (child == current) | ||
85 | loadsegment(ds, child->thread.ds); | ||
80 | return 0; | 86 | return 0; |
81 | case offsetof(struct user_regs_struct,es): | 87 | case offsetof(struct user_regs_struct,es): |
82 | if (value && (value & 3) != 3) | 88 | if (value && (value & 3) != 3) |
83 | return -EIO; | 89 | return -EIO; |
84 | child->thread.es = value & 0xffff; | 90 | child->thread.es = value & 0xffff; |
91 | if (child == current) | ||
92 | loadsegment(es, child->thread.es); | ||
85 | return 0; | 93 | return 0; |
86 | case offsetof(struct user_regs_struct,ss): | 94 | case offsetof(struct user_regs_struct,ss): |
87 | if ((value & 3) != 3) | 95 | if ((value & 3) != 3) |
@@ -135,14 +143,32 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno) | |||
135 | { | 143 | { |
136 | struct pt_regs *regs = task_pt_regs(child); | 144 | struct pt_regs *regs = task_pt_regs(child); |
137 | unsigned long val; | 145 | unsigned long val; |
146 | unsigned int seg; | ||
138 | switch (regno) { | 147 | switch (regno) { |
139 | case offsetof(struct user_regs_struct, fs): | 148 | case offsetof(struct user_regs_struct, fs): |
149 | if (child == current) { | ||
150 | /* Older gas can't assemble movq %?s,%r?? */ | ||
151 | asm("movl %%fs,%0" : "=r" (seg)); | ||
152 | return seg; | ||
153 | } | ||
140 | return child->thread.fsindex; | 154 | return child->thread.fsindex; |
141 | case offsetof(struct user_regs_struct, gs): | 155 | case offsetof(struct user_regs_struct, gs): |
156 | if (child == current) { | ||
157 | asm("movl %%gs,%0" : "=r" (seg)); | ||
158 | return seg; | ||
159 | } | ||
142 | return child->thread.gsindex; | 160 | return child->thread.gsindex; |
143 | case offsetof(struct user_regs_struct, ds): | 161 | case offsetof(struct user_regs_struct, ds): |
162 | if (child == current) { | ||
163 | asm("movl %%ds,%0" : "=r" (seg)); | ||
164 | return seg; | ||
165 | } | ||
144 | return child->thread.ds; | 166 | return child->thread.ds; |
145 | case offsetof(struct user_regs_struct, es): | 167 | case offsetof(struct user_regs_struct, es): |
168 | if (child == current) { | ||
169 | asm("movl %%es,%0" : "=r" (seg)); | ||
170 | return seg; | ||
171 | } | ||
146 | return child->thread.es; | 172 | return child->thread.es; |
147 | case offsetof(struct user_regs_struct, fs_base): | 173 | case offsetof(struct user_regs_struct, fs_base): |
148 | /* | 174 | /* |
@@ -152,7 +178,10 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno) | |||
152 | */ | 178 | */ |
153 | if (child->thread.fs != 0) | 179 | if (child->thread.fs != 0) |
154 | return child->thread.fs; | 180 | return child->thread.fs; |
155 | if (child->thread.fsindex != FS_TLS_SEL) | 181 | seg = child->thread.fsindex; |
182 | if (child == current) | ||
183 | asm("movl %%fs,%0" : "=r" (seg)); | ||
184 | if (seg != FS_TLS_SEL) | ||
156 | return 0; | 185 | return 0; |
157 | return get_desc_base(&child->thread.tls_array[FS_TLS]); | 186 | return get_desc_base(&child->thread.tls_array[FS_TLS]); |
158 | case offsetof(struct user_regs_struct, gs_base): | 187 | case offsetof(struct user_regs_struct, gs_base): |
@@ -161,7 +190,10 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno) | |||
161 | */ | 190 | */ |
162 | if (child->thread.gs != 0) | 191 | if (child->thread.gs != 0) |
163 | return child->thread.gs; | 192 | return child->thread.gs; |
164 | if (child->thread.gsindex != GS_TLS_SEL) | 193 | seg = child->thread.gsindex; |
194 | if (child == current) | ||
195 | asm("movl %%gs,%0" : "=r" (seg)); | ||
196 | if (seg != GS_TLS_SEL) | ||
165 | return 0; | 197 | return 0; |
166 | return get_desc_base(&child->thread.tls_array[GS_TLS]); | 198 | return get_desc_base(&child->thread.tls_array[GS_TLS]); |
167 | case offsetof(struct user_regs_struct, flags): | 199 | case offsetof(struct user_regs_struct, flags): |