blob: 28781ad0761e04d403a29580f35c488721db1350 [file] [log] [blame]
Alexandre Julliarde712e071999-05-23 19:53:30 +00001/*
2 * Server-side debugger functions
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
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliarde712e071999-05-23 19:53:30 +000019 */
20
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000021#include "config.h"
22#include "wine/port.h"
23
Alexandre Julliarde712e071999-05-23 19:53:30 +000024#include <assert.h>
Alexandre Julliard3c4538c2002-02-27 01:55:02 +000025#include <signal.h>
Patrik Stridvall2c684081999-07-31 17:36:48 +000026#include <string.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000027#include <stdarg.h>
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000028#include <stdio.h>
Patrik Stridvall2c684081999-07-31 17:36:48 +000029
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000030#include "windef.h"
Alexandre Julliarde712e071999-05-23 19:53:30 +000031
Alexandre Julliarde712e071999-05-23 19:53:30 +000032#include "handle.h"
33#include "process.h"
34#include "thread.h"
Alexandre Julliard5bc78081999-06-22 17:26:53 +000035#include "request.h"
Eric Pouech0b83d4c2001-11-23 23:04:58 +000036#include "console.h"
Alexandre Julliarde712e071999-05-23 19:53:30 +000037
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000038enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED };
39
40/* debug event */
Alexandre Julliarde712e071999-05-23 19:53:30 +000041struct debug_event
42{
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000043 struct object obj; /* object header */
Alexandre Julliardefdb4962005-02-26 17:45:29 +000044 struct list entry; /* entry in event queue */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000045 struct thread *sender; /* thread which sent this event */
46 struct thread *debugger; /* debugger thread receiving the event */
47 enum debug_event_state state; /* event state */
48 int status; /* continuation status */
Alexandre Julliard3e2517c2000-01-20 18:59:03 +000049 debug_event_t data; /* event data */
Alexandre Julliarde939eae2001-01-26 20:45:41 +000050 CONTEXT context; /* register context */
Alexandre Julliarde712e071999-05-23 19:53:30 +000051};
52
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000053/* debug context */
Alexandre Julliarde712e071999-05-23 19:53:30 +000054struct debug_ctx
55{
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000056 struct object obj; /* object header */
Alexandre Julliardefdb4962005-02-26 17:45:29 +000057 struct list event_queue; /* pending events queue */
Eric Pouechfbccb382002-02-27 01:28:30 +000058 int kill_on_exit;/* kill debuggees on debugger exit ? */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000059};
60
61
62static void debug_event_dump( struct object *obj, int verbose );
63static int debug_event_signaled( struct object *obj, struct thread *thread );
64static void debug_event_destroy( struct object *obj );
65
66static const struct object_ops debug_event_ops =
67{
68 sizeof(struct debug_event), /* size */
69 debug_event_dump, /* dump */
70 add_queue, /* add_queue */
71 remove_queue, /* remove_queue */
72 debug_event_signaled, /* signaled */
73 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000074 no_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +000075 no_get_fd, /* get_fd */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +000076 no_close_handle, /* close_handle */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000077 debug_event_destroy /* destroy */
78};
79
80static void debug_ctx_dump( struct object *obj, int verbose );
81static int debug_ctx_signaled( struct object *obj, struct thread *thread );
82static void debug_ctx_destroy( struct object *obj );
83
84static const struct object_ops debug_ctx_ops =
85{
86 sizeof(struct debug_ctx), /* size */
87 debug_ctx_dump, /* dump */
88 add_queue, /* add_queue */
89 remove_queue, /* remove_queue */
90 debug_ctx_signaled, /* signaled */
91 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000092 no_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +000093 no_get_fd, /* get_fd */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +000094 no_close_handle, /* close_handle */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000095 debug_ctx_destroy /* destroy */
Alexandre Julliarde712e071999-05-23 19:53:30 +000096};
97
Alexandre Julliarde712e071999-05-23 19:53:30 +000098
Alexandre Julliardea0d0282000-03-10 22:16:10 +000099/* routines to build an event according to its type */
100
101static int fill_exception_event( struct debug_event *event, void *arg )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000102{
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000103 memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000104 return 1;
105}
106
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000107static int fill_create_thread_event( struct debug_event *event, void *arg )
108{
109 struct process *debugger = event->debugger->process;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000110 struct thread *thread = event->sender;
Alexandre Julliard51885742002-05-30 20:12:58 +0000111 obj_handle_t handle;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000112
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000113 /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000114 if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE ))) return 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000115 event->data.info.create_thread.handle = handle;
116 event->data.info.create_thread.teb = thread->teb;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000117 event->data.info.create_thread.start = arg;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000118 return 1;
119}
120
121static int fill_create_process_event( struct debug_event *event, void *arg )
122{
123 struct process *debugger = event->debugger->process;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000124 struct thread *thread = event->sender;
125 struct process *process = thread->process;
Alexandre Julliard51885742002-05-30 20:12:58 +0000126 obj_handle_t handle;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000127
128 /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000129 if (!(handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE ))) return 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000130 event->data.info.create_process.process = handle;
131
132 /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000133 if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000134 {
Alexandre Julliardd549f692000-12-22 02:04:15 +0000135 close_handle( debugger, event->data.info.create_process.process, NULL );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000136 return 0;
137 }
138 event->data.info.create_process.thread = handle;
139
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000140 handle = 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000141 if (process->exe.file &&
142 /* the doc says write access too, but this doesn't seem a good idea */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000143 !(handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000144 {
Alexandre Julliardd549f692000-12-22 02:04:15 +0000145 close_handle( debugger, event->data.info.create_process.process, NULL );
146 close_handle( debugger, event->data.info.create_process.thread, NULL );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000147 return 0;
148 }
149 event->data.info.create_process.file = handle;
150 event->data.info.create_process.teb = thread->teb;
151 event->data.info.create_process.base = process->exe.base;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000152 event->data.info.create_process.start = arg;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000153 event->data.info.create_process.dbg_offset = process->exe.dbg_offset;
154 event->data.info.create_process.dbg_size = process->exe.dbg_size;
Alexandre Julliarda37dec02000-06-08 00:57:24 +0000155 event->data.info.create_process.name = process->exe.name;
Alexandre Julliardc30cefb2003-09-30 01:04:19 +0000156 event->data.info.create_process.unicode = 1;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000157 return 1;
158}
159
160static int fill_exit_thread_event( struct debug_event *event, void *arg )
161{
162 struct thread *thread = arg;
163 event->data.info.exit.exit_code = thread->exit_code;
164 return 1;
165}
166
167static int fill_exit_process_event( struct debug_event *event, void *arg )
168{
169 struct process *process = arg;
170 event->data.info.exit.exit_code = process->exit_code;
171 return 1;
172}
173
174static int fill_load_dll_event( struct debug_event *event, void *arg )
175{
176 struct process *debugger = event->debugger->process;
177 struct process_dll *dll = arg;
Alexandre Julliard51885742002-05-30 20:12:58 +0000178 obj_handle_t handle = 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000179
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000180 if (dll->file && !(handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000181 return 0;
182 event->data.info.load_dll.handle = handle;
183 event->data.info.load_dll.base = dll->base;
184 event->data.info.load_dll.dbg_offset = dll->dbg_offset;
185 event->data.info.load_dll.dbg_size = dll->dbg_size;
186 event->data.info.load_dll.name = dll->name;
Alexandre Julliardc30cefb2003-09-30 01:04:19 +0000187 event->data.info.load_dll.unicode = 1;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000188 return 1;
189}
190
191static int fill_unload_dll_event( struct debug_event *event, void *arg )
192{
193 event->data.info.unload_dll.base = arg;
194 return 1;
195}
196
197static int fill_output_debug_string_event( struct debug_event *event, void *arg )
198{
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000199 struct debug_event_output_string *data = arg;
200 event->data.info.output_string = *data;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000201 return 1;
202}
203
204typedef int (*fill_event_func)( struct debug_event *event, void *arg );
205
206#define NB_DEBUG_EVENTS OUTPUT_DEBUG_STRING_EVENT /* RIP_EVENT not supported */
207
208static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] =
209{
210 fill_exception_event, /* EXCEPTION_DEBUG_EVENT */
211 fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */
212 fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */
213 fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */
214 fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */
215 fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */
216 fill_unload_dll_event, /* UNLOAD_DLL_DEBUG_EVENT */
217 fill_output_debug_string_event /* OUTPUT_DEBUG_STRING_EVENT */
218};
219
220
Alexandre Julliarde712e071999-05-23 19:53:30 +0000221/* unlink the first event from the queue */
222static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event )
223{
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000224 list_remove( &event->entry );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000225 if (event->sender->debug_event == event) event->sender->debug_event = NULL;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000226 release_object( event );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000227}
228
229/* link an event at the end of the queue */
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000230static void link_event( struct debug_event *event )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000231{
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000232 struct debug_ctx *debug_ctx = event->debugger->debug_ctx;
233
234 assert( debug_ctx );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000235 grab_object( event );
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000236 list_add_tail( &debug_ctx->event_queue, &event->entry );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000237 if (!event->sender->debug_event) wake_up( &debug_ctx->obj, 0 );
238}
239
240/* find the next event that we can send to the debugger */
241static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx )
242{
243 struct debug_event *event;
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000244
245 LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000246 {
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000247 if (event->state == EVENT_SENT) continue; /* already sent */
248 if (event->sender->debug_event) continue; /* thread busy with another one */
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000249 return event;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000250 }
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000251 return NULL;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000252}
253
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000254static void debug_event_dump( struct object *obj, int verbose )
255{
256 struct debug_event *debug_event = (struct debug_event *)obj;
257 assert( obj->ops == &debug_event_ops );
258 fprintf( stderr, "Debug event sender=%p code=%d state=%d\n",
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000259 debug_event->sender, debug_event->data.code, debug_event->state );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000260}
261
262static int debug_event_signaled( struct object *obj, struct thread *thread )
263{
264 struct debug_event *debug_event = (struct debug_event *)obj;
265 assert( obj->ops == &debug_event_ops );
266 return debug_event->state == EVENT_CONTINUED;
267}
268
269static void debug_event_destroy( struct object *obj )
270{
271 struct debug_event *event = (struct debug_event *)obj;
272 assert( obj->ops == &debug_event_ops );
273
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000274 /* If the event has been sent already, the handles are now under the */
275 /* responsibility of the debugger process, so we don't touch them */
276 if (event->state == EVENT_QUEUED)
277 {
278 struct process *debugger = event->debugger->process;
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000279 switch(event->data.code)
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000280 {
281 case CREATE_THREAD_DEBUG_EVENT:
Alexandre Julliardd549f692000-12-22 02:04:15 +0000282 close_handle( debugger, event->data.info.create_thread.handle, NULL );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000283 break;
284 case CREATE_PROCESS_DEBUG_EVENT:
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000285 if (event->data.info.create_process.file)
Alexandre Julliardd549f692000-12-22 02:04:15 +0000286 close_handle( debugger, event->data.info.create_process.file, NULL );
287 close_handle( debugger, event->data.info.create_process.thread, NULL );
288 close_handle( debugger, event->data.info.create_process.process, NULL );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000289 break;
290 case LOAD_DLL_DEBUG_EVENT:
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000291 if (event->data.info.load_dll.handle)
Alexandre Julliardd549f692000-12-22 02:04:15 +0000292 close_handle( debugger, event->data.info.load_dll.handle, NULL );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000293 break;
294 }
295 }
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000296 if (event->sender->context == &event->context) event->sender->context = NULL;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000297 release_object( event->sender );
298 release_object( event->debugger );
299}
300
301static void debug_ctx_dump( struct object *obj, int verbose )
302{
303 struct debug_ctx *debug_ctx = (struct debug_ctx *)obj;
304 assert( obj->ops == &debug_ctx_ops );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000305 fprintf( stderr, "Debug context head=%p tail=%p\n",
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000306 debug_ctx->event_queue.next, debug_ctx->event_queue.prev );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000307}
308
309static int debug_ctx_signaled( struct object *obj, struct thread *thread )
310{
311 struct debug_ctx *debug_ctx = (struct debug_ctx *)obj;
312 assert( obj->ops == &debug_ctx_ops );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000313 return find_event_to_send( debug_ctx ) != NULL;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000314}
315
316static void debug_ctx_destroy( struct object *obj )
317{
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000318 struct list *ptr;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000319 struct debug_ctx *debug_ctx = (struct debug_ctx *)obj;
320 assert( obj->ops == &debug_ctx_ops );
321
322 /* free all pending events */
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000323 while ((ptr = list_head( &debug_ctx->event_queue )))
324 unlink_event( debug_ctx, LIST_ENTRY( ptr, struct debug_event, entry ));
Alexandre Julliarde712e071999-05-23 19:53:30 +0000325}
326
Alexandre Julliarde712e071999-05-23 19:53:30 +0000327/* continue a debug event */
328static int continue_debug_event( struct process *process, struct thread *thread, int status )
329{
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000330 struct debug_ctx *debug_ctx = current->debug_ctx;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000331
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000332 if (debug_ctx && process->debugger == current && thread->process == process)
Alexandre Julliard17cf8101999-11-24 01:22:14 +0000333 {
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000334 struct debug_event *event;
335
336 /* find the event in the queue */
337 LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry )
338 {
339 if (event->state != EVENT_SENT) continue;
340 if (event->sender == thread)
341 {
342 assert( event->sender->debug_event == event );
343
344 event->status = status;
345 event->state = EVENT_CONTINUED;
346 wake_up( &event->obj, 0 );
347 unlink_event( debug_ctx, event );
348 resume_process( process );
349 return 1;
350 }
351 }
Alexandre Julliard17cf8101999-11-24 01:22:14 +0000352 }
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000353 /* not debugging this process, or no such event */
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000354 set_error( STATUS_ACCESS_DENIED ); /* FIXME */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000355 return 0;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000356}
357
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000358/* alloc a debug event for a debugger */
359static struct debug_event *alloc_debug_event( struct thread *thread, int code,
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000360 void *arg, const CONTEXT *context )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000361{
Alexandre Julliardff81d782000-03-08 12:01:30 +0000362 struct thread *debugger = thread->process->debugger;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000363 struct debug_event *event;
364
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000365 assert( code > 0 && code <= NB_DEBUG_EVENTS );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000366 /* cannot queue a debug event for myself */
367 assert( debugger->process != thread->process );
368
369 /* build the event */
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000370 if (!(event = alloc_object( &debug_event_ops ))) return NULL;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000371 event->state = EVENT_QUEUED;
372 event->sender = (struct thread *)grab_object( thread );
373 event->debugger = (struct thread *)grab_object( debugger );
Alexandre Julliardff81d782000-03-08 12:01:30 +0000374 event->data.code = code;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000375
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000376 if (!fill_debug_event[code-1]( event, arg ))
Alexandre Julliarde712e071999-05-23 19:53:30 +0000377 {
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000378 event->data.code = -1; /* make sure we don't attempt to close handles */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000379 release_object( event );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000380 return NULL;
381 }
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000382 if (context)
383 {
384 memcpy( &event->context, context, sizeof(event->context) );
385 thread->context = &event->context;
386 }
Alexandre Julliarde712e071999-05-23 19:53:30 +0000387 return event;
388}
389
Alexandre Julliardff81d782000-03-08 12:01:30 +0000390/* generate a debug event from inside the server and queue it */
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000391void generate_debug_event( struct thread *thread, int code, void *arg )
Alexandre Julliardff81d782000-03-08 12:01:30 +0000392{
393 if (thread->process->debugger)
394 {
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000395 struct debug_event *event = alloc_debug_event( thread, code, arg, NULL );
396 if (event)
397 {
398 link_event( event );
399 suspend_process( thread->process );
400 release_object( event );
401 }
Alexandre Julliardff81d782000-03-08 12:01:30 +0000402 }
403}
404
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000405/* attach a process to a debugger thread and suspend it */
406static int debugger_attach( struct process *process, struct thread *debugger )
407{
408 struct thread *thread;
409
410 if (process->debugger) goto error; /* already being debugged */
Alexandre Julliard9d802152002-05-24 21:20:27 +0000411 if (!is_process_init_done( process )) goto error; /* still starting up */
Alexandre Julliard05026382005-03-01 10:56:18 +0000412 if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000413
414 /* make sure we don't create a debugging loop */
415 for (thread = debugger; thread; thread = thread->process->debugger)
416 if (thread->process == process) goto error;
417
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000418 /* don't let a debugger debug its console... won't work */
Eric Pouech3940d8a2001-12-04 20:17:43 +0000419 if (debugger->process->console && debugger->process->console->renderer->process == process)
420 goto error;
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000421
Alexandre Julliard5f258c62001-07-14 00:50:30 +0000422 suspend_process( process );
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000423 if (!attach_process( process ) || !set_process_debugger( process, debugger ))
Eric Pouechfbccb382002-02-27 01:28:30 +0000424 {
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000425 resume_process( process );
426 return 0;
Eric Pouechfbccb382002-02-27 01:28:30 +0000427 }
Alexandre Julliarde55d5932003-10-14 01:30:42 +0000428 if (!set_process_debug_flag( process, 1 ))
429 {
430 process->debugger = NULL;
431 resume_process( process );
432 return 0;
433 }
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000434 return 1;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000435
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000436 error:
437 set_error( STATUS_ACCESS_DENIED );
438 return 0;
439}
440
Eric Pouechfbccb382002-02-27 01:28:30 +0000441
442/* detach a process from a debugger thread (and resume it ?) */
443int debugger_detach( struct process *process, struct thread *debugger )
444{
Eric Pouechfbccb382002-02-27 01:28:30 +0000445 struct debug_event *event;
446 struct debug_ctx *debug_ctx;
447
448 if (!process->debugger || process->debugger != debugger)
449 goto error; /* not currently debugged, or debugged by another debugger */
450 if (!debugger->debug_ctx ) goto error; /* should be a debugger */
451 /* init should be done, otherwise wouldn't be attached */
Alexandre Julliard9d802152002-05-24 21:20:27 +0000452 assert(is_process_init_done(process));
Eric Pouechfbccb382002-02-27 01:28:30 +0000453
454 suspend_process( process );
455 /* send continue indication for all events */
456 debug_ctx = debugger->debug_ctx;
457
458 /* find the event in the queue
459 * FIXME: could loop on process' threads and look the debug_event field */
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000460 LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry )
Eric Pouechfbccb382002-02-27 01:28:30 +0000461 {
462 if (event->state != EVENT_QUEUED) continue;
463
464 if (event->sender->process == process)
465 {
466 assert( event->sender->debug_event == event );
467 event->status = DBG_CONTINUE;
468 event->state = EVENT_CONTINUED;
469 wake_up( &event->obj, 0 );
470 unlink_event( debug_ctx, event );
471 /* from queued debug event */
472 resume_process( process );
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000473 break;
Eric Pouechfbccb382002-02-27 01:28:30 +0000474 }
475 }
476
477 /* remove relationships between process and its debugger */
478 process->debugger = NULL;
Alexandre Julliarde55d5932003-10-14 01:30:42 +0000479 if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000480 detach_process( process );
Eric Pouechfbccb382002-02-27 01:28:30 +0000481
482 /* from this function */
483 resume_process( process );
484 return 0;
485
486 error:
487 set_error( STATUS_ACCESS_DENIED );
488 return 0;
489}
490
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000491/* generate all startup events of a given process */
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000492void generate_startup_debug_events( struct process *process, void *entry )
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000493{
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000494 struct list *ptr;
Alexandre Julliard05026382005-03-01 10:56:18 +0000495 struct thread *thread, *first_thread = get_process_first_thread( process );
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000496
497 /* generate creation events */
Alexandre Julliard05026382005-03-01 10:56:18 +0000498 LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
499 {
500 if (thread == first_thread)
501 generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT, entry );
502 else
503 generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, NULL );
504 }
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000505
506 /* generate dll events (in loading order, i.e. reverse list order) */
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000507 ptr = list_tail( &process->dlls );
508 while (ptr)
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000509 {
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000510 struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry );
Alexandre Julliard05026382005-03-01 10:56:18 +0000511 generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll );
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000512 ptr = list_prev( &process->dlls, ptr );
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000513 }
514}
515
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000516/* set the debugger of a given process */
517int set_process_debugger( struct process *process, struct thread *debugger )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000518{
519 struct debug_ctx *debug_ctx;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000520
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000521 assert( !process->debugger );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000522
523 if (!debugger->debug_ctx) /* need to allocate a context */
524 {
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000525 if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0;
Eric Pouechfbccb382002-02-27 01:28:30 +0000526 debug_ctx->kill_on_exit = 1;
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000527 list_init( &debug_ctx->event_queue );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000528 debugger->debug_ctx = debug_ctx;
529 }
Alexandre Julliard17cf8101999-11-24 01:22:14 +0000530 process->debugger = debugger;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000531 return 1;
532}
533
Alexandre Julliarde712e071999-05-23 19:53:30 +0000534/* a thread is exiting */
Alexandre Julliardff81d782000-03-08 12:01:30 +0000535void debug_exit_thread( struct thread *thread )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000536{
Alexandre Julliardff81d782000-03-08 12:01:30 +0000537 if (thread->debug_ctx) /* this thread is a debugger */
Alexandre Julliarde712e071999-05-23 19:53:30 +0000538 {
Eric Pouechfbccb382002-02-27 01:28:30 +0000539 if (thread->debug_ctx->kill_on_exit)
540 {
541 /* kill all debugged processes */
542 kill_debugged_processes( thread, thread->exit_code );
543 }
544 else
545 {
546 detach_debugged_processes( thread );
547 }
Alexandre Julliardff81d782000-03-08 12:01:30 +0000548 release_object( thread->debug_ctx );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000549 thread->debug_ctx = NULL;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000550 }
551}
552
553/* Wait for a debug event */
554DECL_HANDLER(wait_debug_event)
555{
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000556 struct debug_ctx *debug_ctx = current->debug_ctx;
557 struct debug_event *event;
558
559 if (!debug_ctx) /* current thread is not a debugger */
Alexandre Julliarde712e071999-05-23 19:53:30 +0000560 {
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000561 set_error( STATUS_INVALID_HANDLE );
562 return;
563 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000564 reply->wait = 0;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000565 if ((event = find_event_to_send( debug_ctx )))
566 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000567 size_t size = get_reply_max_size();
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000568 event->state = EVENT_SENT;
569 event->sender->debug_event = event;
Alexandre Julliard54f22872002-10-03 19:54:57 +0000570 reply->pid = get_process_id( event->sender->process );
571 reply->tid = get_thread_id( event->sender );
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000572 if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000573 set_reply_data( &event->data, size );
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000574 }
575 else /* no event ready */
576 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000577 reply->pid = 0;
578 reply->tid = 0;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000579 if (req->get_handle)
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000580 reply->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, FALSE );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000581 }
582}
583
584/* Continue a debug event */
585DECL_HANDLER(continue_debug_event)
586{
587 struct process *process = get_process_from_id( req->pid );
588 if (process)
589 {
590 struct thread *thread = get_thread_from_id( req->tid );
591 if (thread)
592 {
593 continue_debug_event( process, thread, req->status );
594 release_object( thread );
595 }
596 release_object( process );
597 }
Alexandre Julliarde712e071999-05-23 19:53:30 +0000598}
599
600/* Start debugging an existing process */
601DECL_HANDLER(debug_process)
602{
603 struct process *process = get_process_from_id( req->pid );
Alexandre Julliardff81d782000-03-08 12:01:30 +0000604 if (!process) return;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000605
Eric Pouechfbccb382002-02-27 01:28:30 +0000606 if (!req->attach)
Alexandre Julliarde712e071999-05-23 19:53:30 +0000607 {
Eric Pouechfbccb382002-02-27 01:28:30 +0000608 debugger_detach( process, current );
609 }
610 else if (debugger_attach( process, current ))
611 {
612 struct debug_event_exception data;
Alexandre Julliard05026382005-03-01 10:56:18 +0000613 struct thread *thread = get_process_first_thread( process );
Eric Pouechfbccb382002-02-27 01:28:30 +0000614
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000615 generate_startup_debug_events( process, NULL );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000616 resume_process( process );
617
618 data.record.ExceptionCode = EXCEPTION_BREAKPOINT;
619 data.record.ExceptionFlags = EXCEPTION_CONTINUABLE;
620 data.record.ExceptionRecord = NULL;
Alexandre Julliard05026382005-03-01 10:56:18 +0000621 data.record.ExceptionAddress = get_thread_ip( thread );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000622 data.record.NumberParameters = 0;
623 data.first = 1;
Alexandre Julliard05026382005-03-01 10:56:18 +0000624 generate_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000625 }
Alexandre Julliardff81d782000-03-08 12:01:30 +0000626 release_object( process );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000627}
628
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000629/* queue an exception event */
630DECL_HANDLER(queue_exception_event)
Alexandre Julliarde712e071999-05-23 19:53:30 +0000631{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000632 reply->handle = 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000633 if (current->process->debugger)
634 {
635 struct debug_event_exception data;
636 struct debug_event *event;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000637 const CONTEXT *context = get_req_data();
Eric Pouech0a258962004-11-30 21:38:57 +0000638 const EXCEPTION_RECORD *rec = (const EXCEPTION_RECORD *)(context + 1);
Alexandre Julliarde712e071999-05-23 19:53:30 +0000639
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000640 if (get_req_data_size() < sizeof(*rec) + sizeof(*context))
Alexandre Julliard92643002000-08-31 01:59:51 +0000641 {
642 set_error( STATUS_INVALID_PARAMETER );
643 return;
644 }
645 data.record = *rec;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000646 data.first = req->first;
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000647 if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000648 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000649 if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, FALSE )))
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000650 {
651 link_event( event );
652 suspend_process( current->process );
653 }
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000654 release_object( event );
655 }
Alexandre Julliarde712e071999-05-23 19:53:30 +0000656 }
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000657}
658
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000659/* retrieve the status of an exception event */
660DECL_HANDLER(get_exception_status)
661{
662 struct debug_event *event;
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000663
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000664 reply->status = 0;
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000665 if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle,
666 0, &debug_event_ops )))
667 {
668 if (event->state == EVENT_CONTINUED)
669 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000670 reply->status = event->status;
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000671 if (current->context == &event->context)
672 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000673 size_t size = min( sizeof(CONTEXT), get_reply_max_size() );
674 set_reply_data( &event->context, size );
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000675 current->context = NULL;
676 }
677 }
678 else set_error( STATUS_PENDING );
679 release_object( event );
680 }
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000681}
682
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000683/* send an output string to the debugger */
684DECL_HANDLER(output_debug_string)
685{
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000686 struct debug_event_output_string data;
687
688 data.string = req->string;
689 data.unicode = req->unicode;
690 data.length = req->length;
691 generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000692}
Eric Pouechfbccb382002-02-27 01:28:30 +0000693
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000694/* simulate a breakpoint in a process */
695DECL_HANDLER(debug_break)
696{
697 struct process *process;
698
699 reply->self = 0;
700 if (!(process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION /*FIXME*/ )))
701 return;
702 if (process != current->process)
703 {
704 /* find a suitable thread to signal */
705 struct thread *thread;
Alexandre Julliard05026382005-03-01 10:56:18 +0000706 LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000707 {
Alexandre Julliard05026382005-03-01 10:56:18 +0000708 if (send_thread_signal( thread, SIGTRAP )) goto done;
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000709 }
Alexandre Julliard05026382005-03-01 10:56:18 +0000710 set_error( STATUS_ACCESS_DENIED );
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000711 }
712 else reply->self = 1;
Alexandre Julliard05026382005-03-01 10:56:18 +0000713
714done:
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000715 release_object( process );
716}
717
Eric Pouechfbccb382002-02-27 01:28:30 +0000718/* set debugger kill on exit flag */
719DECL_HANDLER(set_debugger_kill_on_exit)
720{
721 if (!current->debug_ctx)
722 {
723 set_error( STATUS_ACCESS_DENIED );
724 return;
725 }
726 current->debug_ctx->kill_on_exit = req->kill_on_exit;
727}