mshtml: Initialize url variable in IPersistMoniker::Load.
[wine] / server / ptrace.c
1 /*
2  * Server-side ptrace support
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
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
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <signal.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29 #ifdef HAVE_SYS_PTRACE_H
30 # include <sys/ptrace.h>
31 #endif
32 #ifdef HAVE_SYS_WAIT_H
33 # include <sys/wait.h>
34 #endif
35 #include <unistd.h>
36
37 #include "ntstatus.h"
38 #define WIN32_NO_STATUS
39 #include "winternl.h"
40
41 #include "file.h"
42 #include "process.h"
43 #include "thread.h"
44
45 #ifndef PTRACE_CONT
46 #define PTRACE_CONT PT_CONTINUE
47 #endif
48 #ifndef PTRACE_SINGLESTEP
49 #define PTRACE_SINGLESTEP PT_STEP
50 #endif
51 #ifndef PTRACE_ATTACH
52 #define PTRACE_ATTACH PT_ATTACH
53 #endif
54 #ifndef PTRACE_DETACH
55 #define PTRACE_DETACH PT_DETACH
56 #endif
57 #ifndef PTRACE_PEEKDATA
58 #define PTRACE_PEEKDATA PT_READ_D
59 #endif
60 #ifndef PTRACE_POKEDATA
61 #define PTRACE_POKEDATA PT_WRITE_D
62 #endif
63
64 #ifndef HAVE_SYS_PTRACE_H
65 #define PT_CONTINUE 0
66 #define PT_ATTACH   1
67 #define PT_DETACH   2
68 #define PT_READ_D   3
69 #define PT_WRITE_D  4
70 #define PT_STEP     5
71 inline static int ptrace(int req, ...) { errno = EPERM; return -1; /*FAIL*/ }
72 #endif  /* HAVE_SYS_PTRACE_H */
73
74 /* handle a status returned by wait4 */
75 static int handle_child_status( struct thread *thread, int pid, int status, int want_sig )
76 {
77     if (WIFSTOPPED(status))
78     {
79         int sig = WSTOPSIG(status);
80         if (debug_level && thread)
81             fprintf( stderr, "%04x: *signal* signal=%d\n", thread->id, sig );
82         if (sig != want_sig)
83         {
84             /* ignore other signals for now */
85             ptrace( PTRACE_CONT, pid, (caddr_t)1, sig );
86         }
87         return sig;
88     }
89     if (thread && (WIFSIGNALED(status) || WIFEXITED(status)))
90     {
91         thread->unix_pid = -1;
92         thread->unix_tid = -1;
93         if (debug_level)
94         {
95             if (WIFSIGNALED(status))
96                 fprintf( stderr, "%04x: *exited* signal=%d\n",
97                          thread->id, WTERMSIG(status) );
98             else
99                 fprintf( stderr, "%04x: *exited* status=%d\n",
100                          thread->id, WEXITSTATUS(status) );
101         }
102     }
103     return 0;
104 }
105
106 /* wait4 wrapper to handle missing __WALL flag in older kernels */
107 static inline pid_t wait4_wrapper( pid_t pid, int *status, int options, struct rusage *usage )
108 {
109 #ifdef __WALL
110     static int wall_flag = __WALL;
111
112     for (;;)
113     {
114         pid_t ret = wait4( pid, status, options | wall_flag, usage );
115         if (ret != -1 || !wall_flag || errno != EINVAL) return ret;
116         wall_flag = 0;
117     }
118 #else
119     return wait4( pid, status, options, usage );
120 #endif
121 }
122
123 /* handle a SIGCHLD signal */
124 void sigchld_callback(void)
125 {
126     int pid, status;
127
128     for (;;)
129     {
130         if (!(pid = wait4_wrapper( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
131         if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status, -1 );
132         else break;
133     }
134 }
135
136 /* wait for a ptraced child to get a certain signal */
137 static int wait4_thread( struct thread *thread, int signal )
138 {
139     int res, status;
140
141     start_watchdog();
142     for (;;)
143     {
144         if ((res = wait4_wrapper( get_ptrace_pid(thread), &status, WUNTRACED, NULL )) == -1)
145         {
146             if (errno == EINTR)
147             {
148                 if (!watchdog_triggered()) continue;
149                 if (debug_level) fprintf( stderr, "%04x: *watchdog* wait4 aborted\n", thread->id );
150             }
151             else if (errno == ECHILD)  /* must have died */
152             {
153                 thread->unix_pid = -1;
154                 thread->unix_tid = -1;
155             }
156             else perror( "wait4" );
157             stop_watchdog();
158             return 0;
159         }
160         res = handle_child_status( thread, res, status, signal );
161         if (!res || res == signal) break;
162     }
163     stop_watchdog();
164     return (thread->unix_pid != -1);
165 }
166
167 /* return the Unix pid to use in ptrace calls for a given thread */
168 int get_ptrace_pid( struct thread *thread )
169 {
170     if (thread->unix_tid != -1) return thread->unix_tid;
171     return thread->unix_pid;
172 }
173
174 /* send a signal to a specific thread */
175 static inline int tkill( int tgid, int pid, int sig )
176 {
177     int ret = -ENOSYS;
178
179 #ifdef __linux__
180 # ifdef __i386__
181     __asm__( "pushl %%ebx\n\t"
182              "movl %2,%%ebx\n\t"
183              "int $0x80\n\t"
184              "popl %%ebx\n\t"
185              : "=a" (ret)
186              : "0" (270) /*SYS_tgkill*/, "r" (tgid), "c" (pid), "d" (sig) );
187     if (ret == -ENOSYS)
188         __asm__( "pushl %%ebx\n\t"
189                  "movl %2,%%ebx\n\t"
190                  "int $0x80\n\t"
191                  "popl %%ebx\n\t"
192                  : "=a" (ret)
193                  : "0" (238) /*SYS_tkill*/, "r" (pid), "c" (sig) );
194 # elif defined(__x86_64__)
195     __asm__( "syscall" : "=a" (ret)
196              : "0" (200) /*SYS_tkill*/, "D" (pid), "S" (sig) );
197 # endif
198 #endif  /* __linux__ */
199
200     if (ret >= 0) return ret;
201     errno = -ret;
202     return -1;
203 }
204
205 /* send a Unix signal to a specific thread */
206 int send_thread_signal( struct thread *thread, int sig )
207 {
208     int ret = -1;
209
210     if (thread->unix_pid != -1)
211     {
212         if (thread->unix_tid != -1)
213         {
214             ret = tkill( thread->unix_pid, thread->unix_tid, sig );
215             if (ret == -1 && errno == ENOSYS) ret = kill( thread->unix_pid, sig );
216         }
217         else ret = kill( thread->unix_pid, sig );
218
219         if (ret == -1 && errno == ESRCH) /* thread got killed */
220         {
221             thread->unix_pid = -1;
222             thread->unix_tid = -1;
223         }
224     }
225     return (ret != -1);
226 }
227
228 /* suspend a thread to allow using ptrace on it */
229 /* you must do a resume_after_ptrace when finished with the thread */
230 int suspend_for_ptrace( struct thread *thread )
231 {
232     /* can't stop a thread while initialisation is in progress */
233     if (thread->unix_pid == -1 || !is_process_init_done(thread->process)) goto error;
234
235     /* this may fail if the client is already being debugged */
236     if (ptrace( PTRACE_ATTACH, get_ptrace_pid(thread), 0, 0 ) == -1)
237     {
238         if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1;  /* thread got killed */
239         goto error;
240     }
241     if (wait4_thread( thread, SIGSTOP )) return 1;
242     resume_after_ptrace( thread );
243  error:
244     set_error( STATUS_ACCESS_DENIED );
245     return 0;
246 }
247
248 /* resume a thread after we have used ptrace on it */
249 void resume_after_ptrace( struct thread *thread )
250 {
251     if (thread->unix_pid == -1) return;
252     if (ptrace( PTRACE_DETACH, get_ptrace_pid(thread), (caddr_t)1, 0 ) == -1)
253     {
254         if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1;  /* thread got killed */
255     }
256 }
257
258 /* read an int from a thread address space */
259 static int read_thread_int( struct thread *thread, const int *addr, int *data )
260 {
261     errno = 0;
262     *data = ptrace( PTRACE_PEEKDATA, get_ptrace_pid(thread), (caddr_t)addr, 0 );
263     if ( *data == -1 && errno)
264     {
265         file_set_error();
266         return -1;
267     }
268     return 0;
269 }
270
271 /* write an int to a thread address space */
272 static int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask )
273 {
274     int res;
275     if (mask != ~0)
276     {
277         if (read_thread_int( thread, addr, &res ) == -1) return -1;
278         data = (data & mask) | (res & ~mask);
279     }
280     if ((res = ptrace( PTRACE_POKEDATA, get_ptrace_pid(thread), (caddr_t)addr, data )) == -1)
281         file_set_error();
282     return res;
283 }
284
285 /* read data from a process memory space */
286 int read_process_memory( struct process *process, const void *ptr, size_t size, char *dest )
287 {
288     struct thread *thread = get_process_first_thread( process );
289     unsigned int first_offset, last_offset, len;
290     int data, *addr;
291
292     if (!thread)  /* process is dead */
293     {
294         set_error( STATUS_ACCESS_DENIED );
295         return 0;
296     }
297
298     first_offset = (unsigned long)ptr % sizeof(int);
299     last_offset = (size + first_offset) % sizeof(int);
300     if (!last_offset) last_offset = sizeof(int);
301
302     addr = (int *)((char *)ptr - first_offset);
303     len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
304
305     if (suspend_for_ptrace( thread ))
306     {
307         if (len > 1)
308         {
309             if (read_thread_int( thread, addr++, &data ) == -1) goto done;
310             memcpy( dest, (char *)&data + first_offset, sizeof(int) - first_offset );
311             dest += sizeof(int) - first_offset;
312             first_offset = 0;
313             len--;
314         }
315
316         while (len > 1)
317         {
318             if (read_thread_int( thread, addr++, &data ) == -1) goto done;
319             memcpy( dest, &data, sizeof(int) );
320             dest += sizeof(int);
321             len--;
322         }
323
324         if (read_thread_int( thread, addr++, &data ) == -1) goto done;
325         memcpy( dest, (char *)&data + first_offset, last_offset - first_offset );
326         len--;
327
328     done:
329         resume_after_ptrace( thread );
330     }
331     return !len;
332 }
333
334 /* make sure we can write to the whole address range */
335 /* len is the total size (in ints) */
336 static int check_process_write_access( struct thread *thread, int *addr, size_t len )
337 {
338     int page = get_page_size() / sizeof(int);
339
340     for (;;)
341     {
342         if (write_thread_int( thread, addr, 0, 0 ) == -1) return 0;
343         if (len <= page) break;
344         addr += page;
345         len -= page;
346     }
347     return (write_thread_int( thread, addr + len - 1, 0, 0 ) != -1);
348 }
349
350 /* write data to a process memory space */
351 int write_process_memory( struct process *process, void *ptr, size_t size, const char *src )
352 {
353     struct thread *thread = get_process_first_thread( process );
354     int ret = 0, data = 0;
355     size_t len;
356     int *addr;
357     unsigned int first_mask, first_offset, last_mask, last_offset;
358
359     if (!thread)  /* process is dead */
360     {
361         set_error( STATUS_ACCESS_DENIED );
362         return 0;
363     }
364
365     /* compute the mask for the first int */
366     first_mask = ~0;
367     first_offset = (unsigned long)ptr % sizeof(int);
368     memset( &first_mask, 0, first_offset );
369
370     /* compute the mask for the last int */
371     last_offset = (size + first_offset) % sizeof(int);
372     if (!last_offset) last_offset = sizeof(int);
373     last_mask = 0;
374     memset( &last_mask, 0xff, last_offset );
375
376     addr = (int *)((char *)ptr - first_offset);
377     len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
378
379     if (suspend_for_ptrace( thread ))
380     {
381         if (!check_process_write_access( thread, addr, len ))
382         {
383             set_error( STATUS_ACCESS_DENIED );
384             goto done;
385         }
386         /* first word is special */
387         if (len > 1)
388         {
389             memcpy( (char *)&data + first_offset, src, sizeof(int) - first_offset );
390             src += sizeof(int) - first_offset;
391             if (write_thread_int( thread, addr++, data, first_mask ) == -1) goto done;
392             first_offset = 0;
393             len--;
394         }
395         else last_mask &= first_mask;
396
397         while (len > 1)
398         {
399             memcpy( &data, src, sizeof(int) );
400             src += sizeof(int);
401             if (write_thread_int( thread, addr++, data, ~0 ) == -1) goto done;
402             len--;
403         }
404
405         /* last word is special too */
406         memcpy( (char *)&data + first_offset, src, last_offset - first_offset );
407         if (write_thread_int( thread, addr, data, last_mask ) == -1) goto done;
408         ret = 1;
409
410     done:
411         resume_after_ptrace( thread );
412     }
413     return ret;
414 }
415
416 /* retrieve an LDT selector entry */
417 void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
418                          unsigned int *limit, unsigned char *flags )
419 {
420     if (!thread->process->ldt_copy)
421     {
422         set_error( STATUS_ACCESS_DENIED );
423         return;
424     }
425     if (entry >= 8192)
426     {
427         set_error( STATUS_INVALID_PARAMETER );  /* FIXME */
428         return;
429     }
430     if (suspend_for_ptrace( thread ))
431     {
432         unsigned char flags_buf[4];
433         int *addr = (int *)thread->process->ldt_copy + entry;
434         if (read_thread_int( thread, addr, (int *)base ) == -1) goto done;
435         if (read_thread_int( thread, addr + 8192, (int *)limit ) == -1) goto done;
436         addr = (int *)thread->process->ldt_copy + 2*8192 + (entry >> 2);
437         if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done;
438         *flags = flags_buf[entry & 3];
439     done:
440         resume_after_ptrace( thread );
441     }
442 }