blob: 99cb910c2ea33b3684510f0535ee917626c8ba8e [file] [log] [blame]
Alexandre Julliard578c1001999-11-14 21:23:21 +00001/*
2 * Server-side ptrace support
3 *
4 * Copyright (C) 1999 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard578c1001999-11-14 21:23:21 +000019 */
20
21#include "config.h"
22
23#include <assert.h>
24#include <errno.h>
25#include <stdio.h>
26#include <signal.h>
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010027#include <stdarg.h>
Alexandre Julliard42666ee1999-11-21 01:10:16 +000028#include <sys/types.h>
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000029#ifdef HAVE_SYS_PTRACE_H
30# include <sys/ptrace.h>
31#endif
Alexandre Julliard498742f2006-06-27 21:27:47 +020032#ifdef HAVE_SYS_PARAM_H
33# include <sys/param.h>
34#endif
Alexandre Julliard578c1001999-11-14 21:23:21 +000035#ifdef HAVE_SYS_WAIT_H
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000036# include <sys/wait.h>
Alexandre Julliard578c1001999-11-14 21:23:21 +000037#endif
38#include <unistd.h>
39
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010040#include "ntstatus.h"
41#define WIN32_NO_STATUS
42#include "winternl.h"
43
Alexandre Julliardcf27a7f2003-02-14 20:27:09 +000044#include "file.h"
Alexandre Julliard578c1001999-11-14 21:23:21 +000045#include "process.h"
46#include "thread.h"
47
Alexandre Julliardc2734982006-12-29 20:38:49 +010048#ifdef USE_PTRACE
49
Alexandre Julliard578c1001999-11-14 21:23:21 +000050#ifndef PTRACE_CONT
51#define PTRACE_CONT PT_CONTINUE
52#endif
Ove Kaavenada73832001-04-27 18:39:47 +000053#ifndef PTRACE_SINGLESTEP
54#define PTRACE_SINGLESTEP PT_STEP
55#endif
Alexandre Julliard578c1001999-11-14 21:23:21 +000056#ifndef PTRACE_ATTACH
57#define PTRACE_ATTACH PT_ATTACH
58#endif
59#ifndef PTRACE_DETACH
60#define PTRACE_DETACH PT_DETACH
61#endif
62#ifndef PTRACE_PEEKDATA
63#define PTRACE_PEEKDATA PT_READ_D
64#endif
65#ifndef PTRACE_POKEDATA
66#define PTRACE_POKEDATA PT_WRITE_D
67#endif
Alexandre Julliard498742f2006-06-27 21:27:47 +020068#ifndef PTRACE_PEEKUSER
69#define PTRACE_PEEKUSER PT_READ_U
70#endif
71#ifndef PTRACE_POKEUSER
72#define PTRACE_POKEUSER PT_WRITE_U
73#endif
74
75#ifdef PT_GETDBREGS
76#define PTRACE_GETDBREGS PT_GETDBREGS
77#endif
78#ifdef PT_SETDBREGS
79#define PTRACE_SETDBREGS PT_SETDBREGS
80#endif
Alexandre Julliard578c1001999-11-14 21:23:21 +000081
Alexandre Julliard5f258c62001-07-14 00:50:30 +000082#ifndef HAVE_SYS_PTRACE_H
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000083#define PT_CONTINUE 0
84#define PT_ATTACH 1
85#define PT_DETACH 2
86#define PT_READ_D 3
87#define PT_WRITE_D 4
Ove Kaavenada73832001-04-27 18:39:47 +000088#define PT_STEP 5
Andrew Talbotb1788c82007-03-17 10:52:14 +000089static inline int ptrace(int req, ...) { errno = EPERM; return -1; /*FAIL*/ }
Alexandre Julliard5f258c62001-07-14 00:50:30 +000090#endif /* HAVE_SYS_PTRACE_H */
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000091
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000092/* handle a status returned by wait4 */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +000093static int handle_child_status( struct thread *thread, int pid, int status, int want_sig )
Alexandre Julliard578c1001999-11-14 21:23:21 +000094{
Alexandre Julliard578c1001999-11-14 21:23:21 +000095 if (WIFSTOPPED(status))
96 {
97 int sig = WSTOPSIG(status);
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000098 if (debug_level && thread)
Alexandre Julliard91befe12003-02-01 01:38:40 +000099 fprintf( stderr, "%04x: *signal* signal=%d\n", thread->id, sig );
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000100 if (sig != want_sig)
Alexandre Julliard578c1001999-11-14 21:23:21 +0000101 {
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000102 /* ignore other signals for now */
Alexandre Julliard3dd0b2e2006-04-03 21:42:42 +0200103 ptrace( PTRACE_CONT, pid, (caddr_t)1, sig );
Alexandre Julliard578c1001999-11-14 21:23:21 +0000104 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000105 return sig;
Alexandre Julliard578c1001999-11-14 21:23:21 +0000106 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000107 if (thread && (WIFSIGNALED(status) || WIFEXITED(status)))
Alexandre Julliard578c1001999-11-14 21:23:21 +0000108 {
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000109 thread->unix_pid = -1;
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000110 thread->unix_tid = -1;
Alexandre Julliard578c1001999-11-14 21:23:21 +0000111 if (debug_level)
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000112 {
113 if (WIFSIGNALED(status))
Alexandre Julliard91befe12003-02-01 01:38:40 +0000114 fprintf( stderr, "%04x: *exited* signal=%d\n",
115 thread->id, WTERMSIG(status) );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000116 else
Alexandre Julliard91befe12003-02-01 01:38:40 +0000117 fprintf( stderr, "%04x: *exited* status=%d\n",
118 thread->id, WEXITSTATUS(status) );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000119 }
Alexandre Julliard578c1001999-11-14 21:23:21 +0000120 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000121 return 0;
122}
123
Alexandre Julliard77fde132003-04-26 02:14:02 +0000124/* wait4 wrapper to handle missing __WALL flag in older kernels */
125static inline pid_t wait4_wrapper( pid_t pid, int *status, int options, struct rusage *usage )
126{
127#ifdef __WALL
128 static int wall_flag = __WALL;
129
130 for (;;)
131 {
132 pid_t ret = wait4( pid, status, options | wall_flag, usage );
133 if (ret != -1 || !wall_flag || errno != EINVAL) return ret;
134 wall_flag = 0;
135 }
136#else
137 return wait4( pid, status, options, usage );
138#endif
139}
140
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000141/* handle a SIGCHLD signal */
Alexandre Julliard9037f4b2003-03-26 01:32:18 +0000142void sigchld_callback(void)
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000143{
144 int pid, status;
145
146 for (;;)
Alexandre Julliard578c1001999-11-14 21:23:21 +0000147 {
Alexandre Julliard77fde132003-04-26 02:14:02 +0000148 if (!(pid = wait4_wrapper( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
Alexandre Julliard48b74b32006-12-29 16:53:33 +0100149 if (pid != -1)
150 {
151 struct thread *thread = get_thread_from_tid( pid );
152 if (!thread) thread = get_thread_from_pid( pid );
153 handle_child_status( thread, pid, status, -1 );
154 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000155 else break;
Alexandre Julliard578c1001999-11-14 21:23:21 +0000156 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000157}
158
Alexandre Julliard498742f2006-06-27 21:27:47 +0200159/* return the Unix pid to use in ptrace calls for a given thread */
160static int get_ptrace_pid( struct thread *thread )
161{
162 if (thread->unix_tid != -1) return thread->unix_tid;
163 return thread->unix_pid;
164}
165
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000166/* wait for a ptraced child to get a certain signal */
Alexandre Julliardfcbd0da2003-05-06 00:21:21 +0000167static int wait4_thread( struct thread *thread, int signal )
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000168{
169 int res, status;
170
Alexandre Julliard9d99a042005-08-19 14:01:43 +0000171 start_watchdog();
Alexandre Julliardde1990f2003-08-21 21:35:15 +0000172 for (;;)
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000173 {
Alexandre Julliard77fde132003-04-26 02:14:02 +0000174 if ((res = wait4_wrapper( get_ptrace_pid(thread), &status, WUNTRACED, NULL )) == -1)
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000175 {
Alexandre Julliard9d99a042005-08-19 14:01:43 +0000176 if (errno == EINTR)
177 {
178 if (!watchdog_triggered()) continue;
179 if (debug_level) fprintf( stderr, "%04x: *watchdog* wait4 aborted\n", thread->id );
180 }
181 else if (errno == ECHILD) /* must have died */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000182 {
183 thread->unix_pid = -1;
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000184 thread->unix_tid = -1;
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000185 }
186 else perror( "wait4" );
Alexandre Julliard9d99a042005-08-19 14:01:43 +0000187 stop_watchdog();
Alexandre Julliardfcbd0da2003-05-06 00:21:21 +0000188 return 0;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000189 }
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000190 res = handle_child_status( thread, res, status, signal );
Alexandre Julliardde1990f2003-08-21 21:35:15 +0000191 if (!res || res == signal) break;
192 }
Alexandre Julliard9d99a042005-08-19 14:01:43 +0000193 stop_watchdog();
Alexandre Julliardfcbd0da2003-05-06 00:21:21 +0000194 return (thread->unix_pid != -1);
Alexandre Julliard578c1001999-11-14 21:23:21 +0000195}
196
Alexandre Julliard7dbd1f02006-04-10 21:07:21 +0200197/* send a signal to a specific thread */
198static inline int tkill( int tgid, int pid, int sig )
199{
200 int ret = -ENOSYS;
201
202#ifdef __linux__
203# ifdef __i386__
204 __asm__( "pushl %%ebx\n\t"
205 "movl %2,%%ebx\n\t"
206 "int $0x80\n\t"
207 "popl %%ebx\n\t"
208 : "=a" (ret)
209 : "0" (270) /*SYS_tgkill*/, "r" (tgid), "c" (pid), "d" (sig) );
210 if (ret == -ENOSYS)
211 __asm__( "pushl %%ebx\n\t"
212 "movl %2,%%ebx\n\t"
213 "int $0x80\n\t"
214 "popl %%ebx\n\t"
215 : "=a" (ret)
216 : "0" (238) /*SYS_tkill*/, "r" (pid), "c" (sig) );
217# elif defined(__x86_64__)
218 __asm__( "syscall" : "=a" (ret)
219 : "0" (200) /*SYS_tkill*/, "D" (pid), "S" (sig) );
220# endif
221#endif /* __linux__ */
222
223 if (ret >= 0) return ret;
224 errno = -ret;
225 return -1;
226}
227
Alexandre Julliardcd1c7fc2006-12-29 16:56:11 +0100228/* initialize the process tracing mechanism */
229void init_tracing_mechanism(void)
230{
231 /* no initialization needed for ptrace */
232}
233
234/* initialize the per-process tracing mechanism */
235void init_process_tracing( struct process *process )
236{
237 /* ptrace setup is done on-demand */
238}
239
240/* terminate the per-process tracing mechanism */
241void finish_process_tracing( struct process *process )
242{
243}
244
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000245/* send a Unix signal to a specific thread */
246int send_thread_signal( struct thread *thread, int sig )
247{
248 int ret = -1;
249
250 if (thread->unix_pid != -1)
251 {
Alexandre Julliard3dddc112003-04-16 23:34:05 +0000252 if (thread->unix_tid != -1)
253 {
Eric Pouech22357ca2006-02-14 12:24:32 +0100254 ret = tkill( thread->unix_pid, thread->unix_tid, sig );
Alexandre Julliard3dddc112003-04-16 23:34:05 +0000255 if (ret == -1 && errno == ENOSYS) ret = kill( thread->unix_pid, sig );
256 }
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000257 else ret = kill( thread->unix_pid, sig );
258
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000259 if (ret == -1 && errno == ESRCH) /* thread got killed */
260 {
261 thread->unix_pid = -1;
Alexandre Julliarda8497bd2003-03-22 21:00:09 +0000262 thread->unix_tid = -1;
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000263 }
264 }
Alexandre Julliardae4ecb62007-01-18 12:23:29 +0100265 if (debug_level && ret != -1)
266 fprintf( stderr, "%04x: *sent signal* signal=%d\n", thread->id, sig );
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000267 return (ret != -1);
268}
269
Alexandre Julliard498742f2006-06-27 21:27:47 +0200270/* resume a thread after we have used ptrace on it */
271static void resume_after_ptrace( struct thread *thread )
272{
273 if (thread->unix_pid == -1) return;
274 if (ptrace( PTRACE_DETACH, get_ptrace_pid(thread), (caddr_t)1, 0 ) == -1)
275 {
276 if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1; /* thread got killed */
277 }
278}
279
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000280/* suspend a thread to allow using ptrace on it */
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000281/* you must do a resume_after_ptrace when finished with the thread */
Alexandre Julliard498742f2006-06-27 21:27:47 +0200282static int suspend_for_ptrace( struct thread *thread )
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000283{
Alexandre Julliardd3928312000-04-04 19:55:28 +0000284 /* can't stop a thread while initialisation is in progress */
Alexandre Julliard02a53c12003-02-25 04:17:22 +0000285 if (thread->unix_pid == -1 || !is_process_init_done(thread->process)) goto error;
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000286
Alexandre Julliard820c5922006-04-10 20:25:22 +0200287 /* this may fail if the client is already being debugged */
288 if (ptrace( PTRACE_ATTACH, get_ptrace_pid(thread), 0, 0 ) == -1)
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000289 {
Alexandre Julliard820c5922006-04-10 20:25:22 +0200290 if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1; /* thread got killed */
291 goto error;
Alexandre Julliard9d99a042005-08-19 14:01:43 +0000292 }
293 if (wait4_thread( thread, SIGSTOP )) return 1;
294 resume_after_ptrace( thread );
Alexandre Julliardd3928312000-04-04 19:55:28 +0000295 error:
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000296 set_error( STATUS_ACCESS_DENIED );
297 return 0;
298}
299
Alexandre Julliard578c1001999-11-14 21:23:21 +0000300/* read an int from a thread address space */
Andrew Talbote60c8662006-10-07 19:47:38 +0100301static int read_thread_int( struct thread *thread, int *addr, int *data )
Alexandre Julliard578c1001999-11-14 21:23:21 +0000302{
Alexandre Julliardd04ccb82003-03-04 22:18:43 +0000303 errno = 0;
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000304 *data = ptrace( PTRACE_PEEKDATA, get_ptrace_pid(thread), (caddr_t)addr, 0 );
Gerald Pfeifer1f012362000-10-17 00:25:59 +0000305 if ( *data == -1 && errno)
Alexandre Julliard578c1001999-11-14 21:23:21 +0000306 {
307 file_set_error();
308 return -1;
309 }
310 return 0;
311}
312
313/* write an int to a thread address space */
Alexandre Julliardcb709312006-04-07 19:52:12 +0200314static int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask )
Alexandre Julliard578c1001999-11-14 21:23:21 +0000315{
316 int res;
Michael Stefaniuca6249772006-07-25 10:30:04 +0200317 if (mask != ~0u)
Alexandre Julliard578c1001999-11-14 21:23:21 +0000318 {
319 if (read_thread_int( thread, addr, &res ) == -1) return -1;
320 data = (data & mask) | (res & ~mask);
321 }
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000322 if ((res = ptrace( PTRACE_POKEDATA, get_ptrace_pid(thread), (caddr_t)addr, data )) == -1)
Gerald Pfeifer1f012362000-10-17 00:25:59 +0000323 file_set_error();
Alexandre Julliard578c1001999-11-14 21:23:21 +0000324 return res;
325}
Alexandre Julliardcb709312006-04-07 19:52:12 +0200326
Alexandre Julliard7b767fb2006-07-25 11:41:47 +0200327/* return a thread of the process suitable for ptracing */
328static struct thread *get_ptrace_thread( struct process *process )
329{
330 struct thread *thread;
331
332 LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
333 {
334 if (thread->unix_pid != -1) return thread;
335 }
336 set_error( STATUS_ACCESS_DENIED ); /* process is dead */
337 return NULL;
338}
339
Alexandre Julliardcb709312006-04-07 19:52:12 +0200340/* read data from a process memory space */
Alexandre Julliard0f273c12006-07-26 10:43:25 +0200341int read_process_memory( struct process *process, const void *ptr, data_size_t size, char *dest )
Alexandre Julliardcb709312006-04-07 19:52:12 +0200342{
Alexandre Julliard7b767fb2006-07-25 11:41:47 +0200343 struct thread *thread = get_ptrace_thread( process );
Alexandre Julliardcb709312006-04-07 19:52:12 +0200344 unsigned int first_offset, last_offset, len;
345 int data, *addr;
346
Alexandre Julliard7b767fb2006-07-25 11:41:47 +0200347 if (!thread) return 0;
Alexandre Julliardcb709312006-04-07 19:52:12 +0200348
349 first_offset = (unsigned long)ptr % sizeof(int);
350 last_offset = (size + first_offset) % sizeof(int);
351 if (!last_offset) last_offset = sizeof(int);
352
353 addr = (int *)((char *)ptr - first_offset);
354 len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
355
356 if (suspend_for_ptrace( thread ))
357 {
358 if (len > 1)
359 {
360 if (read_thread_int( thread, addr++, &data ) == -1) goto done;
361 memcpy( dest, (char *)&data + first_offset, sizeof(int) - first_offset );
362 dest += sizeof(int) - first_offset;
363 first_offset = 0;
364 len--;
365 }
366
367 while (len > 1)
368 {
369 if (read_thread_int( thread, addr++, &data ) == -1) goto done;
370 memcpy( dest, &data, sizeof(int) );
371 dest += sizeof(int);
372 len--;
373 }
374
375 if (read_thread_int( thread, addr++, &data ) == -1) goto done;
376 memcpy( dest, (char *)&data + first_offset, last_offset - first_offset );
377 len--;
378
379 done:
380 resume_after_ptrace( thread );
381 }
382 return !len;
383}
384
385/* make sure we can write to the whole address range */
386/* len is the total size (in ints) */
Alexandre Julliard0f273c12006-07-26 10:43:25 +0200387static int check_process_write_access( struct thread *thread, int *addr, data_size_t len )
Alexandre Julliardcb709312006-04-07 19:52:12 +0200388{
389 int page = get_page_size() / sizeof(int);
390
391 for (;;)
392 {
393 if (write_thread_int( thread, addr, 0, 0 ) == -1) return 0;
394 if (len <= page) break;
395 addr += page;
396 len -= page;
397 }
398 return (write_thread_int( thread, addr + len - 1, 0, 0 ) != -1);
399}
400
401/* write data to a process memory space */
Alexandre Julliard0f273c12006-07-26 10:43:25 +0200402int write_process_memory( struct process *process, void *ptr, data_size_t size, const char *src )
Alexandre Julliardcb709312006-04-07 19:52:12 +0200403{
Alexandre Julliard7b767fb2006-07-25 11:41:47 +0200404 struct thread *thread = get_ptrace_thread( process );
Alexandre Julliardcb709312006-04-07 19:52:12 +0200405 int ret = 0, data = 0;
Alexandre Julliard0f273c12006-07-26 10:43:25 +0200406 data_size_t len;
Alexandre Julliardcb709312006-04-07 19:52:12 +0200407 int *addr;
408 unsigned int first_mask, first_offset, last_mask, last_offset;
409
Alexandre Julliard7b767fb2006-07-25 11:41:47 +0200410 if (!thread) return 0;
Alexandre Julliardcb709312006-04-07 19:52:12 +0200411
412 /* compute the mask for the first int */
413 first_mask = ~0;
414 first_offset = (unsigned long)ptr % sizeof(int);
415 memset( &first_mask, 0, first_offset );
416
417 /* compute the mask for the last int */
418 last_offset = (size + first_offset) % sizeof(int);
419 if (!last_offset) last_offset = sizeof(int);
420 last_mask = 0;
421 memset( &last_mask, 0xff, last_offset );
422
423 addr = (int *)((char *)ptr - first_offset);
424 len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
425
426 if (suspend_for_ptrace( thread ))
427 {
428 if (!check_process_write_access( thread, addr, len ))
429 {
430 set_error( STATUS_ACCESS_DENIED );
431 goto done;
432 }
433 /* first word is special */
434 if (len > 1)
435 {
436 memcpy( (char *)&data + first_offset, src, sizeof(int) - first_offset );
437 src += sizeof(int) - first_offset;
438 if (write_thread_int( thread, addr++, data, first_mask ) == -1) goto done;
439 first_offset = 0;
440 len--;
441 }
442 else last_mask &= first_mask;
443
444 while (len > 1)
445 {
446 memcpy( &data, src, sizeof(int) );
447 src += sizeof(int);
448 if (write_thread_int( thread, addr++, data, ~0 ) == -1) goto done;
449 len--;
450 }
451
452 /* last word is special too */
453 memcpy( (char *)&data + first_offset, src, last_offset - first_offset );
454 if (write_thread_int( thread, addr, data, last_mask ) == -1) goto done;
455 ret = 1;
456
457 done:
458 resume_after_ptrace( thread );
459 }
460 return ret;
461}
462
463/* retrieve an LDT selector entry */
464void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
465 unsigned int *limit, unsigned char *flags )
466{
467 if (!thread->process->ldt_copy)
468 {
469 set_error( STATUS_ACCESS_DENIED );
470 return;
471 }
472 if (entry >= 8192)
473 {
Eric Pouech5b1f3b12006-11-04 11:52:44 +0100474 set_error( STATUS_ACCESS_VIOLATION );
Alexandre Julliardcb709312006-04-07 19:52:12 +0200475 return;
476 }
477 if (suspend_for_ptrace( thread ))
478 {
479 unsigned char flags_buf[4];
480 int *addr = (int *)thread->process->ldt_copy + entry;
481 if (read_thread_int( thread, addr, (int *)base ) == -1) goto done;
482 if (read_thread_int( thread, addr + 8192, (int *)limit ) == -1) goto done;
483 addr = (int *)thread->process->ldt_copy + 2*8192 + (entry >> 2);
484 if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done;
485 *flags = flags_buf[entry & 3];
486 done:
487 resume_after_ptrace( thread );
488 }
489}
Alexandre Julliard498742f2006-06-27 21:27:47 +0200490
491
492#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
493
494#ifdef HAVE_SYS_USER_H
495# include <sys/user.h>
496#endif
497
498/* debug register offset in struct user */
Alexandre Julliardc242c3b2006-07-11 12:06:38 +0200499#define DR_OFFSET(dr) ((((struct user *)0)->u_debugreg) + (dr))
Alexandre Julliard498742f2006-06-27 21:27:47 +0200500
501/* retrieve the thread x86 registers */
502void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
503{
Alexandre Julliardc242c3b2006-07-11 12:06:38 +0200504 int i, pid = get_ptrace_pid(thread);
505 long data[8];
Alexandre Julliard498742f2006-06-27 21:27:47 +0200506
507 /* all other regs are handled on the client side */
508 assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS );
509
510 if (!suspend_for_ptrace( thread )) return;
511
Alexandre Julliardc242c3b2006-07-11 12:06:38 +0200512 for (i = 0; i < 8; i++)
513 {
514 if (i == 4 || i == 5) continue;
515 errno = 0;
516 data[i] = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(i), 0 );
517 if ((data[i] == -1) && errno)
518 {
519 file_set_error();
520 goto done;
521 }
522 }
523 context->Dr0 = data[0];
524 context->Dr1 = data[1];
525 context->Dr2 = data[2];
526 context->Dr3 = data[3];
527 context->Dr6 = data[6];
528 context->Dr7 = data[7];
Alexandre Julliard498742f2006-06-27 21:27:47 +0200529 context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
Alexandre Julliardc242c3b2006-07-11 12:06:38 +0200530done:
Alexandre Julliard498742f2006-06-27 21:27:47 +0200531 resume_after_ptrace( thread );
532}
533
534/* set the thread x86 registers */
535void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
536{
537 int pid = get_ptrace_pid( thread );
538
539 /* all other regs are handled on the client side */
540 assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS );
541
542 if (!suspend_for_ptrace( thread )) return;
543
544 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
545 if (thread->context) thread->context->Dr0 = context->Dr0;
546 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
547 if (thread->context) thread->context->Dr1 = context->Dr1;
548 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
549 if (thread->context) thread->context->Dr2 = context->Dr2;
550 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
551 if (thread->context) thread->context->Dr3 = context->Dr3;
552 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
553 if (thread->context) thread->context->Dr6 = context->Dr6;
554 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
555 if (thread->context) thread->context->Dr7 = context->Dr7;
556 resume_after_ptrace( thread );
557 return;
558 error:
559 file_set_error();
560 resume_after_ptrace( thread );
561}
562
563#elif defined(__i386__) && defined(PTRACE_GETDBREGS) && defined(PTRACE_SETDBREGS) && \
564 (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__))
565
566#include <machine/reg.h>
567
568/* retrieve the thread x86 registers */
569void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
570{
571 int pid = get_ptrace_pid(thread);
572 struct dbreg dbregs;
573
574 /* all other regs are handled on the client side */
575 assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS );
576
577 if (!suspend_for_ptrace( thread )) return;
578
579 if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error();
580 else
581 {
582#ifdef DBREG_DRX
583 /* needed for FreeBSD, the structure fields have changed under 5.x */
584 context->Dr0 = DBREG_DRX((&dbregs), 0);
585 context->Dr1 = DBREG_DRX((&dbregs), 1);
586 context->Dr2 = DBREG_DRX((&dbregs), 2);
587 context->Dr3 = DBREG_DRX((&dbregs), 3);
588 context->Dr6 = DBREG_DRX((&dbregs), 6);
589 context->Dr7 = DBREG_DRX((&dbregs), 7);
590#else
591 context->Dr0 = dbregs.dr0;
592 context->Dr1 = dbregs.dr1;
593 context->Dr2 = dbregs.dr2;
594 context->Dr3 = dbregs.dr3;
595 context->Dr6 = dbregs.dr6;
596 context->Dr7 = dbregs.dr7;
597#endif
598 context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
599 }
600 resume_after_ptrace( thread );
601}
602
603/* set the thread x86 registers */
604void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
605{
606 int pid = get_ptrace_pid(thread);
607 struct dbreg dbregs;
608
609 /* all other regs are handled on the client side */
610 assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS );
611
612 if (!suspend_for_ptrace( thread )) return;
613
614#ifdef DBREG_DRX
615 /* needed for FreeBSD, the structure fields have changed under 5.x */
616 DBREG_DRX((&dbregs), 0) = context->Dr0;
617 DBREG_DRX((&dbregs), 1) = context->Dr1;
618 DBREG_DRX((&dbregs), 2) = context->Dr2;
619 DBREG_DRX((&dbregs), 3) = context->Dr3;
620 DBREG_DRX((&dbregs), 4) = 0;
621 DBREG_DRX((&dbregs), 5) = 0;
622 DBREG_DRX((&dbregs), 6) = context->Dr6;
623 DBREG_DRX((&dbregs), 7) = context->Dr7;
624#else
625 dbregs.dr0 = context->Dr0;
626 dbregs.dr1 = context->Dr1;
627 dbregs.dr2 = context->Dr2;
628 dbregs.dr3 = context->Dr3;
629 dbregs.dr4 = 0;
630 dbregs.dr5 = 0;
631 dbregs.dr6 = context->Dr6;
632 dbregs.dr7 = context->Dr7;
633#endif
634 if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error();
635 else if (thread->context) /* update the cached values */
636 {
637 thread->context->Dr0 = context->Dr0;
638 thread->context->Dr1 = context->Dr1;
639 thread->context->Dr2 = context->Dr2;
640 thread->context->Dr3 = context->Dr3;
641 thread->context->Dr6 = context->Dr6;
642 thread->context->Dr7 = context->Dr7;
643 }
644 resume_after_ptrace( thread );
645}
646
647#else /* linux || __FreeBSD__ */
648
649/* retrieve the thread x86 registers */
650void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
651{
652}
653
654/* set the thread x86 debug registers */
655void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
656{
657}
658
659#endif /* linux || __FreeBSD__ */
Alexandre Julliardc2734982006-12-29 20:38:49 +0100660
661#endif /* USE_PTRACE */