Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Server-side debugger functions |
| 3 | * |
| 4 | * Copyright (C) 1999 Alexandre Julliard |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 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 |
Jonathan Ernst | 360a3f9 | 2006-05-18 14:49:52 +0200 | [diff] [blame] | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 19 | */ |
| 20 | |
Alexandre Julliard | 5769d1d | 2002-04-26 19:05:15 +0000 | [diff] [blame] | 21 | #include "config.h" |
| 22 | #include "wine/port.h" |
| 23 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 24 | #include <assert.h> |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 25 | #include <signal.h> |
Patrik Stridvall | 2c68408 | 1999-07-31 17:36:48 +0000 | [diff] [blame] | 26 | #include <string.h> |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 27 | #include <stdarg.h> |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 28 | #include <stdio.h> |
Patrik Stridvall | 2c68408 | 1999-07-31 17:36:48 +0000 | [diff] [blame] | 29 | |
Ge van Geldorp | 1a1583a | 2005-11-28 17:32:54 +0100 | [diff] [blame] | 30 | #include "ntstatus.h" |
| 31 | #define WIN32_NO_STATUS |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 32 | #include "windef.h" |
Ge van Geldorp | 1a1583a | 2005-11-28 17:32:54 +0100 | [diff] [blame] | 33 | #include "winternl.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 34 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 35 | #include "handle.h" |
| 36 | #include "process.h" |
| 37 | #include "thread.h" |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 38 | #include "request.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 39 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 40 | enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED }; |
| 41 | |
| 42 | /* debug event */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 43 | struct debug_event |
| 44 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 45 | struct object obj; /* object header */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 46 | struct list entry; /* entry in event queue */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 47 | 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 Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 51 | debug_event_t data; /* event data */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 52 | CONTEXT context; /* register context */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 53 | }; |
| 54 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 55 | /* debug context */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 56 | struct debug_ctx |
| 57 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 58 | struct object obj; /* object header */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 59 | struct list event_queue; /* pending events queue */ |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 60 | int kill_on_exit;/* kill debuggees on debugger exit ? */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 61 | }; |
| 62 | |
| 63 | |
| 64 | static void debug_event_dump( struct object *obj, int verbose ); |
| 65 | static int debug_event_signaled( struct object *obj, struct thread *thread ); |
| 66 | static void debug_event_destroy( struct object *obj ); |
| 67 | |
| 68 | static 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 McCormack | f92fff6 | 2005-04-24 17:35:52 +0000 | [diff] [blame] | 76 | no_signal, /* signal */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 77 | no_get_fd, /* get_fd */ |
Alexandre Julliard | 28beba3 | 2005-12-12 14:57:40 +0100 | [diff] [blame] | 78 | no_map_access, /* map_access */ |
Rob Shearman | c1707d8 | 2007-10-03 13:10:37 +0100 | [diff] [blame] | 79 | default_get_sd, /* get_sd */ |
| 80 | default_set_sd, /* set_sd */ |
Vitaliy Margolen | baffcb9 | 2005-11-22 14:55:42 +0000 | [diff] [blame] | 81 | no_lookup_name, /* lookup_name */ |
Alexandre Julliard | 7e71c1d | 2007-03-22 11:44:29 +0100 | [diff] [blame] | 82 | no_open_file, /* open_file */ |
Alexandre Julliard | b9b1ea9 | 2005-06-09 15:39:52 +0000 | [diff] [blame] | 83 | no_close_handle, /* close_handle */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 84 | debug_event_destroy /* destroy */ |
| 85 | }; |
| 86 | |
| 87 | static void debug_ctx_dump( struct object *obj, int verbose ); |
| 88 | static int debug_ctx_signaled( struct object *obj, struct thread *thread ); |
| 89 | static void debug_ctx_destroy( struct object *obj ); |
| 90 | |
| 91 | static 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 McCormack | f92fff6 | 2005-04-24 17:35:52 +0000 | [diff] [blame] | 99 | no_signal, /* signal */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 100 | no_get_fd, /* get_fd */ |
Alexandre Julliard | 28beba3 | 2005-12-12 14:57:40 +0100 | [diff] [blame] | 101 | no_map_access, /* map_access */ |
Rob Shearman | c1707d8 | 2007-10-03 13:10:37 +0100 | [diff] [blame] | 102 | default_get_sd, /* get_sd */ |
| 103 | default_set_sd, /* set_sd */ |
Vitaliy Margolen | baffcb9 | 2005-11-22 14:55:42 +0000 | [diff] [blame] | 104 | no_lookup_name, /* lookup_name */ |
Alexandre Julliard | 7e71c1d | 2007-03-22 11:44:29 +0100 | [diff] [blame] | 105 | no_open_file, /* open_file */ |
Alexandre Julliard | b9b1ea9 | 2005-06-09 15:39:52 +0000 | [diff] [blame] | 106 | no_close_handle, /* close_handle */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 107 | debug_ctx_destroy /* destroy */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 108 | }; |
| 109 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 110 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 111 | /* routines to build an event according to its type */ |
| 112 | |
| 113 | static int fill_exception_event( struct debug_event *event, void *arg ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 114 | { |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 115 | memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 116 | return 1; |
| 117 | } |
| 118 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 119 | static int fill_create_thread_event( struct debug_event *event, void *arg ) |
| 120 | { |
| 121 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 122 | struct thread *thread = event->sender; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 123 | obj_handle_t handle; |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 124 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 125 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 126 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, 0 ))) return 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 127 | event->data.info.create_thread.handle = handle; |
| 128 | event->data.info.create_thread.teb = thread->teb; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 129 | event->data.info.create_thread.start = arg; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 130 | return 1; |
| 131 | } |
| 132 | |
| 133 | static int fill_create_process_event( struct debug_event *event, void *arg ) |
| 134 | { |
| 135 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 136 | struct thread *thread = event->sender; |
| 137 | struct process *process = thread->process; |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 138 | struct process_dll *exe_module = get_process_exe_module( process ); |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 139 | obj_handle_t handle; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 140 | |
| 141 | /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 142 | if (!(handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, 0 ))) return 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 143 | event->data.info.create_process.process = handle; |
| 144 | |
| 145 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 146 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, 0 ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 147 | { |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 148 | close_handle( debugger, event->data.info.create_process.process ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 149 | return 0; |
| 150 | } |
| 151 | event->data.info.create_process.thread = handle; |
| 152 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 153 | handle = 0; |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 154 | if (exe_module->file && |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 155 | /* the doc says write access too, but this doesn't seem a good idea */ |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 156 | !(handle = alloc_handle( debugger, exe_module->file, GENERIC_READ, 0 ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 157 | { |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 158 | close_handle( debugger, event->data.info.create_process.process ); |
| 159 | close_handle( debugger, event->data.info.create_process.thread ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 160 | return 0; |
| 161 | } |
| 162 | event->data.info.create_process.file = handle; |
| 163 | event->data.info.create_process.teb = thread->teb; |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 164 | event->data.info.create_process.base = exe_module->base; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 165 | event->data.info.create_process.start = arg; |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 166 | 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 Julliard | c30cefb | 2003-09-30 01:04:19 +0000 | [diff] [blame] | 169 | event->data.info.create_process.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 170 | return 1; |
| 171 | } |
| 172 | |
| 173 | static 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 | |
| 180 | static 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 | |
| 187 | static 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 Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 191 | obj_handle_t handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 192 | |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 193 | if (dll->file && !(handle = alloc_handle( debugger, dll->file, GENERIC_READ, 0 ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 194 | 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 Julliard | c30cefb | 2003-09-30 01:04:19 +0000 | [diff] [blame] | 200 | event->data.info.load_dll.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 201 | return 1; |
| 202 | } |
| 203 | |
| 204 | static 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 | |
| 210 | static int fill_output_debug_string_event( struct debug_event *event, void *arg ) |
| 211 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 212 | struct debug_event_output_string *data = arg; |
| 213 | event->data.info.output_string = *data; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 214 | return 1; |
| 215 | } |
| 216 | |
| 217 | typedef 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 | |
| 221 | static 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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 234 | /* unlink the first event from the queue */ |
| 235 | static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) |
| 236 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 237 | list_remove( &event->entry ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 238 | if (event->sender->debug_event == event) event->sender->debug_event = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 239 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | /* link an event at the end of the queue */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 243 | static void link_event( struct debug_event *event ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 244 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 245 | struct debug_ctx *debug_ctx = event->debugger->debug_ctx; |
| 246 | |
| 247 | assert( debug_ctx ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 248 | grab_object( event ); |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 249 | list_add_tail( &debug_ctx->event_queue, &event->entry ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 250 | 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 */ |
| 254 | static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx ) |
| 255 | { |
| 256 | struct debug_event *event; |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 257 | |
| 258 | LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 259 | { |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 260 | if (event->state == EVENT_SENT) continue; /* already sent */ |
| 261 | if (event->sender->debug_event) continue; /* thread busy with another one */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 262 | return event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 263 | } |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 264 | return NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 265 | } |
| 266 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 267 | static 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 Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 272 | debug_event->sender, debug_event->data.code, debug_event->state ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 273 | } |
| 274 | |
| 275 | static 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 | |
| 282 | static 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 Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 287 | /* 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 Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 292 | switch(event->data.code) |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 293 | { |
| 294 | case CREATE_THREAD_DEBUG_EVENT: |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 295 | close_handle( debugger, event->data.info.create_thread.handle ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 296 | break; |
| 297 | case CREATE_PROCESS_DEBUG_EVENT: |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 298 | if (event->data.info.create_process.file) |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 299 | 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 Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 302 | break; |
| 303 | case LOAD_DLL_DEBUG_EVENT: |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 304 | if (event->data.info.load_dll.handle) |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 305 | close_handle( debugger, event->data.info.load_dll.handle ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 306 | break; |
| 307 | } |
| 308 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 309 | if (event->sender->context == &event->context) event->sender->context = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 310 | release_object( event->sender ); |
| 311 | release_object( event->debugger ); |
| 312 | } |
| 313 | |
| 314 | static 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 Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 318 | fprintf( stderr, "Debug context head=%p tail=%p\n", |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 319 | debug_ctx->event_queue.next, debug_ctx->event_queue.prev ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 320 | } |
| 321 | |
| 322 | static 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 Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 326 | return find_event_to_send( debug_ctx ) != NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | static void debug_ctx_destroy( struct object *obj ) |
| 330 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 331 | struct list *ptr; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 332 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 333 | assert( obj->ops == &debug_ctx_ops ); |
| 334 | |
| 335 | /* free all pending events */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 336 | while ((ptr = list_head( &debug_ctx->event_queue ))) |
| 337 | unlink_event( debug_ctx, LIST_ENTRY( ptr, struct debug_event, entry )); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 338 | } |
| 339 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 340 | /* continue a debug event */ |
| 341 | static int continue_debug_event( struct process *process, struct thread *thread, int status ) |
| 342 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 343 | struct debug_ctx *debug_ctx = current->debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 344 | |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 345 | if (debug_ctx && process->debugger == current && thread->process == process) |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 346 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 347 | 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 Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 365 | } |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 366 | /* not debugging this process, or no such event */ |
Alexandre Julliard | cb1fc73 | 2000-01-24 21:58:06 +0000 | [diff] [blame] | 367 | set_error( STATUS_ACCESS_DENIED ); /* FIXME */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 368 | return 0; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 369 | } |
| 370 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 371 | /* alloc a debug event for a debugger */ |
| 372 | static struct debug_event *alloc_debug_event( struct thread *thread, int code, |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 373 | void *arg, const CONTEXT *context ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 374 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 375 | struct thread *debugger = thread->process->debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 376 | struct debug_event *event; |
| 377 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 378 | assert( code > 0 && code <= NB_DEBUG_EVENTS ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 379 | /* cannot queue a debug event for myself */ |
| 380 | assert( debugger->process != thread->process ); |
| 381 | |
| 382 | /* build the event */ |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 383 | if (!(event = alloc_object( &debug_event_ops ))) return NULL; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 384 | event->state = EVENT_QUEUED; |
| 385 | event->sender = (struct thread *)grab_object( thread ); |
| 386 | event->debugger = (struct thread *)grab_object( debugger ); |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 387 | event->data.code = code; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 388 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 389 | if (!fill_debug_event[code-1]( event, arg )) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 390 | { |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 391 | event->data.code = -1; /* make sure we don't attempt to close handles */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 392 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 393 | return NULL; |
| 394 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 395 | if (context) |
| 396 | { |
| 397 | memcpy( &event->context, context, sizeof(event->context) ); |
| 398 | thread->context = &event->context; |
| 399 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 400 | return event; |
| 401 | } |
| 402 | |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 403 | /* generate a debug event from inside the server and queue it */ |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 404 | void generate_debug_event( struct thread *thread, int code, void *arg ) |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 405 | { |
| 406 | if (thread->process->debugger) |
| 407 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 408 | 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 Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 415 | } |
| 416 | } |
| 417 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 418 | /* attach a process to a debugger thread and suspend it */ |
| 419 | static 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 Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 424 | if (!is_process_init_done( process )) goto error; /* still starting up */ |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 425 | if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */ |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 426 | |
| 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 Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 431 | /* don't let a debugger debug its console... won't work */ |
Alexandre Julliard | 627ca40 | 2007-05-11 12:46:32 +0200 | [diff] [blame] | 432 | if (debugger->process->console && console_get_renderer(debugger->process->console)->process == process) |
Eric Pouech | 3940d8a | 2001-12-04 20:17:43 +0000 | [diff] [blame] | 433 | goto error; |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 434 | |
Alexandre Julliard | 5f258c6 | 2001-07-14 00:50:30 +0000 | [diff] [blame] | 435 | suspend_process( process ); |
Alexandre Julliard | 820c592 | 2006-04-10 20:25:22 +0200 | [diff] [blame] | 436 | if (!set_process_debugger( process, debugger )) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 437 | { |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 438 | resume_process( process ); |
| 439 | return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 440 | } |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 441 | if (!set_process_debug_flag( process, 1 )) |
| 442 | { |
| 443 | process->debugger = NULL; |
| 444 | resume_process( process ); |
| 445 | return 0; |
| 446 | } |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 447 | return 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 448 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 449 | error: |
| 450 | set_error( STATUS_ACCESS_DENIED ); |
| 451 | return 0; |
| 452 | } |
| 453 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 454 | |
| 455 | /* detach a process from a debugger thread (and resume it ?) */ |
| 456 | int debugger_detach( struct process *process, struct thread *debugger ) |
| 457 | { |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 458 | struct debug_event *event, *next; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 459 | 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 Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 465 | assert(is_process_init_done(process)); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 466 | |
| 467 | suspend_process( process ); |
| 468 | /* send continue indication for all events */ |
| 469 | debug_ctx = debugger->debug_ctx; |
| 470 | |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 471 | /* free all events from this process */ |
| 472 | LIST_FOR_EACH_ENTRY_SAFE( event, next, &debug_ctx->event_queue, struct debug_event, entry ) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 473 | { |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 474 | if (event->sender->process != process) continue; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 475 | |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 476 | 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 Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 483 | } |
| 484 | |
| 485 | /* remove relationships between process and its debugger */ |
| 486 | process->debugger = NULL; |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 487 | if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */ |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 488 | |
| 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 Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 498 | /* generate all startup events of a given process */ |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 499 | void generate_startup_debug_events( struct process *process, void *entry ) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 500 | { |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 501 | struct list *ptr; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 502 | struct thread *thread, *first_thread = get_process_first_thread( process ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 503 | |
| 504 | /* generate creation events */ |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 505 | 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 Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 512 | |
| 513 | /* generate dll events (in loading order, i.e. reverse list order) */ |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 514 | ptr = list_tail( &process->dlls ); |
| 515 | while (ptr) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 516 | { |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 517 | struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry ); |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 518 | generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll ); |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 519 | ptr = list_prev( &process->dlls, ptr ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 520 | } |
| 521 | } |
| 522 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 523 | /* set the debugger of a given process */ |
| 524 | int set_process_debugger( struct process *process, struct thread *debugger ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 525 | { |
| 526 | struct debug_ctx *debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 527 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 528 | assert( !process->debugger ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 529 | |
| 530 | if (!debugger->debug_ctx) /* need to allocate a context */ |
| 531 | { |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 532 | if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 533 | debug_ctx->kill_on_exit = 1; |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 534 | list_init( &debug_ctx->event_queue ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 535 | debugger->debug_ctx = debug_ctx; |
| 536 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 537 | process->debugger = debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 538 | return 1; |
| 539 | } |
| 540 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 541 | /* a thread is exiting */ |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 542 | void debug_exit_thread( struct thread *thread ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 543 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 544 | if (thread->debug_ctx) /* this thread is a debugger */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 545 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 546 | if (thread->debug_ctx->kill_on_exit) |
| 547 | { |
| 548 | /* kill all debugged processes */ |
Francois Gouget | b6aa247 | 2007-08-31 02:35:54 +0200 | [diff] [blame] | 549 | kill_debugged_processes( thread, STATUS_DEBUGGER_INACTIVE ); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 550 | } |
| 551 | else |
| 552 | { |
| 553 | detach_debugged_processes( thread ); |
| 554 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 555 | release_object( thread->debug_ctx ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 556 | thread->debug_ctx = NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 557 | } |
| 558 | } |
| 559 | |
| 560 | /* Wait for a debug event */ |
| 561 | DECL_HANDLER(wait_debug_event) |
| 562 | { |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 563 | 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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 567 | { |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 568 | set_error( STATUS_INVALID_HANDLE ); |
| 569 | return; |
| 570 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 571 | reply->wait = 0; |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 572 | if ((event = find_event_to_send( debug_ctx ))) |
| 573 | { |
Alexandre Julliard | 0f273c1 | 2006-07-26 10:43:25 +0200 | [diff] [blame] | 574 | data_size_t size = get_reply_max_size(); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 575 | event->state = EVENT_SENT; |
| 576 | event->sender->debug_event = event; |
Alexandre Julliard | 54f2287 | 2002-10-03 19:54:57 +0000 | [diff] [blame] | 577 | reply->pid = get_process_id( event->sender->process ); |
| 578 | reply->tid = get_thread_id( event->sender ); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 579 | if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 580 | set_reply_data( &event->data, size ); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 581 | } |
| 582 | else /* no event ready */ |
| 583 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 584 | reply->pid = 0; |
| 585 | reply->tid = 0; |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 586 | if (req->get_handle) |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 587 | reply->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, 0 ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 588 | } |
| 589 | } |
| 590 | |
| 591 | /* Continue a debug event */ |
| 592 | DECL_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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 605 | } |
| 606 | |
| 607 | /* Start debugging an existing process */ |
| 608 | DECL_HANDLER(debug_process) |
| 609 | { |
| 610 | struct process *process = get_process_from_id( req->pid ); |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 611 | if (!process) return; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 612 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 613 | if (!req->attach) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 614 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 615 | debugger_detach( process, current ); |
| 616 | } |
| 617 | else if (debugger_attach( process, current )) |
| 618 | { |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 619 | generate_startup_debug_events( process, NULL ); |
Alexandre Julliard | 17de829 | 2006-04-19 19:45:39 +0200 | [diff] [blame] | 620 | break_process( process ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 621 | resume_process( process ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 622 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 623 | release_object( process ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 624 | } |
| 625 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 626 | /* queue an exception event */ |
| 627 | DECL_HANDLER(queue_exception_event) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 628 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 629 | reply->handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 630 | if (current->process->debugger) |
| 631 | { |
| 632 | struct debug_event_exception data; |
| 633 | struct debug_event *event; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 634 | const CONTEXT *context = get_req_data(); |
Eric Pouech | 0a25896 | 2004-11-30 21:38:57 +0000 | [diff] [blame] | 635 | const EXCEPTION_RECORD *rec = (const EXCEPTION_RECORD *)(context + 1); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 636 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 637 | if (get_req_data_size() < sizeof(*rec) + sizeof(*context)) |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 638 | { |
| 639 | set_error( STATUS_INVALID_PARAMETER ); |
| 640 | return; |
| 641 | } |
| 642 | data.record = *rec; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 643 | data.first = req->first; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 644 | if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 645 | { |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 646 | if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, 0 ))) |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 647 | { |
| 648 | link_event( event ); |
| 649 | suspend_process( current->process ); |
| 650 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 651 | release_object( event ); |
| 652 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 653 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 654 | } |
| 655 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 656 | /* retrieve the status of an exception event */ |
| 657 | DECL_HANDLER(get_exception_status) |
| 658 | { |
| 659 | struct debug_event *event; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 660 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 661 | if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle, |
| 662 | 0, &debug_event_ops ))) |
| 663 | { |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 664 | close_handle( current->process, req->handle ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 665 | if (event->state == EVENT_CONTINUED) |
| 666 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 667 | if (current->context == &event->context) |
| 668 | { |
Alexandre Julliard | 0f273c1 | 2006-07-26 10:43:25 +0200 | [diff] [blame] | 669 | data_size_t size = min( sizeof(CONTEXT), get_reply_max_size() ); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 670 | set_reply_data( &event->context, size ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 671 | current->context = NULL; |
| 672 | } |
Alexandre Julliard | ff7795e | 2005-11-01 21:47:07 +0000 | [diff] [blame] | 673 | set_error( event->status ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 674 | } |
| 675 | else set_error( STATUS_PENDING ); |
| 676 | release_object( event ); |
| 677 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 678 | } |
| 679 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 680 | /* send an output string to the debugger */ |
| 681 | DECL_HANDLER(output_debug_string) |
| 682 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 683 | 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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 689 | } |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 690 | |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 691 | /* simulate a breakpoint in a process */ |
| 692 | DECL_HANDLER(debug_break) |
| 693 | { |
| 694 | struct process *process; |
| 695 | |
| 696 | reply->self = 0; |
Alexandre Julliard | 17de829 | 2006-04-19 19:45:39 +0200 | [diff] [blame] | 697 | if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION /*FIXME*/ ))) |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 698 | { |
Alexandre Julliard | 17de829 | 2006-04-19 19:45:39 +0200 | [diff] [blame] | 699 | if (process != current->process) break_process( process ); |
| 700 | else reply->self = 1; |
| 701 | release_object( process ); |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 702 | } |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 703 | } |
| 704 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 705 | /* set debugger kill on exit flag */ |
| 706 | DECL_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 | } |