blob: a64a17a7d8956931acc4a5f72f297f17c7db7d76 [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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010030#include "ntstatus.h"
31#define WIN32_NO_STATUS
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000032#include "windef.h"
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010033#include "winternl.h"
Alexandre Julliarde712e071999-05-23 19:53:30 +000034
Alexandre Julliarde712e071999-05-23 19:53:30 +000035#include "handle.h"
36#include "process.h"
37#include "thread.h"
Alexandre Julliard5bc78081999-06-22 17:26:53 +000038#include "request.h"
Alexandre Julliarde712e071999-05-23 19:53:30 +000039
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000040enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED };
41
42/* debug event */
Alexandre Julliarde712e071999-05-23 19:53:30 +000043struct debug_event
44{
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000045 struct object obj; /* object header */
Alexandre Julliardefdb4962005-02-26 17:45:29 +000046 struct list entry; /* entry in event queue */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000047 struct thread *sender; /* thread which sent this event */
48 struct thread *debugger; /* debugger thread receiving the event */
49 enum debug_event_state state; /* event state */
50 int status; /* continuation status */
Alexandre Julliard3e2517c2000-01-20 18:59:03 +000051 debug_event_t data; /* event data */
Alexandre Julliarde939eae2001-01-26 20:45:41 +000052 CONTEXT context; /* register context */
Alexandre Julliarde712e071999-05-23 19:53:30 +000053};
54
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000055/* debug context */
Alexandre Julliarde712e071999-05-23 19:53:30 +000056struct debug_ctx
57{
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000058 struct object obj; /* object header */
Alexandre Julliardefdb4962005-02-26 17:45:29 +000059 struct list event_queue; /* pending events queue */
Eric Pouechfbccb382002-02-27 01:28:30 +000060 int kill_on_exit;/* kill debuggees on debugger exit ? */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000061};
62
63
64static void debug_event_dump( struct object *obj, int verbose );
65static int debug_event_signaled( struct object *obj, struct thread *thread );
66static void debug_event_destroy( struct object *obj );
67
68static const struct object_ops debug_event_ops =
69{
70 sizeof(struct debug_event), /* size */
71 debug_event_dump, /* dump */
72 add_queue, /* add_queue */
73 remove_queue, /* remove_queue */
74 debug_event_signaled, /* signaled */
75 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000076 no_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +000077 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +010078 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +010079 default_get_sd, /* get_sd */
80 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +000081 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +010082 no_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +000083 no_close_handle, /* close_handle */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +000084 debug_event_destroy /* destroy */
85};
86
87static void debug_ctx_dump( struct object *obj, int verbose );
88static int debug_ctx_signaled( struct object *obj, struct thread *thread );
89static void debug_ctx_destroy( struct object *obj );
90
91static const struct object_ops debug_ctx_ops =
92{
93 sizeof(struct debug_ctx), /* size */
94 debug_ctx_dump, /* dump */
95 add_queue, /* add_queue */
96 remove_queue, /* remove_queue */
97 debug_ctx_signaled, /* signaled */
98 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000099 no_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +0000100 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100101 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100102 default_get_sd, /* get_sd */
103 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000104 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100105 no_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000106 no_close_handle, /* close_handle */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000107 debug_ctx_destroy /* destroy */
Alexandre Julliarde712e071999-05-23 19:53:30 +0000108};
109
Alexandre Julliarde712e071999-05-23 19:53:30 +0000110
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000111/* routines to build an event according to its type */
112
113static int fill_exception_event( struct debug_event *event, void *arg )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000114{
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000115 memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000116 return 1;
117}
118
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000119static int fill_create_thread_event( struct debug_event *event, void *arg )
120{
121 struct process *debugger = event->debugger->process;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000122 struct thread *thread = event->sender;
Alexandre Julliard51885742002-05-30 20:12:58 +0000123 obj_handle_t handle;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000124
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000125 /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
Alexandre Julliard24560e72005-12-09 13:58:25 +0100126 if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, 0 ))) return 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000127 event->data.info.create_thread.handle = handle;
128 event->data.info.create_thread.teb = thread->teb;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000129 event->data.info.create_thread.start = arg;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000130 return 1;
131}
132
133static int fill_create_process_event( struct debug_event *event, void *arg )
134{
135 struct process *debugger = event->debugger->process;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000136 struct thread *thread = event->sender;
137 struct process *process = thread->process;
Alexandre Julliarde6374cb2006-02-16 12:13:01 +0100138 struct process_dll *exe_module = get_process_exe_module( process );
Alexandre Julliard51885742002-05-30 20:12:58 +0000139 obj_handle_t handle;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000140
141 /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
Alexandre Julliard24560e72005-12-09 13:58:25 +0100142 if (!(handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, 0 ))) return 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000143 event->data.info.create_process.process = handle;
144
145 /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
Alexandre Julliard24560e72005-12-09 13:58:25 +0100146 if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, 0 )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000147 {
Alexandre Julliard8700c432006-11-02 20:52:05 +0100148 close_handle( debugger, event->data.info.create_process.process );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000149 return 0;
150 }
151 event->data.info.create_process.thread = handle;
152
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000153 handle = 0;
Alexandre Julliarde6374cb2006-02-16 12:13:01 +0100154 if (exe_module->file &&
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000155 /* the doc says write access too, but this doesn't seem a good idea */
Alexandre Julliarde6374cb2006-02-16 12:13:01 +0100156 !(handle = alloc_handle( debugger, exe_module->file, GENERIC_READ, 0 )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000157 {
Alexandre Julliard8700c432006-11-02 20:52:05 +0100158 close_handle( debugger, event->data.info.create_process.process );
159 close_handle( debugger, event->data.info.create_process.thread );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000160 return 0;
161 }
162 event->data.info.create_process.file = handle;
163 event->data.info.create_process.teb = thread->teb;
Alexandre Julliarde6374cb2006-02-16 12:13:01 +0100164 event->data.info.create_process.base = exe_module->base;
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000165 event->data.info.create_process.start = arg;
Alexandre Julliarde6374cb2006-02-16 12:13:01 +0100166 event->data.info.create_process.dbg_offset = exe_module->dbg_offset;
167 event->data.info.create_process.dbg_size = exe_module->dbg_size;
168 event->data.info.create_process.name = exe_module->name;
Alexandre Julliardc30cefb2003-09-30 01:04:19 +0000169 event->data.info.create_process.unicode = 1;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000170 return 1;
171}
172
173static int fill_exit_thread_event( struct debug_event *event, void *arg )
174{
175 struct thread *thread = arg;
176 event->data.info.exit.exit_code = thread->exit_code;
177 return 1;
178}
179
180static int fill_exit_process_event( struct debug_event *event, void *arg )
181{
182 struct process *process = arg;
183 event->data.info.exit.exit_code = process->exit_code;
184 return 1;
185}
186
187static int fill_load_dll_event( struct debug_event *event, void *arg )
188{
189 struct process *debugger = event->debugger->process;
190 struct process_dll *dll = arg;
Alexandre Julliard51885742002-05-30 20:12:58 +0000191 obj_handle_t handle = 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000192
Alexandre Julliard24560e72005-12-09 13:58:25 +0100193 if (dll->file && !(handle = alloc_handle( debugger, dll->file, GENERIC_READ, 0 )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000194 return 0;
195 event->data.info.load_dll.handle = handle;
196 event->data.info.load_dll.base = dll->base;
197 event->data.info.load_dll.dbg_offset = dll->dbg_offset;
198 event->data.info.load_dll.dbg_size = dll->dbg_size;
199 event->data.info.load_dll.name = dll->name;
Alexandre Julliardc30cefb2003-09-30 01:04:19 +0000200 event->data.info.load_dll.unicode = 1;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000201 return 1;
202}
203
204static int fill_unload_dll_event( struct debug_event *event, void *arg )
205{
206 event->data.info.unload_dll.base = arg;
207 return 1;
208}
209
210static int fill_output_debug_string_event( struct debug_event *event, void *arg )
211{
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000212 struct debug_event_output_string *data = arg;
213 event->data.info.output_string = *data;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000214 return 1;
215}
216
217typedef int (*fill_event_func)( struct debug_event *event, void *arg );
218
219#define NB_DEBUG_EVENTS OUTPUT_DEBUG_STRING_EVENT /* RIP_EVENT not supported */
220
221static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] =
222{
223 fill_exception_event, /* EXCEPTION_DEBUG_EVENT */
224 fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */
225 fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */
226 fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */
227 fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */
228 fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */
229 fill_unload_dll_event, /* UNLOAD_DLL_DEBUG_EVENT */
230 fill_output_debug_string_event /* OUTPUT_DEBUG_STRING_EVENT */
231};
232
233
Alexandre Julliarde712e071999-05-23 19:53:30 +0000234/* unlink the first event from the queue */
235static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event )
236{
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000237 list_remove( &event->entry );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000238 if (event->sender->debug_event == event) event->sender->debug_event = NULL;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000239 release_object( event );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000240}
241
242/* link an event at the end of the queue */
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000243static void link_event( struct debug_event *event )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000244{
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000245 struct debug_ctx *debug_ctx = event->debugger->debug_ctx;
246
247 assert( debug_ctx );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000248 grab_object( event );
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000249 list_add_tail( &debug_ctx->event_queue, &event->entry );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000250 if (!event->sender->debug_event) wake_up( &debug_ctx->obj, 0 );
251}
252
253/* find the next event that we can send to the debugger */
254static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx )
255{
256 struct debug_event *event;
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000257
258 LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000259 {
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000260 if (event->state == EVENT_SENT) continue; /* already sent */
261 if (event->sender->debug_event) continue; /* thread busy with another one */
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000262 return event;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000263 }
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000264 return NULL;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000265}
266
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000267static void debug_event_dump( struct object *obj, int verbose )
268{
269 struct debug_event *debug_event = (struct debug_event *)obj;
270 assert( obj->ops == &debug_event_ops );
271 fprintf( stderr, "Debug event sender=%p code=%d state=%d\n",
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000272 debug_event->sender, debug_event->data.code, debug_event->state );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000273}
274
275static int debug_event_signaled( struct object *obj, struct thread *thread )
276{
277 struct debug_event *debug_event = (struct debug_event *)obj;
278 assert( obj->ops == &debug_event_ops );
279 return debug_event->state == EVENT_CONTINUED;
280}
281
282static void debug_event_destroy( struct object *obj )
283{
284 struct debug_event *event = (struct debug_event *)obj;
285 assert( obj->ops == &debug_event_ops );
286
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000287 /* If the event has been sent already, the handles are now under the */
288 /* responsibility of the debugger process, so we don't touch them */
289 if (event->state == EVENT_QUEUED)
290 {
291 struct process *debugger = event->debugger->process;
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000292 switch(event->data.code)
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000293 {
294 case CREATE_THREAD_DEBUG_EVENT:
Alexandre Julliard8700c432006-11-02 20:52:05 +0100295 close_handle( debugger, event->data.info.create_thread.handle );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000296 break;
297 case CREATE_PROCESS_DEBUG_EVENT:
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000298 if (event->data.info.create_process.file)
Alexandre Julliard8700c432006-11-02 20:52:05 +0100299 close_handle( debugger, event->data.info.create_process.file );
300 close_handle( debugger, event->data.info.create_process.thread );
301 close_handle( debugger, event->data.info.create_process.process );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000302 break;
303 case LOAD_DLL_DEBUG_EVENT:
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000304 if (event->data.info.load_dll.handle)
Alexandre Julliard8700c432006-11-02 20:52:05 +0100305 close_handle( debugger, event->data.info.load_dll.handle );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000306 break;
307 }
308 }
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000309 if (event->sender->context == &event->context) event->sender->context = NULL;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000310 release_object( event->sender );
311 release_object( event->debugger );
312}
313
314static void debug_ctx_dump( struct object *obj, int verbose )
315{
316 struct debug_ctx *debug_ctx = (struct debug_ctx *)obj;
317 assert( obj->ops == &debug_ctx_ops );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000318 fprintf( stderr, "Debug context head=%p tail=%p\n",
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000319 debug_ctx->event_queue.next, debug_ctx->event_queue.prev );
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000320}
321
322static int debug_ctx_signaled( struct object *obj, struct thread *thread )
323{
324 struct debug_ctx *debug_ctx = (struct debug_ctx *)obj;
325 assert( obj->ops == &debug_ctx_ops );
Alexandre Julliardf6507ed2000-04-06 22:05:16 +0000326 return find_event_to_send( debug_ctx ) != NULL;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000327}
328
329static void debug_ctx_destroy( struct object *obj )
330{
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000331 struct list *ptr;
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000332 struct debug_ctx *debug_ctx = (struct debug_ctx *)obj;
333 assert( obj->ops == &debug_ctx_ops );
334
335 /* free all pending events */
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000336 while ((ptr = list_head( &debug_ctx->event_queue )))
337 unlink_event( debug_ctx, LIST_ENTRY( ptr, struct debug_event, entry ));
Alexandre Julliarde712e071999-05-23 19:53:30 +0000338}
339
Alexandre Julliarde712e071999-05-23 19:53:30 +0000340/* continue a debug event */
341static int continue_debug_event( struct process *process, struct thread *thread, int status )
342{
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000343 struct debug_ctx *debug_ctx = current->debug_ctx;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000344
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000345 if (debug_ctx && process->debugger == current && thread->process == process)
Alexandre Julliard17cf8101999-11-24 01:22:14 +0000346 {
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000347 struct debug_event *event;
348
349 /* find the event in the queue */
350 LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry )
351 {
352 if (event->state != EVENT_SENT) continue;
353 if (event->sender == thread)
354 {
355 assert( event->sender->debug_event == event );
356
357 event->status = status;
358 event->state = EVENT_CONTINUED;
359 wake_up( &event->obj, 0 );
360 unlink_event( debug_ctx, event );
361 resume_process( process );
362 return 1;
363 }
364 }
Alexandre Julliard17cf8101999-11-24 01:22:14 +0000365 }
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000366 /* not debugging this process, or no such event */
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000367 set_error( STATUS_ACCESS_DENIED ); /* FIXME */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000368 return 0;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000369}
370
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000371/* alloc a debug event for a debugger */
372static struct debug_event *alloc_debug_event( struct thread *thread, int code,
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000373 void *arg, const CONTEXT *context )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000374{
Alexandre Julliardff81d782000-03-08 12:01:30 +0000375 struct thread *debugger = thread->process->debugger;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000376 struct debug_event *event;
377
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000378 assert( code > 0 && code <= NB_DEBUG_EVENTS );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000379 /* cannot queue a debug event for myself */
380 assert( debugger->process != thread->process );
381
382 /* build the event */
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000383 if (!(event = alloc_object( &debug_event_ops ))) return NULL;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000384 event->state = EVENT_QUEUED;
385 event->sender = (struct thread *)grab_object( thread );
386 event->debugger = (struct thread *)grab_object( debugger );
Alexandre Julliardff81d782000-03-08 12:01:30 +0000387 event->data.code = code;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000388
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000389 if (!fill_debug_event[code-1]( event, arg ))
Alexandre Julliarde712e071999-05-23 19:53:30 +0000390 {
Alexandre Julliard3e2517c2000-01-20 18:59:03 +0000391 event->data.code = -1; /* make sure we don't attempt to close handles */
Alexandre Julliard79b1ec82000-01-04 02:24:43 +0000392 release_object( event );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000393 return NULL;
394 }
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000395 if (context)
396 {
397 memcpy( &event->context, context, sizeof(event->context) );
398 thread->context = &event->context;
399 }
Alexandre Julliarde712e071999-05-23 19:53:30 +0000400 return event;
401}
402
Alexandre Julliardff81d782000-03-08 12:01:30 +0000403/* generate a debug event from inside the server and queue it */
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000404void generate_debug_event( struct thread *thread, int code, void *arg )
Alexandre Julliardff81d782000-03-08 12:01:30 +0000405{
406 if (thread->process->debugger)
407 {
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000408 struct debug_event *event = alloc_debug_event( thread, code, arg, NULL );
409 if (event)
410 {
411 link_event( event );
412 suspend_process( thread->process );
413 release_object( event );
414 }
Alexandre Julliardff81d782000-03-08 12:01:30 +0000415 }
416}
417
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000418/* attach a process to a debugger thread and suspend it */
419static int debugger_attach( struct process *process, struct thread *debugger )
420{
421 struct thread *thread;
422
423 if (process->debugger) goto error; /* already being debugged */
Alexandre Julliard9d802152002-05-24 21:20:27 +0000424 if (!is_process_init_done( process )) goto error; /* still starting up */
Alexandre Julliard05026382005-03-01 10:56:18 +0000425 if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000426
427 /* make sure we don't create a debugging loop */
428 for (thread = debugger; thread; thread = thread->process->debugger)
429 if (thread->process == process) goto error;
430
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000431 /* don't let a debugger debug its console... won't work */
Alexandre Julliard627ca402007-05-11 12:46:32 +0200432 if (debugger->process->console && console_get_renderer(debugger->process->console)->process == process)
Eric Pouech3940d8a2001-12-04 20:17:43 +0000433 goto error;
Eric Pouech0b83d4c2001-11-23 23:04:58 +0000434
Alexandre Julliard5f258c62001-07-14 00:50:30 +0000435 suspend_process( process );
Alexandre Julliard820c5922006-04-10 20:25:22 +0200436 if (!set_process_debugger( process, debugger ))
Eric Pouechfbccb382002-02-27 01:28:30 +0000437 {
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000438 resume_process( process );
439 return 0;
Eric Pouechfbccb382002-02-27 01:28:30 +0000440 }
Alexandre Julliarde55d5932003-10-14 01:30:42 +0000441 if (!set_process_debug_flag( process, 1 ))
442 {
443 process->debugger = NULL;
444 resume_process( process );
445 return 0;
446 }
Alexandre Julliardbaf0a062003-03-11 01:48:53 +0000447 return 1;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000448
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000449 error:
450 set_error( STATUS_ACCESS_DENIED );
451 return 0;
452}
453
Eric Pouechfbccb382002-02-27 01:28:30 +0000454
455/* detach a process from a debugger thread (and resume it ?) */
456int debugger_detach( struct process *process, struct thread *debugger )
457{
Alexandre Julliard9c18d922007-08-30 19:47:43 +0200458 struct debug_event *event, *next;
Eric Pouechfbccb382002-02-27 01:28:30 +0000459 struct debug_ctx *debug_ctx;
460
461 if (!process->debugger || process->debugger != debugger)
462 goto error; /* not currently debugged, or debugged by another debugger */
463 if (!debugger->debug_ctx ) goto error; /* should be a debugger */
464 /* init should be done, otherwise wouldn't be attached */
Alexandre Julliard9d802152002-05-24 21:20:27 +0000465 assert(is_process_init_done(process));
Eric Pouechfbccb382002-02-27 01:28:30 +0000466
467 suspend_process( process );
468 /* send continue indication for all events */
469 debug_ctx = debugger->debug_ctx;
470
Alexandre Julliard9c18d922007-08-30 19:47:43 +0200471 /* free all events from this process */
472 LIST_FOR_EACH_ENTRY_SAFE( event, next, &debug_ctx->event_queue, struct debug_event, entry )
Eric Pouechfbccb382002-02-27 01:28:30 +0000473 {
Alexandre Julliard9c18d922007-08-30 19:47:43 +0200474 if (event->sender->process != process) continue;
Eric Pouechfbccb382002-02-27 01:28:30 +0000475
Alexandre Julliard9c18d922007-08-30 19:47:43 +0200476 assert( event->state != EVENT_CONTINUED );
477 event->status = DBG_CONTINUE;
478 event->state = EVENT_CONTINUED;
479 wake_up( &event->obj, 0 );
480 unlink_event( debug_ctx, event );
481 /* from queued debug event */
482 resume_process( process );
Eric Pouechfbccb382002-02-27 01:28:30 +0000483 }
484
485 /* remove relationships between process and its debugger */
486 process->debugger = NULL;
Alexandre Julliarde55d5932003-10-14 01:30:42 +0000487 if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */
Eric Pouechfbccb382002-02-27 01:28:30 +0000488
489 /* from this function */
490 resume_process( process );
491 return 0;
492
493 error:
494 set_error( STATUS_ACCESS_DENIED );
495 return 0;
496}
497
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000498/* generate all startup events of a given process */
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000499void generate_startup_debug_events( struct process *process, void *entry )
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000500{
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000501 struct list *ptr;
Alexandre Julliard05026382005-03-01 10:56:18 +0000502 struct thread *thread, *first_thread = get_process_first_thread( process );
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000503
504 /* generate creation events */
Alexandre Julliard05026382005-03-01 10:56:18 +0000505 LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
506 {
507 if (thread == first_thread)
508 generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT, entry );
509 else
510 generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, NULL );
511 }
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000512
513 /* generate dll events (in loading order, i.e. reverse list order) */
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000514 ptr = list_tail( &process->dlls );
515 while (ptr)
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000516 {
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000517 struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry );
Alexandre Julliard05026382005-03-01 10:56:18 +0000518 generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll );
Alexandre Julliarda9e0fb12005-03-02 10:20:09 +0000519 ptr = list_prev( &process->dlls, ptr );
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000520 }
521}
522
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000523/* set the debugger of a given process */
524int set_process_debugger( struct process *process, struct thread *debugger )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000525{
526 struct debug_ctx *debug_ctx;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000527
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000528 assert( !process->debugger );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000529
530 if (!debugger->debug_ctx) /* need to allocate a context */
531 {
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000532 if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0;
Eric Pouechfbccb382002-02-27 01:28:30 +0000533 debug_ctx->kill_on_exit = 1;
Alexandre Julliardefdb4962005-02-26 17:45:29 +0000534 list_init( &debug_ctx->event_queue );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000535 debugger->debug_ctx = debug_ctx;
536 }
Alexandre Julliard17cf8101999-11-24 01:22:14 +0000537 process->debugger = debugger;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000538 return 1;
539}
540
Alexandre Julliarde712e071999-05-23 19:53:30 +0000541/* a thread is exiting */
Alexandre Julliardff81d782000-03-08 12:01:30 +0000542void debug_exit_thread( struct thread *thread )
Alexandre Julliarde712e071999-05-23 19:53:30 +0000543{
Alexandre Julliardff81d782000-03-08 12:01:30 +0000544 if (thread->debug_ctx) /* this thread is a debugger */
Alexandre Julliarde712e071999-05-23 19:53:30 +0000545 {
Eric Pouechfbccb382002-02-27 01:28:30 +0000546 if (thread->debug_ctx->kill_on_exit)
547 {
548 /* kill all debugged processes */
Francois Gougetb6aa2472007-08-31 02:35:54 +0200549 kill_debugged_processes( thread, STATUS_DEBUGGER_INACTIVE );
Eric Pouechfbccb382002-02-27 01:28:30 +0000550 }
551 else
552 {
553 detach_debugged_processes( thread );
554 }
Alexandre Julliardff81d782000-03-08 12:01:30 +0000555 release_object( thread->debug_ctx );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000556 thread->debug_ctx = NULL;
Alexandre Julliarde712e071999-05-23 19:53:30 +0000557 }
558}
559
560/* Wait for a debug event */
561DECL_HANDLER(wait_debug_event)
562{
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000563 struct debug_ctx *debug_ctx = current->debug_ctx;
564 struct debug_event *event;
565
566 if (!debug_ctx) /* current thread is not a debugger */
Alexandre Julliarde712e071999-05-23 19:53:30 +0000567 {
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000568 set_error( STATUS_INVALID_HANDLE );
569 return;
570 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000571 reply->wait = 0;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000572 if ((event = find_event_to_send( debug_ctx )))
573 {
Alexandre Julliard0f273c12006-07-26 10:43:25 +0200574 data_size_t size = get_reply_max_size();
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000575 event->state = EVENT_SENT;
576 event->sender->debug_event = event;
Alexandre Julliard54f22872002-10-03 19:54:57 +0000577 reply->pid = get_process_id( event->sender->process );
578 reply->tid = get_thread_id( event->sender );
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000579 if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000580 set_reply_data( &event->data, size );
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000581 }
582 else /* no event ready */
583 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000584 reply->pid = 0;
585 reply->tid = 0;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000586 if (req->get_handle)
Alexandre Julliard24560e72005-12-09 13:58:25 +0100587 reply->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, 0 );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000588 }
589}
590
591/* Continue a debug event */
592DECL_HANDLER(continue_debug_event)
593{
594 struct process *process = get_process_from_id( req->pid );
595 if (process)
596 {
597 struct thread *thread = get_thread_from_id( req->tid );
598 if (thread)
599 {
600 continue_debug_event( process, thread, req->status );
601 release_object( thread );
602 }
603 release_object( process );
604 }
Alexandre Julliarde712e071999-05-23 19:53:30 +0000605}
606
607/* Start debugging an existing process */
608DECL_HANDLER(debug_process)
609{
610 struct process *process = get_process_from_id( req->pid );
Alexandre Julliardff81d782000-03-08 12:01:30 +0000611 if (!process) return;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000612
Eric Pouechfbccb382002-02-27 01:28:30 +0000613 if (!req->attach)
Alexandre Julliarde712e071999-05-23 19:53:30 +0000614 {
Eric Pouechfbccb382002-02-27 01:28:30 +0000615 debugger_detach( process, current );
616 }
617 else if (debugger_attach( process, current ))
618 {
Alexandre Julliardb73421d2000-03-30 19:30:24 +0000619 generate_startup_debug_events( process, NULL );
Alexandre Julliard17de8292006-04-19 19:45:39 +0200620 break_process( process );
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000621 resume_process( process );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000622 }
Alexandre Julliardff81d782000-03-08 12:01:30 +0000623 release_object( process );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000624}
625
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000626/* queue an exception event */
627DECL_HANDLER(queue_exception_event)
Alexandre Julliarde712e071999-05-23 19:53:30 +0000628{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000629 reply->handle = 0;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000630 if (current->process->debugger)
631 {
632 struct debug_event_exception data;
633 struct debug_event *event;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000634 const CONTEXT *context = get_req_data();
Eric Pouech0a258962004-11-30 21:38:57 +0000635 const EXCEPTION_RECORD *rec = (const EXCEPTION_RECORD *)(context + 1);
Alexandre Julliarde712e071999-05-23 19:53:30 +0000636
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000637 if (get_req_data_size() < sizeof(*rec) + sizeof(*context))
Alexandre Julliard92643002000-08-31 01:59:51 +0000638 {
639 set_error( STATUS_INVALID_PARAMETER );
640 return;
641 }
642 data.record = *rec;
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000643 data.first = req->first;
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000644 if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context )))
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000645 {
Alexandre Julliard24560e72005-12-09 13:58:25 +0100646 if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, 0 )))
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000647 {
648 link_event( event );
649 suspend_process( current->process );
650 }
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000651 release_object( event );
652 }
Alexandre Julliarde712e071999-05-23 19:53:30 +0000653 }
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000654}
655
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000656/* retrieve the status of an exception event */
657DECL_HANDLER(get_exception_status)
658{
659 struct debug_event *event;
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000660
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000661 if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle,
662 0, &debug_event_ops )))
663 {
Alexandre Julliard8700c432006-11-02 20:52:05 +0100664 close_handle( current->process, req->handle );
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000665 if (event->state == EVENT_CONTINUED)
666 {
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000667 if (current->context == &event->context)
668 {
Alexandre Julliard0f273c12006-07-26 10:43:25 +0200669 data_size_t size = min( sizeof(CONTEXT), get_reply_max_size() );
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000670 set_reply_data( &event->context, size );
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000671 current->context = NULL;
672 }
Alexandre Julliardff7795e2005-11-01 21:47:07 +0000673 set_error( event->status );
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000674 }
675 else set_error( STATUS_PENDING );
676 release_object( event );
677 }
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000678}
679
Alexandre Julliardea0d0282000-03-10 22:16:10 +0000680/* send an output string to the debugger */
681DECL_HANDLER(output_debug_string)
682{
Alexandre Julliarde939eae2001-01-26 20:45:41 +0000683 struct debug_event_output_string data;
684
685 data.string = req->string;
686 data.unicode = req->unicode;
687 data.length = req->length;
688 generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data );
Alexandre Julliarde712e071999-05-23 19:53:30 +0000689}
Eric Pouechfbccb382002-02-27 01:28:30 +0000690
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000691/* simulate a breakpoint in a process */
692DECL_HANDLER(debug_break)
693{
694 struct process *process;
695
696 reply->self = 0;
Alexandre Julliard17de8292006-04-19 19:45:39 +0200697 if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION /*FIXME*/ )))
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000698 {
Alexandre Julliard17de8292006-04-19 19:45:39 +0200699 if (process != current->process) break_process( process );
700 else reply->self = 1;
701 release_object( process );
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000702 }
Alexandre Julliard3c4538c2002-02-27 01:55:02 +0000703}
704
Eric Pouechfbccb382002-02-27 01:28:30 +0000705/* set debugger kill on exit flag */
706DECL_HANDLER(set_debugger_kill_on_exit)
707{
708 if (!current->debug_ctx)
709 {
710 set_error( STATUS_ACCESS_DENIED );
711 return;
712 }
713 current->debug_ctx->kill_on_exit = req->kill_on_exit;
714}