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 |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 | |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 30 | #include "windef.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 31 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 32 | #include "handle.h" |
| 33 | #include "process.h" |
| 34 | #include "thread.h" |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 35 | #include "request.h" |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 36 | #include "console.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 37 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 38 | enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED }; |
| 39 | |
| 40 | /* debug event */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 41 | struct debug_event |
| 42 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 43 | struct object obj; /* object header */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 44 | struct list entry; /* entry in event queue */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 45 | 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 Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 49 | debug_event_t data; /* event data */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 50 | CONTEXT context; /* register context */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 51 | }; |
| 52 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 53 | /* debug context */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 54 | struct debug_ctx |
| 55 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 56 | struct object obj; /* object header */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 57 | struct list event_queue; /* pending events queue */ |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 58 | int kill_on_exit;/* kill debuggees on debugger exit ? */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 59 | }; |
| 60 | |
| 61 | |
| 62 | static void debug_event_dump( struct object *obj, int verbose ); |
| 63 | static int debug_event_signaled( struct object *obj, struct thread *thread ); |
| 64 | static void debug_event_destroy( struct object *obj ); |
| 65 | |
| 66 | static 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 McCormack | f92fff6 | 2005-04-24 17:35:52 +0000 | [diff] [blame] | 74 | no_signal, /* signal */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 75 | no_get_fd, /* get_fd */ |
Alexandre Julliard | b9b1ea9 | 2005-06-09 15:39:52 +0000 | [diff] [blame] | 76 | no_close_handle, /* close_handle */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 77 | debug_event_destroy /* destroy */ |
| 78 | }; |
| 79 | |
| 80 | static void debug_ctx_dump( struct object *obj, int verbose ); |
| 81 | static int debug_ctx_signaled( struct object *obj, struct thread *thread ); |
| 82 | static void debug_ctx_destroy( struct object *obj ); |
| 83 | |
| 84 | static 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 McCormack | f92fff6 | 2005-04-24 17:35:52 +0000 | [diff] [blame] | 92 | no_signal, /* signal */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 93 | no_get_fd, /* get_fd */ |
Alexandre Julliard | b9b1ea9 | 2005-06-09 15:39:52 +0000 | [diff] [blame] | 94 | no_close_handle, /* close_handle */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 95 | debug_ctx_destroy /* destroy */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 96 | }; |
| 97 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 98 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 99 | /* routines to build an event according to its type */ |
| 100 | |
| 101 | static int fill_exception_event( struct debug_event *event, void *arg ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 102 | { |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 103 | memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 104 | return 1; |
| 105 | } |
| 106 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 107 | static int fill_create_thread_event( struct debug_event *event, void *arg ) |
| 108 | { |
| 109 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 110 | struct thread *thread = event->sender; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 111 | obj_handle_t handle; |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 112 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 113 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 114 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE ))) return 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 115 | event->data.info.create_thread.handle = handle; |
| 116 | event->data.info.create_thread.teb = thread->teb; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 117 | event->data.info.create_thread.start = arg; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 118 | return 1; |
| 119 | } |
| 120 | |
| 121 | static int fill_create_process_event( struct debug_event *event, void *arg ) |
| 122 | { |
| 123 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 124 | struct thread *thread = event->sender; |
| 125 | struct process *process = thread->process; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 126 | obj_handle_t handle; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 127 | |
| 128 | /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 129 | if (!(handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE ))) return 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 130 | event->data.info.create_process.process = handle; |
| 131 | |
| 132 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 133 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 134 | { |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 135 | close_handle( debugger, event->data.info.create_process.process, NULL ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 136 | return 0; |
| 137 | } |
| 138 | event->data.info.create_process.thread = handle; |
| 139 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 140 | handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 141 | if (process->exe.file && |
| 142 | /* the doc says write access too, but this doesn't seem a good idea */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 143 | !(handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 144 | { |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 145 | close_handle( debugger, event->data.info.create_process.process, NULL ); |
| 146 | close_handle( debugger, event->data.info.create_process.thread, NULL ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 147 | 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 Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 152 | event->data.info.create_process.start = arg; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 153 | event->data.info.create_process.dbg_offset = process->exe.dbg_offset; |
| 154 | event->data.info.create_process.dbg_size = process->exe.dbg_size; |
Alexandre Julliard | a37dec0 | 2000-06-08 00:57:24 +0000 | [diff] [blame] | 155 | event->data.info.create_process.name = process->exe.name; |
Alexandre Julliard | c30cefb | 2003-09-30 01:04:19 +0000 | [diff] [blame] | 156 | event->data.info.create_process.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 157 | return 1; |
| 158 | } |
| 159 | |
| 160 | static 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 | |
| 167 | static 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 | |
| 174 | static 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 Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 178 | obj_handle_t handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 179 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 180 | if (dll->file && !(handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 181 | 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 Julliard | c30cefb | 2003-09-30 01:04:19 +0000 | [diff] [blame] | 187 | event->data.info.load_dll.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 188 | return 1; |
| 189 | } |
| 190 | |
| 191 | static 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 | |
| 197 | static int fill_output_debug_string_event( struct debug_event *event, void *arg ) |
| 198 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 199 | struct debug_event_output_string *data = arg; |
| 200 | event->data.info.output_string = *data; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 201 | return 1; |
| 202 | } |
| 203 | |
| 204 | typedef 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 | |
| 208 | static 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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 221 | /* unlink the first event from the queue */ |
| 222 | static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) |
| 223 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 224 | list_remove( &event->entry ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 225 | if (event->sender->debug_event == event) event->sender->debug_event = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 226 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 227 | } |
| 228 | |
| 229 | /* link an event at the end of the queue */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 230 | static void link_event( struct debug_event *event ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 231 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 232 | struct debug_ctx *debug_ctx = event->debugger->debug_ctx; |
| 233 | |
| 234 | assert( debug_ctx ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 235 | grab_object( event ); |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 236 | list_add_tail( &debug_ctx->event_queue, &event->entry ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 237 | 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 */ |
| 241 | static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx ) |
| 242 | { |
| 243 | struct debug_event *event; |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 244 | |
| 245 | 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] | 246 | { |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 247 | if (event->state == EVENT_SENT) continue; /* already sent */ |
| 248 | if (event->sender->debug_event) continue; /* thread busy with another one */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 249 | return event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 250 | } |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 251 | return NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 252 | } |
| 253 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 254 | static 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 Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 259 | debug_event->sender, debug_event->data.code, debug_event->state ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | static 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 | |
| 269 | static 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 Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 274 | /* 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 Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 279 | switch(event->data.code) |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 280 | { |
| 281 | case CREATE_THREAD_DEBUG_EVENT: |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 282 | close_handle( debugger, event->data.info.create_thread.handle, NULL ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 283 | break; |
| 284 | case CREATE_PROCESS_DEBUG_EVENT: |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 285 | if (event->data.info.create_process.file) |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 286 | 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 Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 289 | break; |
| 290 | case LOAD_DLL_DEBUG_EVENT: |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 291 | if (event->data.info.load_dll.handle) |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 292 | close_handle( debugger, event->data.info.load_dll.handle, NULL ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 293 | break; |
| 294 | } |
| 295 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 296 | if (event->sender->context == &event->context) event->sender->context = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 297 | release_object( event->sender ); |
| 298 | release_object( event->debugger ); |
| 299 | } |
| 300 | |
| 301 | static 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 Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 305 | fprintf( stderr, "Debug context head=%p tail=%p\n", |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 306 | debug_ctx->event_queue.next, debug_ctx->event_queue.prev ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 307 | } |
| 308 | |
| 309 | static 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 Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 313 | return find_event_to_send( debug_ctx ) != NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | static void debug_ctx_destroy( struct object *obj ) |
| 317 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 318 | struct list *ptr; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 319 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 320 | assert( obj->ops == &debug_ctx_ops ); |
| 321 | |
| 322 | /* free all pending events */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 323 | while ((ptr = list_head( &debug_ctx->event_queue ))) |
| 324 | unlink_event( debug_ctx, LIST_ENTRY( ptr, struct debug_event, entry )); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 325 | } |
| 326 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 327 | /* continue a debug event */ |
| 328 | static int continue_debug_event( struct process *process, struct thread *thread, int status ) |
| 329 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 330 | struct debug_ctx *debug_ctx = current->debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 331 | |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 332 | if (debug_ctx && process->debugger == current && thread->process == process) |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 333 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 334 | 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 Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 352 | } |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 353 | /* not debugging this process, or no such event */ |
Alexandre Julliard | cb1fc73 | 2000-01-24 21:58:06 +0000 | [diff] [blame] | 354 | set_error( STATUS_ACCESS_DENIED ); /* FIXME */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 355 | return 0; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 356 | } |
| 357 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 358 | /* alloc a debug event for a debugger */ |
| 359 | static struct debug_event *alloc_debug_event( struct thread *thread, int code, |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 360 | void *arg, const CONTEXT *context ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 361 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 362 | struct thread *debugger = thread->process->debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 363 | struct debug_event *event; |
| 364 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 365 | assert( code > 0 && code <= NB_DEBUG_EVENTS ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 366 | /* cannot queue a debug event for myself */ |
| 367 | assert( debugger->process != thread->process ); |
| 368 | |
| 369 | /* build the event */ |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 370 | if (!(event = alloc_object( &debug_event_ops ))) return NULL; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 371 | event->state = EVENT_QUEUED; |
| 372 | event->sender = (struct thread *)grab_object( thread ); |
| 373 | event->debugger = (struct thread *)grab_object( debugger ); |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 374 | event->data.code = code; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 375 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 376 | if (!fill_debug_event[code-1]( event, arg )) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 377 | { |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 378 | 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] | 379 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 380 | return NULL; |
| 381 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 382 | if (context) |
| 383 | { |
| 384 | memcpy( &event->context, context, sizeof(event->context) ); |
| 385 | thread->context = &event->context; |
| 386 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 387 | return event; |
| 388 | } |
| 389 | |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 390 | /* generate a debug event from inside the server and queue it */ |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 391 | void generate_debug_event( struct thread *thread, int code, void *arg ) |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 392 | { |
| 393 | if (thread->process->debugger) |
| 394 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 395 | 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 Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 402 | } |
| 403 | } |
| 404 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 405 | /* attach a process to a debugger thread and suspend it */ |
| 406 | static 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 Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 411 | if (!is_process_init_done( process )) goto error; /* still starting up */ |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 412 | 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] | 413 | |
| 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 Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 418 | /* don't let a debugger debug its console... won't work */ |
Eric Pouech | 3940d8a | 2001-12-04 20:17:43 +0000 | [diff] [blame] | 419 | if (debugger->process->console && debugger->process->console->renderer->process == process) |
| 420 | goto error; |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 421 | |
Alexandre Julliard | 5f258c6 | 2001-07-14 00:50:30 +0000 | [diff] [blame] | 422 | suspend_process( process ); |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 423 | if (!attach_process( process ) || !set_process_debugger( process, debugger )) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 424 | { |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 425 | resume_process( process ); |
| 426 | return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 427 | } |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 428 | if (!set_process_debug_flag( process, 1 )) |
| 429 | { |
| 430 | process->debugger = NULL; |
| 431 | resume_process( process ); |
| 432 | return 0; |
| 433 | } |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 434 | return 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 435 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 436 | error: |
| 437 | set_error( STATUS_ACCESS_DENIED ); |
| 438 | return 0; |
| 439 | } |
| 440 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 441 | |
| 442 | /* detach a process from a debugger thread (and resume it ?) */ |
| 443 | int debugger_detach( struct process *process, struct thread *debugger ) |
| 444 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 445 | 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 Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 452 | assert(is_process_init_done(process)); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 453 | |
| 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 Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 460 | LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry ) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 461 | { |
| 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 Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 473 | break; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 474 | } |
| 475 | } |
| 476 | |
| 477 | /* remove relationships between process and its debugger */ |
| 478 | process->debugger = NULL; |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 479 | if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */ |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 480 | detach_process( process ); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 481 | |
| 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 Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 491 | /* generate all startup events of a given process */ |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 492 | void generate_startup_debug_events( struct process *process, void *entry ) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 493 | { |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 494 | struct list *ptr; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 495 | struct thread *thread, *first_thread = get_process_first_thread( process ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 496 | |
| 497 | /* generate creation events */ |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 498 | 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 Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 505 | |
| 506 | /* generate dll events (in loading order, i.e. reverse list order) */ |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 507 | ptr = list_tail( &process->dlls ); |
| 508 | while (ptr) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 509 | { |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 510 | struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry ); |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 511 | generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll ); |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 512 | ptr = list_prev( &process->dlls, ptr ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 513 | } |
| 514 | } |
| 515 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 516 | /* set the debugger of a given process */ |
| 517 | int set_process_debugger( struct process *process, struct thread *debugger ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 518 | { |
| 519 | struct debug_ctx *debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 520 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 521 | assert( !process->debugger ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 522 | |
| 523 | if (!debugger->debug_ctx) /* need to allocate a context */ |
| 524 | { |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 525 | if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 526 | debug_ctx->kill_on_exit = 1; |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 527 | list_init( &debug_ctx->event_queue ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 528 | debugger->debug_ctx = debug_ctx; |
| 529 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 530 | process->debugger = debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 531 | return 1; |
| 532 | } |
| 533 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 534 | /* a thread is exiting */ |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 535 | void debug_exit_thread( struct thread *thread ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 536 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 537 | if (thread->debug_ctx) /* this thread is a debugger */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 538 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 539 | 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 Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 548 | release_object( thread->debug_ctx ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 549 | thread->debug_ctx = NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 550 | } |
| 551 | } |
| 552 | |
| 553 | /* Wait for a debug event */ |
| 554 | DECL_HANDLER(wait_debug_event) |
| 555 | { |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 556 | 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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 560 | { |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 561 | set_error( STATUS_INVALID_HANDLE ); |
| 562 | return; |
| 563 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 564 | reply->wait = 0; |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 565 | if ((event = find_event_to_send( debug_ctx ))) |
| 566 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 567 | size_t size = get_reply_max_size(); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 568 | event->state = EVENT_SENT; |
| 569 | event->sender->debug_event = event; |
Alexandre Julliard | 54f2287 | 2002-10-03 19:54:57 +0000 | [diff] [blame] | 570 | reply->pid = get_process_id( event->sender->process ); |
| 571 | reply->tid = get_thread_id( event->sender ); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 572 | if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 573 | set_reply_data( &event->data, size ); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 574 | } |
| 575 | else /* no event ready */ |
| 576 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 577 | reply->pid = 0; |
| 578 | reply->tid = 0; |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 579 | if (req->get_handle) |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 580 | reply->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, FALSE ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 581 | } |
| 582 | } |
| 583 | |
| 584 | /* Continue a debug event */ |
| 585 | DECL_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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 598 | } |
| 599 | |
| 600 | /* Start debugging an existing process */ |
| 601 | DECL_HANDLER(debug_process) |
| 602 | { |
| 603 | struct process *process = get_process_from_id( req->pid ); |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 604 | if (!process) return; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 605 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 606 | if (!req->attach) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 607 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 608 | debugger_detach( process, current ); |
| 609 | } |
| 610 | else if (debugger_attach( process, current )) |
| 611 | { |
| 612 | struct debug_event_exception data; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 613 | struct thread *thread = get_process_first_thread( process ); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 614 | |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 615 | generate_startup_debug_events( process, NULL ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 616 | resume_process( process ); |
| 617 | |
| 618 | data.record.ExceptionCode = EXCEPTION_BREAKPOINT; |
| 619 | data.record.ExceptionFlags = EXCEPTION_CONTINUABLE; |
| 620 | data.record.ExceptionRecord = NULL; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 621 | data.record.ExceptionAddress = get_thread_ip( thread ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 622 | data.record.NumberParameters = 0; |
| 623 | data.first = 1; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 624 | generate_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 625 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 626 | release_object( process ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 627 | } |
| 628 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 629 | /* queue an exception event */ |
| 630 | DECL_HANDLER(queue_exception_event) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 631 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 632 | reply->handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 633 | if (current->process->debugger) |
| 634 | { |
| 635 | struct debug_event_exception data; |
| 636 | struct debug_event *event; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 637 | const CONTEXT *context = get_req_data(); |
Eric Pouech | 0a25896 | 2004-11-30 21:38:57 +0000 | [diff] [blame] | 638 | const EXCEPTION_RECORD *rec = (const EXCEPTION_RECORD *)(context + 1); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 639 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 640 | if (get_req_data_size() < sizeof(*rec) + sizeof(*context)) |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 641 | { |
| 642 | set_error( STATUS_INVALID_PARAMETER ); |
| 643 | return; |
| 644 | } |
| 645 | data.record = *rec; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 646 | data.first = req->first; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 647 | if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 648 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 649 | if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, FALSE ))) |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 650 | { |
| 651 | link_event( event ); |
| 652 | suspend_process( current->process ); |
| 653 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 654 | release_object( event ); |
| 655 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 656 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 657 | } |
| 658 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 659 | /* retrieve the status of an exception event */ |
| 660 | DECL_HANDLER(get_exception_status) |
| 661 | { |
| 662 | struct debug_event *event; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 663 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 664 | reply->status = 0; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 665 | 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 Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 670 | reply->status = event->status; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 671 | if (current->context == &event->context) |
| 672 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 673 | size_t size = min( sizeof(CONTEXT), get_reply_max_size() ); |
| 674 | set_reply_data( &event->context, size ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 675 | current->context = NULL; |
| 676 | } |
| 677 | } |
| 678 | else set_error( STATUS_PENDING ); |
| 679 | release_object( event ); |
| 680 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 681 | } |
| 682 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 683 | /* send an output string to the debugger */ |
| 684 | DECL_HANDLER(output_debug_string) |
| 685 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 686 | 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 Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 692 | } |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 693 | |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 694 | /* simulate a breakpoint in a process */ |
| 695 | DECL_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 Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 706 | LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 707 | { |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 708 | if (send_thread_signal( thread, SIGTRAP )) goto done; |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 709 | } |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 710 | set_error( STATUS_ACCESS_DENIED ); |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 711 | } |
| 712 | else reply->self = 1; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 713 | |
| 714 | done: |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 715 | release_object( process ); |
| 716 | } |
| 717 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 718 | /* set debugger kill on exit flag */ |
| 719 | DECL_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 | } |