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 |
| 5 | */ |
| 6 | |
| 7 | #include <assert.h> |
Patrik Stridvall | 2c68408 | 1999-07-31 17:36:48 +0000 | [diff] [blame] | 8 | #include <string.h> |
| 9 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 10 | #include "winbase.h" |
| 11 | #include "winerror.h" |
| 12 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 13 | #include "handle.h" |
| 14 | #include "process.h" |
| 15 | #include "thread.h" |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 16 | #include "request.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 17 | |
| 18 | struct debug_event |
| 19 | { |
| 20 | struct debug_event *next; /* event queue */ |
| 21 | struct debug_event *prev; |
| 22 | struct thread *thread; /* thread which sent this event */ |
| 23 | int sent; /* already sent to the debugger? */ |
| 24 | int code; /* event code */ |
| 25 | union debug_event_data data; /* event data */ |
| 26 | }; |
| 27 | |
| 28 | struct debug_ctx |
| 29 | { |
| 30 | struct thread *owner; /* thread owning this debug context */ |
| 31 | int waiting; /* is thread waiting for an event? */ |
| 32 | struct timeout_user *timeout; /* timeout user for wait timeout */ |
| 33 | struct debug_event *event_head; /* head of pending events queue */ |
| 34 | struct debug_event *event_tail; /* tail of pending events queue */ |
| 35 | }; |
| 36 | |
| 37 | /* size of the event data */ |
| 38 | static const int event_sizes[] = |
| 39 | { |
| 40 | 0, |
| 41 | sizeof(struct debug_event_exception), /* EXCEPTION_DEBUG_EVENT */ |
| 42 | sizeof(struct debug_event_create_thread), /* CREATE_THREAD_DEBUG_EVENT */ |
| 43 | sizeof(struct debug_event_create_process), /* CREATE_PROCESS_DEBUG_EVENT */ |
| 44 | sizeof(struct debug_event_exit), /* EXIT_THREAD_DEBUG_EVENT */ |
| 45 | sizeof(struct debug_event_exit), /* EXIT_PROCESS_DEBUG_EVENT */ |
| 46 | sizeof(struct debug_event_load_dll), /* LOAD_DLL_DEBUG_EVENT */ |
| 47 | sizeof(struct debug_event_unload_dll), /* UNLOAD_DLL_DEBUG_EVENT */ |
| 48 | sizeof(struct debug_event_output_string), /* OUTPUT_DEBUG_STRING_EVENT */ |
| 49 | sizeof(struct debug_event_rip_info) /* RIP_EVENT */ |
| 50 | }; |
| 51 | |
| 52 | |
| 53 | /* initialise the fields that do not need to be filled by the client */ |
| 54 | static int fill_debug_event( struct thread *debugger, struct thread *thread, |
| 55 | struct debug_event *event ) |
| 56 | { |
| 57 | int handle; |
| 58 | |
| 59 | /* some events need special handling */ |
| 60 | switch(event->code) |
| 61 | { |
| 62 | case CREATE_THREAD_DEBUG_EVENT: |
| 63 | if ((event->data.create_thread.handle = alloc_handle( debugger->process, thread, |
Alexandre Julliard | 3b83222 | 1999-11-14 21:02:04 +0000 | [diff] [blame] | 64 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
| 65 | THREAD_ALL_ACCESS, FALSE )) == -1) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 66 | return 0; |
| 67 | break; |
| 68 | case CREATE_PROCESS_DEBUG_EVENT: |
| 69 | if ((handle = event->data.create_process.file) != -1) |
| 70 | { |
| 71 | if ((handle = duplicate_handle( thread->process, handle, debugger->process, |
| 72 | GENERIC_READ, FALSE, 0 )) == -1) |
| 73 | return 0; |
| 74 | event->data.create_process.file = handle; |
| 75 | } |
| 76 | if ((event->data.create_process.process = alloc_handle( debugger->process, thread->process, |
Alexandre Julliard | 3b83222 | 1999-11-14 21:02:04 +0000 | [diff] [blame] | 77 | /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ |
| 78 | PROCESS_ALL_ACCESS, FALSE )) == -1) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 79 | { |
| 80 | if (handle != -1) close_handle( debugger->process, handle ); |
| 81 | return 0; |
| 82 | } |
| 83 | if ((event->data.create_process.thread = alloc_handle( debugger->process, thread, |
Alexandre Julliard | 3b83222 | 1999-11-14 21:02:04 +0000 | [diff] [blame] | 84 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
| 85 | THREAD_ALL_ACCESS, FALSE )) == -1) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 86 | { |
| 87 | if (handle != -1) close_handle( debugger->process, handle ); |
| 88 | close_handle( debugger->process, event->data.create_process.process ); |
| 89 | return 0; |
| 90 | } |
| 91 | break; |
| 92 | case LOAD_DLL_DEBUG_EVENT: |
| 93 | if ((handle = event->data.load_dll.handle) != -1) |
| 94 | { |
| 95 | if ((handle = duplicate_handle( thread->process, handle, debugger->process, |
| 96 | GENERIC_READ, FALSE, 0 )) == -1) |
| 97 | return 0; |
| 98 | event->data.load_dll.handle = handle; |
| 99 | } |
| 100 | break; |
| 101 | } |
| 102 | return 1; |
| 103 | } |
| 104 | |
| 105 | /* free a debug event structure */ |
Alexandre Julliard | 1d22c53 | 1999-11-04 02:31:10 +0000 | [diff] [blame] | 106 | static void free_event( struct thread *debugger, struct debug_event *event ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 107 | { |
Alexandre Julliard | c61eb03 | 1999-11-07 23:59:08 +0000 | [diff] [blame] | 108 | /* If the event has been sent already, the handles are now under the */ |
| 109 | /* responsibility of the debugger process, so we don't touch them */ |
| 110 | if (!event->sent) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 111 | { |
Alexandre Julliard | c61eb03 | 1999-11-07 23:59:08 +0000 | [diff] [blame] | 112 | switch(event->code) |
| 113 | { |
| 114 | case CREATE_THREAD_DEBUG_EVENT: |
| 115 | close_handle( debugger->process, event->data.create_thread.handle ); |
| 116 | break; |
| 117 | case CREATE_PROCESS_DEBUG_EVENT: |
| 118 | if (event->data.create_process.file != -1) |
| 119 | close_handle( debugger->process, event->data.create_process.file ); |
| 120 | close_handle( debugger->process, event->data.create_process.thread ); |
| 121 | close_handle( debugger->process, event->data.create_process.process ); |
| 122 | break; |
| 123 | case LOAD_DLL_DEBUG_EVENT: |
| 124 | if (event->data.load_dll.handle != -1) |
| 125 | close_handle( debugger->process, event->data.load_dll.handle ); |
| 126 | break; |
| 127 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 128 | } |
| 129 | event->thread->debug_event = NULL; |
| 130 | release_object( event->thread ); |
| 131 | free( event ); |
| 132 | } |
| 133 | |
| 134 | /* unlink the first event from the queue */ |
| 135 | static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) |
| 136 | { |
| 137 | if (event->prev) event->prev->next = event->next; |
| 138 | else debug_ctx->event_head = event->next; |
| 139 | if (event->next) event->next->prev = event->prev; |
| 140 | else debug_ctx->event_tail = event->prev; |
| 141 | event->next = event->prev = NULL; |
| 142 | } |
| 143 | |
| 144 | /* link an event at the end of the queue */ |
| 145 | static void link_event( struct debug_ctx *debug_ctx, struct debug_event *event ) |
| 146 | { |
| 147 | event->next = NULL; |
| 148 | event->prev = debug_ctx->event_tail; |
| 149 | if (event->prev) event->prev->next = event; |
| 150 | else debug_ctx->event_head = event; |
| 151 | debug_ctx->event_tail = event; |
| 152 | } |
| 153 | |
| 154 | /* send the first queue event as a reply */ |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 155 | static void build_event_reply( struct debug_ctx *debug_ctx ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 156 | { |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 157 | struct debug_event *event = debug_ctx->event_head; |
| 158 | struct thread *thread = event->thread; |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 159 | struct wait_debug_event_request *req = get_req_ptr( debug_ctx->owner ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 160 | |
| 161 | assert( event ); |
| 162 | assert( debug_ctx->waiting ); |
| 163 | |
| 164 | unlink_event( debug_ctx, event ); |
| 165 | event->sent = 1; |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 166 | req->code = event->code; |
| 167 | req->pid = thread->process; |
| 168 | req->tid = thread; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 169 | debug_ctx->waiting = 0; |
| 170 | if (debug_ctx->timeout) |
| 171 | { |
| 172 | remove_timeout_user( debug_ctx->timeout ); |
| 173 | debug_ctx->timeout = NULL; |
| 174 | } |
| 175 | debug_ctx->owner->error = 0; |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 176 | memcpy( req + 1, &event->data, event_sizes[event->code] ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | /* timeout callback while waiting for a debug event */ |
| 180 | static void wait_event_timeout( void *ctx ) |
| 181 | { |
| 182 | struct debug_ctx *debug_ctx = (struct debug_ctx *)ctx; |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 183 | struct wait_debug_event_request *req = get_req_ptr( debug_ctx->owner ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 184 | |
| 185 | assert( debug_ctx->waiting ); |
| 186 | |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 187 | req->code = 0; |
| 188 | req->pid = 0; |
| 189 | req->tid = 0; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 190 | debug_ctx->waiting = 0; |
| 191 | debug_ctx->timeout = NULL; |
| 192 | debug_ctx->owner->error = WAIT_TIMEOUT; |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 193 | send_reply( debug_ctx->owner ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 194 | } |
| 195 | |
| 196 | /* wait for a debug event (or send a reply at once if one is pending) */ |
| 197 | static int wait_for_debug_event( int timeout ) |
| 198 | { |
| 199 | struct debug_ctx *debug_ctx = current->debug_ctx; |
| 200 | struct timeval when; |
| 201 | |
| 202 | if (!debug_ctx) /* current thread is not a debugger */ |
| 203 | { |
Alexandre Julliard | 3b83222 | 1999-11-14 21:02:04 +0000 | [diff] [blame] | 204 | set_error( ERROR_INVALID_HANDLE ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 205 | return 0; |
| 206 | } |
| 207 | assert( !debug_ctx->waiting ); |
| 208 | if (debug_ctx->event_head) /* already have a pending event */ |
| 209 | { |
| 210 | debug_ctx->waiting = 1; |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 211 | build_event_reply( debug_ctx ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 212 | return 1; |
| 213 | } |
| 214 | if (!timeout) /* no event and we don't want to wait */ |
| 215 | { |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 216 | set_error( WAIT_TIMEOUT ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 217 | return 0; |
| 218 | } |
| 219 | if (timeout != -1) /* start the timeout */ |
| 220 | { |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame^] | 221 | gettimeofday( &when, 0 ); |
| 222 | add_timeout( &when, timeout ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 223 | if (!(debug_ctx->timeout = add_timeout_user( &when, wait_event_timeout, debug_ctx ))) |
| 224 | return 0; |
| 225 | } |
| 226 | debug_ctx->waiting = 1; |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 227 | current->state = SLEEPING; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 228 | return 1; |
| 229 | } |
| 230 | |
| 231 | /* continue a debug event */ |
| 232 | static int continue_debug_event( struct process *process, struct thread *thread, int status ) |
| 233 | { |
| 234 | struct debug_event *event = thread->debug_event; |
| 235 | |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 236 | if (process->debugger != current || thread->process != process || !event || !event->sent) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 237 | { |
| 238 | /* not debugging this process, or no event pending */ |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 239 | set_error( ERROR_ACCESS_DENIED ); /* FIXME */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 240 | return 0; |
| 241 | } |
| 242 | if (thread->state != TERMINATED) |
| 243 | { |
| 244 | /* only send a reply if the thread is still there */ |
| 245 | /* (we can get a continue on an exit thread/process event) */ |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 246 | struct send_debug_event_request *req = get_req_ptr( thread ); |
| 247 | req->status = status; |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 248 | /* copy the context into the reply */ |
| 249 | if (event->code == EXCEPTION_DEBUG_EVENT) |
| 250 | memcpy( req + 1, &event->data, event_sizes[event->code] ); |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 251 | send_reply( thread ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 252 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 253 | |
Alexandre Julliard | 1d22c53 | 1999-11-04 02:31:10 +0000 | [diff] [blame] | 254 | free_event( current, event ); |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 255 | |
| 256 | if (thread->exit_event) |
| 257 | { |
| 258 | /* we still have a queued exit event, promote it to normal event */ |
| 259 | thread->debug_event = thread->exit_event; |
| 260 | thread->exit_event = NULL; |
| 261 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 262 | resume_process( process ); |
| 263 | return 1; |
| 264 | } |
| 265 | |
| 266 | /* queue a debug event for a debugger */ |
| 267 | static struct debug_event *queue_debug_event( struct thread *debugger, struct thread *thread, |
| 268 | int code, void *data ) |
| 269 | { |
| 270 | struct debug_ctx *debug_ctx = debugger->debug_ctx; |
| 271 | struct debug_event *event; |
| 272 | |
| 273 | assert( debug_ctx ); |
| 274 | /* cannot queue a debug event for myself */ |
| 275 | assert( debugger->process != thread->process ); |
| 276 | |
| 277 | /* build the event */ |
| 278 | if (!(event = mem_alloc( sizeof(*event) - sizeof(event->data) + event_sizes[code] ))) |
| 279 | return NULL; |
| 280 | event->sent = 0; |
| 281 | event->code = code; |
| 282 | event->thread = (struct thread *)grab_object( thread ); |
| 283 | memcpy( &event->data, data, event_sizes[code] ); |
| 284 | |
| 285 | if (!fill_debug_event( debugger, thread, event )) |
| 286 | { |
| 287 | release_object( event->thread ); |
| 288 | free( event ); |
| 289 | return NULL; |
| 290 | } |
| 291 | |
| 292 | if (thread->debug_event) |
| 293 | { |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 294 | /* exit events can happen while another one is still queued */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 295 | assert( code == EXIT_THREAD_DEBUG_EVENT || code == EXIT_PROCESS_DEBUG_EVENT ); |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 296 | thread->exit_event = event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 297 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 298 | else thread->debug_event = event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 299 | |
| 300 | link_event( debug_ctx, event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 301 | suspend_process( thread->process ); |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 302 | if (debug_ctx->waiting) |
| 303 | { |
| 304 | build_event_reply( debug_ctx ); |
| 305 | send_reply( debug_ctx->owner ); |
| 306 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 307 | return event; |
| 308 | } |
| 309 | |
| 310 | /* attach a process to a debugger thread */ |
| 311 | int debugger_attach( struct process *process, struct thread *debugger ) |
| 312 | { |
| 313 | struct debug_ctx *debug_ctx; |
| 314 | struct thread *thread; |
| 315 | |
| 316 | if (process->debugger) /* already being debugged */ |
| 317 | { |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 318 | set_error( ERROR_ACCESS_DENIED ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 319 | return 0; |
| 320 | } |
| 321 | /* make sure we don't create a debugging loop */ |
| 322 | for (thread = debugger; thread; thread = thread->process->debugger) |
| 323 | if (thread->process == process) |
| 324 | { |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 325 | set_error( ERROR_ACCESS_DENIED ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 326 | return 0; |
| 327 | } |
| 328 | |
| 329 | if (!debugger->debug_ctx) /* need to allocate a context */ |
| 330 | { |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 331 | if (!(debug_ctx = mem_alloc( sizeof(*debug_ctx) ))) return 0; |
| 332 | debug_ctx->owner = current; |
| 333 | debug_ctx->waiting = 0; |
| 334 | debug_ctx->timeout = NULL; |
| 335 | debug_ctx->event_head = NULL; |
| 336 | debug_ctx->event_tail = NULL; |
| 337 | debugger->debug_ctx = debug_ctx; |
| 338 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 339 | process->debugger = debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 340 | return 1; |
| 341 | } |
| 342 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 343 | /* a thread is exiting */ |
| 344 | void debug_exit_thread( struct thread *thread, int exit_code ) |
| 345 | { |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 346 | struct thread *debugger = thread->process->debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 347 | struct debug_ctx *debug_ctx = thread->debug_ctx; |
| 348 | |
| 349 | if (debugger) /* being debugged -> send an event to the debugger */ |
| 350 | { |
| 351 | struct debug_event_exit event; |
| 352 | event.exit_code = exit_code; |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 353 | if (thread->process->running_threads == 1) |
| 354 | /* this is the last thread, send an exit process event */ |
| 355 | queue_debug_event( debugger, thread, EXIT_PROCESS_DEBUG_EVENT, &event ); |
| 356 | else |
| 357 | queue_debug_event( debugger, thread, EXIT_THREAD_DEBUG_EVENT, &event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 358 | } |
| 359 | |
| 360 | if (debug_ctx) /* this thread is a debugger */ |
| 361 | { |
| 362 | struct debug_event *event; |
| 363 | |
| 364 | /* kill all debugged processes */ |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 365 | kill_debugged_processes( thread, exit_code ); |
| 366 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 367 | /* free all pending events */ |
| 368 | while ((event = debug_ctx->event_head) != NULL) |
| 369 | { |
| 370 | unlink_event( debug_ctx, event ); |
Alexandre Julliard | 1d22c53 | 1999-11-04 02:31:10 +0000 | [diff] [blame] | 371 | free_event( thread, event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 372 | } |
| 373 | /* remove the timeout */ |
| 374 | if (debug_ctx->timeout) remove_timeout_user( debug_ctx->timeout ); |
| 375 | thread->debug_ctx = NULL; |
| 376 | free( debug_ctx ); |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | /* Wait for a debug event */ |
| 381 | DECL_HANDLER(wait_debug_event) |
| 382 | { |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 383 | if (!wait_for_debug_event( req->timeout )) |
| 384 | { |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 385 | req->code = 0; |
| 386 | req->pid = NULL; |
| 387 | req->tid = NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 388 | } |
| 389 | } |
| 390 | |
| 391 | /* Continue a debug event */ |
| 392 | DECL_HANDLER(continue_debug_event) |
| 393 | { |
| 394 | struct process *process = get_process_from_id( req->pid ); |
| 395 | if (process) |
| 396 | { |
| 397 | struct thread *thread = get_thread_from_id( req->tid ); |
| 398 | if (thread) |
| 399 | { |
| 400 | continue_debug_event( process, thread, req->status ); |
| 401 | release_object( thread ); |
| 402 | } |
| 403 | release_object( process ); |
| 404 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 405 | } |
| 406 | |
| 407 | /* Start debugging an existing process */ |
| 408 | DECL_HANDLER(debug_process) |
| 409 | { |
| 410 | struct process *process = get_process_from_id( req->pid ); |
| 411 | if (process) |
| 412 | { |
| 413 | debugger_attach( process, current ); |
| 414 | /* FIXME: should notice the debugged process somehow */ |
| 415 | release_object( process ); |
| 416 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 417 | } |
| 418 | |
| 419 | /* Send a debug event */ |
| 420 | DECL_HANDLER(send_debug_event) |
| 421 | { |
| 422 | struct thread *debugger = current->process->debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 423 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 424 | assert( !current->debug_event ); |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 425 | if ((req->code <= 0) || (req->code > RIP_EVENT)) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 426 | { |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 427 | fatal_protocol_error( current, "send_debug_event: bad code %d\n", req->code ); |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 428 | return; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 429 | } |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 430 | req->status = 0; |
| 431 | if (debugger && queue_debug_event( debugger, current, req->code, req + 1 )) |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 432 | { |
| 433 | /* wait for continue_debug_event */ |
| 434 | current->state = SLEEPING; |
| 435 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 436 | } |