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 | #include "winbase.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 32 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 33 | #include "handle.h" |
| 34 | #include "process.h" |
| 35 | #include "thread.h" |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 36 | #include "request.h" |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 37 | #include "console.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 38 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 39 | enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED }; |
| 40 | |
| 41 | /* debug event */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 42 | struct debug_event |
| 43 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 44 | struct object obj; /* object header */ |
| 45 | struct debug_event *next; /* event queue */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 46 | struct debug_event *prev; |
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 | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 59 | struct debug_event *event_head; /* head of pending events queue */ |
| 60 | struct debug_event *event_tail; /* tail of pending events queue */ |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 61 | int kill_on_exit;/* kill debuggees on debugger exit ? */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 62 | }; |
| 63 | |
| 64 | |
| 65 | static void debug_event_dump( struct object *obj, int verbose ); |
| 66 | static int debug_event_signaled( struct object *obj, struct thread *thread ); |
| 67 | static void debug_event_destroy( struct object *obj ); |
| 68 | |
| 69 | static const struct object_ops debug_event_ops = |
| 70 | { |
| 71 | sizeof(struct debug_event), /* size */ |
| 72 | debug_event_dump, /* dump */ |
| 73 | add_queue, /* add_queue */ |
| 74 | remove_queue, /* remove_queue */ |
| 75 | debug_event_signaled, /* signaled */ |
| 76 | no_satisfied, /* satisfied */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 77 | no_get_fd, /* get_fd */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 78 | debug_event_destroy /* destroy */ |
| 79 | }; |
| 80 | |
| 81 | static void debug_ctx_dump( struct object *obj, int verbose ); |
| 82 | static int debug_ctx_signaled( struct object *obj, struct thread *thread ); |
| 83 | static void debug_ctx_destroy( struct object *obj ); |
| 84 | |
| 85 | static const struct object_ops debug_ctx_ops = |
| 86 | { |
| 87 | sizeof(struct debug_ctx), /* size */ |
| 88 | debug_ctx_dump, /* dump */ |
| 89 | add_queue, /* add_queue */ |
| 90 | remove_queue, /* remove_queue */ |
| 91 | debug_ctx_signaled, /* signaled */ |
| 92 | no_satisfied, /* satisfied */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 93 | no_get_fd, /* get_fd */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 94 | debug_ctx_destroy /* destroy */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 95 | }; |
| 96 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 97 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 98 | /* routines to build an event according to its type */ |
| 99 | |
| 100 | static int fill_exception_event( struct debug_event *event, void *arg ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 101 | { |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 102 | memcpy( &event->data.info.exception, arg, sizeof(event->data.info.exception) ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 103 | return 1; |
| 104 | } |
| 105 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 106 | static int fill_create_thread_event( struct debug_event *event, void *arg ) |
| 107 | { |
| 108 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 109 | struct thread *thread = event->sender; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 110 | obj_handle_t handle; |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 111 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 112 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 113 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE ))) return 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 114 | event->data.info.create_thread.handle = handle; |
| 115 | event->data.info.create_thread.teb = thread->teb; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 116 | event->data.info.create_thread.start = arg; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 117 | return 1; |
| 118 | } |
| 119 | |
| 120 | static int fill_create_process_event( struct debug_event *event, void *arg ) |
| 121 | { |
| 122 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 123 | struct thread *thread = event->sender; |
| 124 | struct process *process = thread->process; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 125 | obj_handle_t handle; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 126 | |
| 127 | /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 128 | if (!(handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, FALSE ))) return 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 129 | event->data.info.create_process.process = handle; |
| 130 | |
| 131 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 132 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 133 | { |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 134 | close_handle( debugger, event->data.info.create_process.process, NULL ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 135 | return 0; |
| 136 | } |
| 137 | event->data.info.create_process.thread = handle; |
| 138 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 139 | handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 140 | if (process->exe.file && |
| 141 | /* 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] | 142 | !(handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 143 | { |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 144 | close_handle( debugger, event->data.info.create_process.process, NULL ); |
| 145 | close_handle( debugger, event->data.info.create_process.thread, NULL ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 146 | return 0; |
| 147 | } |
| 148 | event->data.info.create_process.file = handle; |
| 149 | event->data.info.create_process.teb = thread->teb; |
| 150 | event->data.info.create_process.base = process->exe.base; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 151 | event->data.info.create_process.start = arg; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 152 | event->data.info.create_process.dbg_offset = process->exe.dbg_offset; |
| 153 | event->data.info.create_process.dbg_size = process->exe.dbg_size; |
Alexandre Julliard | a37dec0 | 2000-06-08 00:57:24 +0000 | [diff] [blame] | 154 | event->data.info.create_process.name = process->exe.name; |
Alexandre Julliard | c30cefb | 2003-09-30 01:04:19 +0000 | [diff] [blame] | 155 | event->data.info.create_process.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 156 | return 1; |
| 157 | } |
| 158 | |
| 159 | static int fill_exit_thread_event( struct debug_event *event, void *arg ) |
| 160 | { |
| 161 | struct thread *thread = arg; |
| 162 | event->data.info.exit.exit_code = thread->exit_code; |
| 163 | return 1; |
| 164 | } |
| 165 | |
| 166 | static int fill_exit_process_event( struct debug_event *event, void *arg ) |
| 167 | { |
| 168 | struct process *process = arg; |
| 169 | event->data.info.exit.exit_code = process->exit_code; |
| 170 | return 1; |
| 171 | } |
| 172 | |
| 173 | static int fill_load_dll_event( struct debug_event *event, void *arg ) |
| 174 | { |
| 175 | struct process *debugger = event->debugger->process; |
| 176 | struct process_dll *dll = arg; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 177 | obj_handle_t handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 178 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 179 | if (dll->file && !(handle = alloc_handle( debugger, dll->file, GENERIC_READ, FALSE ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 180 | return 0; |
| 181 | event->data.info.load_dll.handle = handle; |
| 182 | event->data.info.load_dll.base = dll->base; |
| 183 | event->data.info.load_dll.dbg_offset = dll->dbg_offset; |
| 184 | event->data.info.load_dll.dbg_size = dll->dbg_size; |
| 185 | event->data.info.load_dll.name = dll->name; |
Alexandre Julliard | c30cefb | 2003-09-30 01:04:19 +0000 | [diff] [blame] | 186 | event->data.info.load_dll.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 187 | return 1; |
| 188 | } |
| 189 | |
| 190 | static int fill_unload_dll_event( struct debug_event *event, void *arg ) |
| 191 | { |
| 192 | event->data.info.unload_dll.base = arg; |
| 193 | return 1; |
| 194 | } |
| 195 | |
| 196 | static int fill_output_debug_string_event( struct debug_event *event, void *arg ) |
| 197 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 198 | struct debug_event_output_string *data = arg; |
| 199 | event->data.info.output_string = *data; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 200 | return 1; |
| 201 | } |
| 202 | |
| 203 | typedef int (*fill_event_func)( struct debug_event *event, void *arg ); |
| 204 | |
| 205 | #define NB_DEBUG_EVENTS OUTPUT_DEBUG_STRING_EVENT /* RIP_EVENT not supported */ |
| 206 | |
| 207 | static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] = |
| 208 | { |
| 209 | fill_exception_event, /* EXCEPTION_DEBUG_EVENT */ |
| 210 | fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */ |
| 211 | fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */ |
| 212 | fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */ |
| 213 | fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */ |
| 214 | fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */ |
| 215 | fill_unload_dll_event, /* UNLOAD_DLL_DEBUG_EVENT */ |
| 216 | fill_output_debug_string_event /* OUTPUT_DEBUG_STRING_EVENT */ |
| 217 | }; |
| 218 | |
| 219 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 220 | /* unlink the first event from the queue */ |
| 221 | static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) |
| 222 | { |
| 223 | if (event->prev) event->prev->next = event->next; |
| 224 | else debug_ctx->event_head = event->next; |
| 225 | if (event->next) event->next->prev = event->prev; |
| 226 | else debug_ctx->event_tail = event->prev; |
| 227 | event->next = event->prev = NULL; |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 228 | if (event->sender->debug_event == event) event->sender->debug_event = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 229 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | /* link an event at the end of the queue */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 233 | static void link_event( struct debug_event *event ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 234 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 235 | struct debug_ctx *debug_ctx = event->debugger->debug_ctx; |
| 236 | |
| 237 | assert( debug_ctx ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 238 | grab_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 239 | event->next = NULL; |
| 240 | event->prev = debug_ctx->event_tail; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 241 | debug_ctx->event_tail = event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 242 | if (event->prev) event->prev->next = event; |
| 243 | else debug_ctx->event_head = event; |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 244 | if (!event->sender->debug_event) wake_up( &debug_ctx->obj, 0 ); |
| 245 | } |
| 246 | |
| 247 | /* find the next event that we can send to the debugger */ |
| 248 | static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx ) |
| 249 | { |
| 250 | struct debug_event *event; |
| 251 | for (event = debug_ctx->event_head; event; event = event->next) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 252 | { |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 253 | if (event->state == EVENT_SENT) continue; /* already sent */ |
| 254 | if (event->sender->debug_event) continue; /* thread busy with another one */ |
| 255 | break; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 256 | } |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 257 | return event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 258 | } |
| 259 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 260 | static void debug_event_dump( struct object *obj, int verbose ) |
| 261 | { |
| 262 | struct debug_event *debug_event = (struct debug_event *)obj; |
| 263 | assert( obj->ops == &debug_event_ops ); |
| 264 | fprintf( stderr, "Debug event sender=%p code=%d state=%d\n", |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 265 | debug_event->sender, debug_event->data.code, debug_event->state ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | static int debug_event_signaled( struct object *obj, struct thread *thread ) |
| 269 | { |
| 270 | struct debug_event *debug_event = (struct debug_event *)obj; |
| 271 | assert( obj->ops == &debug_event_ops ); |
| 272 | return debug_event->state == EVENT_CONTINUED; |
| 273 | } |
| 274 | |
| 275 | static void debug_event_destroy( struct object *obj ) |
| 276 | { |
| 277 | struct debug_event *event = (struct debug_event *)obj; |
| 278 | assert( obj->ops == &debug_event_ops ); |
| 279 | |
| 280 | /* cannot still be in the queue */ |
| 281 | assert( !event->next ); |
| 282 | assert( !event->prev ); |
| 283 | |
| 284 | /* If the event has been sent already, the handles are now under the */ |
| 285 | /* responsibility of the debugger process, so we don't touch them */ |
| 286 | if (event->state == EVENT_QUEUED) |
| 287 | { |
| 288 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 289 | switch(event->data.code) |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 290 | { |
| 291 | case CREATE_THREAD_DEBUG_EVENT: |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 292 | close_handle( debugger, event->data.info.create_thread.handle, NULL ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 293 | break; |
| 294 | case CREATE_PROCESS_DEBUG_EVENT: |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 295 | if (event->data.info.create_process.file) |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 296 | close_handle( debugger, event->data.info.create_process.file, NULL ); |
| 297 | close_handle( debugger, event->data.info.create_process.thread, NULL ); |
| 298 | close_handle( debugger, event->data.info.create_process.process, NULL ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 299 | break; |
| 300 | case LOAD_DLL_DEBUG_EVENT: |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 301 | if (event->data.info.load_dll.handle) |
Alexandre Julliard | d549f69 | 2000-12-22 02:04:15 +0000 | [diff] [blame] | 302 | close_handle( debugger, event->data.info.load_dll.handle, NULL ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 303 | break; |
| 304 | } |
| 305 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 306 | if (event->sender->context == &event->context) event->sender->context = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 307 | release_object( event->sender ); |
| 308 | release_object( event->debugger ); |
| 309 | } |
| 310 | |
| 311 | static void debug_ctx_dump( struct object *obj, int verbose ) |
| 312 | { |
| 313 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 314 | assert( obj->ops == &debug_ctx_ops ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 315 | fprintf( stderr, "Debug context head=%p tail=%p\n", |
| 316 | debug_ctx->event_head, debug_ctx->event_tail ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 317 | } |
| 318 | |
| 319 | static int debug_ctx_signaled( struct object *obj, struct thread *thread ) |
| 320 | { |
| 321 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 322 | assert( obj->ops == &debug_ctx_ops ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 323 | return find_event_to_send( debug_ctx ) != NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 324 | } |
| 325 | |
| 326 | static void debug_ctx_destroy( struct object *obj ) |
| 327 | { |
| 328 | struct debug_event *event; |
| 329 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 330 | assert( obj->ops == &debug_ctx_ops ); |
| 331 | |
| 332 | /* free all pending events */ |
| 333 | while ((event = debug_ctx->event_head) != NULL) unlink_event( debug_ctx, event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 334 | } |
| 335 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 336 | /* continue a debug event */ |
| 337 | static int continue_debug_event( struct process *process, struct thread *thread, int status ) |
| 338 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 339 | struct debug_event *event; |
| 340 | struct debug_ctx *debug_ctx = current->debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 341 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 342 | if (!debug_ctx || process->debugger != current || thread->process != process) goto error; |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 343 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 344 | /* find the event in the queue */ |
| 345 | for (event = debug_ctx->event_head; event; event = event->next) |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 346 | { |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 347 | if (event->state != EVENT_SENT) continue; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 348 | if (event->sender == thread) break; |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 349 | } |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 350 | if (!event) goto error; |
| 351 | |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 352 | assert( event->sender->debug_event == event ); |
| 353 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 354 | event->status = status; |
| 355 | event->state = EVENT_CONTINUED; |
| 356 | wake_up( &event->obj, 0 ); |
| 357 | |
| 358 | unlink_event( debug_ctx, event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 359 | resume_process( process ); |
| 360 | return 1; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 361 | error: |
| 362 | /* not debugging this process, or no such event */ |
Alexandre Julliard | cb1fc73 | 2000-01-24 21:58:06 +0000 | [diff] [blame] | 363 | set_error( STATUS_ACCESS_DENIED ); /* FIXME */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 364 | return 0; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 365 | } |
| 366 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 367 | /* alloc a debug event for a debugger */ |
| 368 | static struct debug_event *alloc_debug_event( struct thread *thread, int code, |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 369 | void *arg, const CONTEXT *context ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 370 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 371 | struct thread *debugger = thread->process->debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 372 | struct debug_event *event; |
| 373 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 374 | assert( code > 0 && code <= NB_DEBUG_EVENTS ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 375 | /* cannot queue a debug event for myself */ |
| 376 | assert( debugger->process != thread->process ); |
| 377 | |
| 378 | /* build the event */ |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 379 | if (!(event = alloc_object( &debug_event_ops ))) return NULL; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 380 | event->next = NULL; |
| 381 | event->prev = NULL; |
| 382 | event->state = EVENT_QUEUED; |
| 383 | event->sender = (struct thread *)grab_object( thread ); |
| 384 | event->debugger = (struct thread *)grab_object( debugger ); |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 385 | event->data.code = code; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 386 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 387 | if (!fill_debug_event[code-1]( event, arg )) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 388 | { |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 389 | 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] | 390 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 391 | return NULL; |
| 392 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 393 | if (context) |
| 394 | { |
| 395 | memcpy( &event->context, context, sizeof(event->context) ); |
| 396 | thread->context = &event->context; |
| 397 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 398 | return event; |
| 399 | } |
| 400 | |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 401 | /* generate a debug event from inside the server and queue it */ |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 402 | void generate_debug_event( struct thread *thread, int code, void *arg ) |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 403 | { |
| 404 | if (thread->process->debugger) |
| 405 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 406 | struct debug_event *event = alloc_debug_event( thread, code, arg, NULL ); |
| 407 | if (event) |
| 408 | { |
| 409 | link_event( event ); |
| 410 | suspend_process( thread->process ); |
| 411 | release_object( event ); |
| 412 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 413 | } |
| 414 | } |
| 415 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 416 | /* attach a process to a debugger thread and suspend it */ |
| 417 | static int debugger_attach( struct process *process, struct thread *debugger ) |
| 418 | { |
| 419 | struct thread *thread; |
| 420 | |
| 421 | if (process->debugger) goto error; /* already being debugged */ |
Alexandre Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 422 | if (!is_process_init_done( process )) goto error; /* still starting up */ |
Alexandre Julliard | 4705b8a | 2002-04-02 02:50:24 +0000 | [diff] [blame] | 423 | if (!process->thread_list) goto error; /* no thread running in the process */ |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 424 | |
| 425 | /* make sure we don't create a debugging loop */ |
| 426 | for (thread = debugger; thread; thread = thread->process->debugger) |
| 427 | if (thread->process == process) goto error; |
| 428 | |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 429 | /* don't let a debugger debug its console... won't work */ |
Eric Pouech | 3940d8a | 2001-12-04 20:17:43 +0000 | [diff] [blame] | 430 | if (debugger->process->console && debugger->process->console->renderer->process == process) |
| 431 | goto error; |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 432 | |
Alexandre Julliard | 5f258c6 | 2001-07-14 00:50:30 +0000 | [diff] [blame] | 433 | suspend_process( process ); |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 434 | if (!attach_process( process ) || !set_process_debugger( process, debugger )) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 435 | { |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 436 | resume_process( process ); |
| 437 | return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 438 | } |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 439 | if (!set_process_debug_flag( process, 1 )) |
| 440 | { |
| 441 | process->debugger = NULL; |
| 442 | resume_process( process ); |
| 443 | return 0; |
| 444 | } |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 445 | return 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 446 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 447 | error: |
| 448 | set_error( STATUS_ACCESS_DENIED ); |
| 449 | return 0; |
| 450 | } |
| 451 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 452 | |
| 453 | /* detach a process from a debugger thread (and resume it ?) */ |
| 454 | int debugger_detach( struct process *process, struct thread *debugger ) |
| 455 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 456 | struct debug_event *event; |
| 457 | struct debug_ctx *debug_ctx; |
| 458 | |
| 459 | if (!process->debugger || process->debugger != debugger) |
| 460 | goto error; /* not currently debugged, or debugged by another debugger */ |
| 461 | if (!debugger->debug_ctx ) goto error; /* should be a debugger */ |
| 462 | /* init should be done, otherwise wouldn't be attached */ |
Alexandre Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 463 | assert(is_process_init_done(process)); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 464 | |
| 465 | suspend_process( process ); |
| 466 | /* send continue indication for all events */ |
| 467 | debug_ctx = debugger->debug_ctx; |
| 468 | |
| 469 | /* find the event in the queue |
| 470 | * FIXME: could loop on process' threads and look the debug_event field */ |
| 471 | for (event = debug_ctx->event_head; event; event = event->next) |
| 472 | { |
| 473 | if (event->state != EVENT_QUEUED) continue; |
| 474 | |
| 475 | if (event->sender->process == process) |
| 476 | { |
| 477 | assert( event->sender->debug_event == event ); |
| 478 | event->status = DBG_CONTINUE; |
| 479 | event->state = EVENT_CONTINUED; |
| 480 | wake_up( &event->obj, 0 ); |
| 481 | unlink_event( debug_ctx, event ); |
| 482 | /* from queued debug event */ |
| 483 | resume_process( process ); |
| 484 | } |
| 485 | } |
| 486 | |
| 487 | /* remove relationships between process and its debugger */ |
| 488 | process->debugger = NULL; |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 489 | if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */ |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 490 | detach_process( process ); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 491 | |
| 492 | /* from this function */ |
| 493 | resume_process( process ); |
| 494 | return 0; |
| 495 | |
| 496 | error: |
| 497 | set_error( STATUS_ACCESS_DENIED ); |
| 498 | return 0; |
| 499 | } |
| 500 | |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 501 | /* generate all startup events of a given process */ |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 502 | void generate_startup_debug_events( struct process *process, void *entry ) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 503 | { |
| 504 | struct process_dll *dll; |
| 505 | struct thread *thread = process->thread_list; |
| 506 | |
| 507 | /* generate creation events */ |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 508 | generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT, entry ); |
Alexandre Julliard | f2f1ff3 | 2000-03-15 19:45:15 +0000 | [diff] [blame] | 509 | while ((thread = thread->proc_next)) |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 510 | generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, NULL ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 511 | |
| 512 | /* generate dll events (in loading order, i.e. reverse list order) */ |
Alexandre Julliard | 566a52a | 2001-03-05 19:34:17 +0000 | [diff] [blame] | 513 | dll = &process->exe; |
| 514 | while (dll->next) dll = dll->next; |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 515 | while (dll != &process->exe) |
| 516 | { |
| 517 | generate_debug_event( process->thread_list, LOAD_DLL_DEBUG_EVENT, dll ); |
| 518 | dll = dll->prev; |
| 519 | } |
| 520 | } |
| 521 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 522 | /* set the debugger of a given process */ |
| 523 | int set_process_debugger( struct process *process, struct thread *debugger ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 524 | { |
| 525 | struct debug_ctx *debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 526 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 527 | assert( !process->debugger ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 528 | |
| 529 | if (!debugger->debug_ctx) /* need to allocate a context */ |
| 530 | { |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 531 | if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 532 | debug_ctx->event_head = NULL; |
| 533 | debug_ctx->event_tail = NULL; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 534 | debug_ctx->kill_on_exit = 1; |
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 */ |
| 549 | kill_debugged_processes( thread, thread->exit_code ); |
| 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 | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 574 | 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 | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 587 | reply->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, FALSE ); |
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 | { |
| 619 | struct debug_event_exception data; |
| 620 | |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 621 | generate_startup_debug_events( process, NULL ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 622 | resume_process( process ); |
| 623 | |
| 624 | data.record.ExceptionCode = EXCEPTION_BREAKPOINT; |
| 625 | data.record.ExceptionFlags = EXCEPTION_CONTINUABLE; |
| 626 | data.record.ExceptionRecord = NULL; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 627 | data.record.ExceptionAddress = get_thread_ip( process->thread_list ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 628 | data.record.NumberParameters = 0; |
| 629 | data.first = 1; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 630 | generate_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 631 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 632 | release_object( process ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 633 | } |
| 634 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 635 | /* queue an exception event */ |
| 636 | DECL_HANDLER(queue_exception_event) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 637 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 638 | reply->handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 639 | if (current->process->debugger) |
| 640 | { |
| 641 | struct debug_event_exception data; |
| 642 | struct debug_event *event; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 643 | const CONTEXT *context = get_req_data(); |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 644 | EXCEPTION_RECORD *rec = (EXCEPTION_RECORD *)(context + 1); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 645 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 646 | if (get_req_data_size() < sizeof(*rec) + sizeof(*context)) |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 647 | { |
| 648 | set_error( STATUS_INVALID_PARAMETER ); |
| 649 | return; |
| 650 | } |
| 651 | data.record = *rec; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 652 | data.first = req->first; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 653 | if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 654 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 655 | if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, FALSE ))) |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 656 | { |
| 657 | link_event( event ); |
| 658 | suspend_process( current->process ); |
| 659 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 660 | release_object( event ); |
| 661 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 662 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 663 | } |
| 664 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 665 | /* retrieve the status of an exception event */ |
| 666 | DECL_HANDLER(get_exception_status) |
| 667 | { |
| 668 | struct debug_event *event; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 669 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 670 | reply->status = 0; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 671 | if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle, |
| 672 | 0, &debug_event_ops ))) |
| 673 | { |
| 674 | if (event->state == EVENT_CONTINUED) |
| 675 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 676 | reply->status = event->status; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 677 | if (current->context == &event->context) |
| 678 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 679 | size_t size = min( sizeof(CONTEXT), get_reply_max_size() ); |
| 680 | set_reply_data( &event->context, size ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 681 | current->context = NULL; |
| 682 | } |
| 683 | } |
| 684 | else set_error( STATUS_PENDING ); |
| 685 | release_object( event ); |
| 686 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 687 | } |
| 688 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 689 | /* send an output string to the debugger */ |
| 690 | DECL_HANDLER(output_debug_string) |
| 691 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 692 | struct debug_event_output_string data; |
| 693 | |
| 694 | data.string = req->string; |
| 695 | data.unicode = req->unicode; |
| 696 | data.length = req->length; |
| 697 | generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 698 | } |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 699 | |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 700 | /* simulate a breakpoint in a process */ |
| 701 | DECL_HANDLER(debug_break) |
| 702 | { |
| 703 | struct process *process; |
| 704 | |
| 705 | reply->self = 0; |
| 706 | if (!(process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION /*FIXME*/ ))) |
| 707 | return; |
| 708 | if (process != current->process) |
| 709 | { |
| 710 | /* find a suitable thread to signal */ |
| 711 | struct thread *thread; |
| 712 | for (thread = process->thread_list; thread; thread = thread->proc_next) |
| 713 | { |
Alexandre Julliard | 02a53c1 | 2003-02-25 04:17:22 +0000 | [diff] [blame] | 714 | if (send_thread_signal( thread, SIGTRAP )) break; |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 715 | } |
| 716 | if (!thread) set_error( STATUS_ACCESS_DENIED ); |
| 717 | } |
| 718 | else reply->self = 1; |
| 719 | release_object( process ); |
| 720 | } |
| 721 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 722 | /* set debugger kill on exit flag */ |
| 723 | DECL_HANDLER(set_debugger_kill_on_exit) |
| 724 | { |
| 725 | if (!current->debug_ctx) |
| 726 | { |
| 727 | set_error( STATUS_ACCESS_DENIED ); |
| 728 | return; |
| 729 | } |
| 730 | current->debug_ctx->kill_on_exit = req->kill_on_exit; |
| 731 | } |