Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Server-side debugger functions |
| 3 | * |
| 4 | * Copyright (C) 1999 Alexandre Julliard |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, write to the Free Software |
Jonathan Ernst | 360a3f9 | 2006-05-18 14:49:52 +0200 | [diff] [blame] | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 19 | */ |
| 20 | |
Alexandre Julliard | 5769d1d | 2002-04-26 19:05:15 +0000 | [diff] [blame] | 21 | #include "config.h" |
| 22 | #include "wine/port.h" |
| 23 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 24 | #include <assert.h> |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 25 | #include <signal.h> |
Patrik Stridvall | 2c68408 | 1999-07-31 17:36:48 +0000 | [diff] [blame] | 26 | #include <string.h> |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 27 | #include <stdarg.h> |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 28 | #include <stdio.h> |
Patrik Stridvall | 2c68408 | 1999-07-31 17:36:48 +0000 | [diff] [blame] | 29 | |
Ge van Geldorp | 1a1583a | 2005-11-28 17:32:54 +0100 | [diff] [blame] | 30 | #include "ntstatus.h" |
| 31 | #define WIN32_NO_STATUS |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 32 | #include "windef.h" |
Ge van Geldorp | 1a1583a | 2005-11-28 17:32:54 +0100 | [diff] [blame] | 33 | #include "winternl.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 34 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 35 | #include "handle.h" |
| 36 | #include "process.h" |
| 37 | #include "thread.h" |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 38 | #include "request.h" |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 39 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 40 | enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED }; |
| 41 | |
| 42 | /* debug event */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 43 | struct debug_event |
| 44 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 45 | struct object obj; /* object header */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 46 | struct list entry; /* entry in event queue */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 47 | struct thread *sender; /* thread which sent this event */ |
| 48 | struct thread *debugger; /* debugger thread receiving the event */ |
| 49 | enum debug_event_state state; /* event state */ |
| 50 | int status; /* continuation status */ |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 51 | debug_event_t data; /* event data */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 52 | CONTEXT context; /* register context */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 53 | }; |
| 54 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 55 | /* debug context */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 56 | struct debug_ctx |
| 57 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 58 | struct object obj; /* object header */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 59 | struct list event_queue; /* pending events queue */ |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 60 | int kill_on_exit;/* kill debuggees on debugger exit ? */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 61 | }; |
| 62 | |
| 63 | |
| 64 | static void debug_event_dump( struct object *obj, int verbose ); |
| 65 | static int debug_event_signaled( struct object *obj, struct thread *thread ); |
| 66 | static void debug_event_destroy( struct object *obj ); |
| 67 | |
| 68 | static const struct object_ops debug_event_ops = |
| 69 | { |
| 70 | sizeof(struct debug_event), /* size */ |
| 71 | debug_event_dump, /* dump */ |
Alexandre Julliard | 8382eb0 | 2007-12-05 18:16:42 +0100 | [diff] [blame] | 72 | no_get_type, /* get_type */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 73 | add_queue, /* add_queue */ |
| 74 | remove_queue, /* remove_queue */ |
| 75 | debug_event_signaled, /* signaled */ |
| 76 | no_satisfied, /* satisfied */ |
Mike McCormack | f92fff6 | 2005-04-24 17:35:52 +0000 | [diff] [blame] | 77 | no_signal, /* signal */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 78 | no_get_fd, /* get_fd */ |
Alexandre Julliard | 28beba3 | 2005-12-12 14:57:40 +0100 | [diff] [blame] | 79 | no_map_access, /* map_access */ |
Rob Shearman | c1707d8 | 2007-10-03 13:10:37 +0100 | [diff] [blame] | 80 | default_get_sd, /* get_sd */ |
| 81 | default_set_sd, /* set_sd */ |
Vitaliy Margolen | baffcb9 | 2005-11-22 14:55:42 +0000 | [diff] [blame] | 82 | no_lookup_name, /* lookup_name */ |
Alexandre Julliard | 7e71c1d | 2007-03-22 11:44:29 +0100 | [diff] [blame] | 83 | no_open_file, /* open_file */ |
Alexandre Julliard | b9b1ea9 | 2005-06-09 15:39:52 +0000 | [diff] [blame] | 84 | no_close_handle, /* close_handle */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 85 | debug_event_destroy /* destroy */ |
| 86 | }; |
| 87 | |
| 88 | static void debug_ctx_dump( struct object *obj, int verbose ); |
| 89 | static int debug_ctx_signaled( struct object *obj, struct thread *thread ); |
| 90 | static void debug_ctx_destroy( struct object *obj ); |
| 91 | |
| 92 | static const struct object_ops debug_ctx_ops = |
| 93 | { |
| 94 | sizeof(struct debug_ctx), /* size */ |
| 95 | debug_ctx_dump, /* dump */ |
Alexandre Julliard | 8382eb0 | 2007-12-05 18:16:42 +0100 | [diff] [blame] | 96 | no_get_type, /* get_type */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 97 | add_queue, /* add_queue */ |
| 98 | remove_queue, /* remove_queue */ |
| 99 | debug_ctx_signaled, /* signaled */ |
| 100 | no_satisfied, /* satisfied */ |
Mike McCormack | f92fff6 | 2005-04-24 17:35:52 +0000 | [diff] [blame] | 101 | no_signal, /* signal */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 102 | no_get_fd, /* get_fd */ |
Alexandre Julliard | 28beba3 | 2005-12-12 14:57:40 +0100 | [diff] [blame] | 103 | no_map_access, /* map_access */ |
Rob Shearman | c1707d8 | 2007-10-03 13:10:37 +0100 | [diff] [blame] | 104 | default_get_sd, /* get_sd */ |
| 105 | default_set_sd, /* set_sd */ |
Vitaliy Margolen | baffcb9 | 2005-11-22 14:55:42 +0000 | [diff] [blame] | 106 | no_lookup_name, /* lookup_name */ |
Alexandre Julliard | 7e71c1d | 2007-03-22 11:44:29 +0100 | [diff] [blame] | 107 | no_open_file, /* open_file */ |
Alexandre Julliard | b9b1ea9 | 2005-06-09 15:39:52 +0000 | [diff] [blame] | 108 | no_close_handle, /* close_handle */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 109 | debug_ctx_destroy /* destroy */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 110 | }; |
| 111 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 112 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 113 | /* routines to build an event according to its type */ |
| 114 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 115 | static int fill_exception_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 116 | { |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 117 | const debug_event_t *data = arg; |
| 118 | event->data.exception = data->exception; |
Alexandre Julliard | 9f365e7 | 2009-01-02 20:12:46 +0100 | [diff] [blame] | 119 | event->data.exception.nb_params = min( event->data.exception.nb_params, EXCEPTION_MAXIMUM_PARAMETERS ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 120 | return 1; |
| 121 | } |
| 122 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 123 | static int fill_create_thread_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 124 | { |
| 125 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 126 | struct thread *thread = event->sender; |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 127 | const client_ptr_t *entry = arg; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 128 | obj_handle_t handle; |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 129 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 130 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 131 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, 0 ))) return 0; |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 132 | event->data.create_thread.handle = handle; |
| 133 | event->data.create_thread.teb = thread->teb; |
| 134 | if (entry) event->data.create_thread.start = *entry; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 135 | return 1; |
| 136 | } |
| 137 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 138 | static int fill_create_process_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 139 | { |
| 140 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | b73421d | 2000-03-30 19:30:24 +0000 | [diff] [blame] | 141 | struct thread *thread = event->sender; |
| 142 | struct process *process = thread->process; |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 143 | struct process_dll *exe_module = get_process_exe_module( process ); |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 144 | const client_ptr_t *entry = arg; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 145 | obj_handle_t handle; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 146 | |
| 147 | /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */ |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 148 | if (!(handle = alloc_handle( debugger, process, PROCESS_ALL_ACCESS, 0 ))) return 0; |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 149 | event->data.create_process.process = handle; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 150 | |
| 151 | /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */ |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 152 | if (!(handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, 0 ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 153 | { |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 154 | close_handle( debugger, event->data.create_process.process ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 155 | return 0; |
| 156 | } |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 157 | event->data.create_process.thread = handle; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 158 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 159 | handle = 0; |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 160 | if (exe_module->file && |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 161 | /* the doc says write access too, but this doesn't seem a good idea */ |
Alexandre Julliard | e6374cb | 2006-02-16 12:13:01 +0100 | [diff] [blame] | 162 | !(handle = alloc_handle( debugger, exe_module->file, GENERIC_READ, 0 ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 163 | { |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 164 | close_handle( debugger, event->data.create_process.process ); |
| 165 | close_handle( debugger, event->data.create_process.thread ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 166 | return 0; |
| 167 | } |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 168 | event->data.create_process.file = handle; |
| 169 | event->data.create_process.teb = thread->teb; |
| 170 | event->data.create_process.base = exe_module->base; |
| 171 | event->data.create_process.start = *entry; |
| 172 | event->data.create_process.dbg_offset = exe_module->dbg_offset; |
| 173 | event->data.create_process.dbg_size = exe_module->dbg_size; |
| 174 | event->data.create_process.name = exe_module->name; |
| 175 | event->data.create_process.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 176 | return 1; |
| 177 | } |
| 178 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 179 | static int fill_exit_thread_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 180 | { |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 181 | const struct thread *thread = arg; |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 182 | event->data.exit.exit_code = thread->exit_code; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 183 | return 1; |
| 184 | } |
| 185 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 186 | static int fill_exit_process_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 187 | { |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 188 | const struct process *process = arg; |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 189 | event->data.exit.exit_code = process->exit_code; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 190 | return 1; |
| 191 | } |
| 192 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 193 | static int fill_load_dll_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 194 | { |
| 195 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 196 | const struct process_dll *dll = arg; |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 197 | obj_handle_t handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 198 | |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 199 | if (dll->file && !(handle = alloc_handle( debugger, dll->file, GENERIC_READ, 0 ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 200 | return 0; |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 201 | event->data.load_dll.handle = handle; |
| 202 | event->data.load_dll.base = dll->base; |
| 203 | event->data.load_dll.dbg_offset = dll->dbg_offset; |
| 204 | event->data.load_dll.dbg_size = dll->dbg_size; |
| 205 | event->data.load_dll.name = dll->name; |
| 206 | event->data.load_dll.unicode = 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 207 | return 1; |
| 208 | } |
| 209 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 210 | static int fill_unload_dll_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 211 | { |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 212 | const mod_handle_t *base = arg; |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 213 | event->data.unload_dll.base = *base; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 214 | return 1; |
| 215 | } |
| 216 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 217 | static int fill_output_debug_string_event( struct debug_event *event, const void *arg ) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 218 | { |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 219 | const debug_event_t *data = arg; |
| 220 | event->data.output_string = data->output_string; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 221 | return 1; |
| 222 | } |
| 223 | |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 224 | typedef int (*fill_event_func)( struct debug_event *event, const void *arg ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 225 | |
| 226 | #define NB_DEBUG_EVENTS OUTPUT_DEBUG_STRING_EVENT /* RIP_EVENT not supported */ |
| 227 | |
| 228 | static const fill_event_func fill_debug_event[NB_DEBUG_EVENTS] = |
| 229 | { |
| 230 | fill_exception_event, /* EXCEPTION_DEBUG_EVENT */ |
| 231 | fill_create_thread_event, /* CREATE_THREAD_DEBUG_EVENT */ |
| 232 | fill_create_process_event, /* CREATE_PROCESS_DEBUG_EVENT */ |
| 233 | fill_exit_thread_event, /* EXIT_THREAD_DEBUG_EVENT */ |
| 234 | fill_exit_process_event, /* EXIT_PROCESS_DEBUG_EVENT */ |
| 235 | fill_load_dll_event, /* LOAD_DLL_DEBUG_EVENT */ |
| 236 | fill_unload_dll_event, /* UNLOAD_DLL_DEBUG_EVENT */ |
| 237 | fill_output_debug_string_event /* OUTPUT_DEBUG_STRING_EVENT */ |
| 238 | }; |
| 239 | |
| 240 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 241 | /* unlink the first event from the queue */ |
| 242 | static void unlink_event( struct debug_ctx *debug_ctx, struct debug_event *event ) |
| 243 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 244 | list_remove( &event->entry ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 245 | if (event->sender->debug_event == event) event->sender->debug_event = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 246 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | /* link an event at the end of the queue */ |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 250 | static void link_event( struct debug_event *event ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 251 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 252 | struct debug_ctx *debug_ctx = event->debugger->debug_ctx; |
| 253 | |
| 254 | assert( debug_ctx ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 255 | grab_object( event ); |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 256 | list_add_tail( &debug_ctx->event_queue, &event->entry ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 257 | if (!event->sender->debug_event) wake_up( &debug_ctx->obj, 0 ); |
| 258 | } |
| 259 | |
| 260 | /* find the next event that we can send to the debugger */ |
| 261 | static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx ) |
| 262 | { |
| 263 | struct debug_event *event; |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 264 | |
| 265 | 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] | 266 | { |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 267 | if (event->state == EVENT_SENT) continue; /* already sent */ |
| 268 | if (event->sender->debug_event) continue; /* thread busy with another one */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 269 | return event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 270 | } |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 271 | return NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 272 | } |
| 273 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 274 | static void debug_event_dump( struct object *obj, int verbose ) |
| 275 | { |
| 276 | struct debug_event *debug_event = (struct debug_event *)obj; |
| 277 | assert( obj->ops == &debug_event_ops ); |
| 278 | fprintf( stderr, "Debug event sender=%p code=%d state=%d\n", |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 279 | debug_event->sender, debug_event->data.code, debug_event->state ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | static int debug_event_signaled( struct object *obj, struct thread *thread ) |
| 283 | { |
| 284 | struct debug_event *debug_event = (struct debug_event *)obj; |
| 285 | assert( obj->ops == &debug_event_ops ); |
| 286 | return debug_event->state == EVENT_CONTINUED; |
| 287 | } |
| 288 | |
| 289 | static void debug_event_destroy( struct object *obj ) |
| 290 | { |
| 291 | struct debug_event *event = (struct debug_event *)obj; |
| 292 | assert( obj->ops == &debug_event_ops ); |
| 293 | |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 294 | /* If the event has been sent already, the handles are now under the */ |
| 295 | /* responsibility of the debugger process, so we don't touch them */ |
| 296 | if (event->state == EVENT_QUEUED) |
| 297 | { |
| 298 | struct process *debugger = event->debugger->process; |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 299 | switch(event->data.code) |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 300 | { |
| 301 | case CREATE_THREAD_DEBUG_EVENT: |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 302 | close_handle( debugger, event->data.create_thread.handle ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 303 | break; |
| 304 | case CREATE_PROCESS_DEBUG_EVENT: |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 305 | if (event->data.create_process.file) |
| 306 | close_handle( debugger, event->data.create_process.file ); |
| 307 | close_handle( debugger, event->data.create_process.thread ); |
| 308 | close_handle( debugger, event->data.create_process.process ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 309 | break; |
| 310 | case LOAD_DLL_DEBUG_EVENT: |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 311 | if (event->data.load_dll.handle) |
| 312 | close_handle( debugger, event->data.load_dll.handle ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 313 | break; |
| 314 | } |
| 315 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 316 | if (event->sender->context == &event->context) event->sender->context = NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 317 | release_object( event->sender ); |
| 318 | release_object( event->debugger ); |
| 319 | } |
| 320 | |
| 321 | static void debug_ctx_dump( struct object *obj, int verbose ) |
| 322 | { |
| 323 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 324 | assert( obj->ops == &debug_ctx_ops ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 325 | fprintf( stderr, "Debug context head=%p tail=%p\n", |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 326 | debug_ctx->event_queue.next, debug_ctx->event_queue.prev ); |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | static int debug_ctx_signaled( struct object *obj, struct thread *thread ) |
| 330 | { |
| 331 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 332 | assert( obj->ops == &debug_ctx_ops ); |
Alexandre Julliard | f6507ed | 2000-04-06 22:05:16 +0000 | [diff] [blame] | 333 | return find_event_to_send( debug_ctx ) != NULL; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 334 | } |
| 335 | |
| 336 | static void debug_ctx_destroy( struct object *obj ) |
| 337 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 338 | struct list *ptr; |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 339 | struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; |
| 340 | assert( obj->ops == &debug_ctx_ops ); |
| 341 | |
| 342 | /* free all pending events */ |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 343 | while ((ptr = list_head( &debug_ctx->event_queue ))) |
| 344 | unlink_event( debug_ctx, LIST_ENTRY( ptr, struct debug_event, entry )); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 345 | } |
| 346 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 347 | /* continue a debug event */ |
| 348 | static int continue_debug_event( struct process *process, struct thread *thread, int status ) |
| 349 | { |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 350 | struct debug_ctx *debug_ctx = current->debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 351 | |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 352 | if (debug_ctx && process->debugger == current && thread->process == process) |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 353 | { |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 354 | struct debug_event *event; |
| 355 | |
| 356 | /* find the event in the queue */ |
| 357 | LIST_FOR_EACH_ENTRY( event, &debug_ctx->event_queue, struct debug_event, entry ) |
| 358 | { |
| 359 | if (event->state != EVENT_SENT) continue; |
| 360 | if (event->sender == thread) |
| 361 | { |
| 362 | assert( event->sender->debug_event == event ); |
| 363 | |
| 364 | event->status = status; |
| 365 | event->state = EVENT_CONTINUED; |
| 366 | wake_up( &event->obj, 0 ); |
| 367 | unlink_event( debug_ctx, event ); |
| 368 | resume_process( process ); |
| 369 | return 1; |
| 370 | } |
| 371 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 372 | } |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 373 | /* not debugging this process, or no such event */ |
Alexandre Julliard | cb1fc73 | 2000-01-24 21:58:06 +0000 | [diff] [blame] | 374 | set_error( STATUS_ACCESS_DENIED ); /* FIXME */ |
Alexandre Julliard | 79b1ec8 | 2000-01-04 02:24:43 +0000 | [diff] [blame] | 375 | return 0; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 376 | } |
| 377 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 378 | /* alloc a debug event for a debugger */ |
Alexandre Julliard | 9f365e7 | 2009-01-02 20:12:46 +0100 | [diff] [blame] | 379 | static struct debug_event *alloc_debug_event( struct thread *thread, int code, const void *arg ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 380 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 381 | struct thread *debugger = thread->process->debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 382 | struct debug_event *event; |
| 383 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 384 | assert( code > 0 && code <= NB_DEBUG_EVENTS ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 385 | /* cannot queue a debug event for myself */ |
| 386 | assert( debugger->process != thread->process ); |
| 387 | |
| 388 | /* build the event */ |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 389 | if (!(event = alloc_object( &debug_event_ops ))) return NULL; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 390 | event->state = EVENT_QUEUED; |
| 391 | event->sender = (struct thread *)grab_object( thread ); |
| 392 | event->debugger = (struct thread *)grab_object( debugger ); |
Alexandre Julliard | 9087e5c | 2009-01-02 20:00:54 +0100 | [diff] [blame] | 393 | memset( &event->data, 0, sizeof(event->data) ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 394 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 395 | if (!fill_debug_event[code-1]( event, arg )) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 396 | { |
Alexandre Julliard | 3e2517c | 2000-01-20 18:59:03 +0000 | [diff] [blame] | 397 | 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] | 398 | release_object( event ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 399 | return NULL; |
| 400 | } |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 401 | event->data.code = code; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 402 | return event; |
| 403 | } |
| 404 | |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 405 | /* generate a debug event from inside the server and queue it */ |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 406 | void generate_debug_event( struct thread *thread, int code, const void *arg ) |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 407 | { |
| 408 | if (thread->process->debugger) |
| 409 | { |
Alexandre Julliard | 9f365e7 | 2009-01-02 20:12:46 +0100 | [diff] [blame] | 410 | struct debug_event *event = alloc_debug_event( thread, code, arg ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 411 | if (event) |
| 412 | { |
| 413 | link_event( event ); |
| 414 | suspend_process( thread->process ); |
| 415 | release_object( event ); |
| 416 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 417 | } |
| 418 | } |
| 419 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 420 | /* attach a process to a debugger thread and suspend it */ |
| 421 | static int debugger_attach( struct process *process, struct thread *debugger ) |
| 422 | { |
| 423 | struct thread *thread; |
| 424 | |
| 425 | if (process->debugger) goto error; /* already being debugged */ |
Alexandre Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 426 | if (!is_process_init_done( process )) goto error; /* still starting up */ |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 427 | 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] | 428 | |
| 429 | /* make sure we don't create a debugging loop */ |
| 430 | for (thread = debugger; thread; thread = thread->process->debugger) |
| 431 | if (thread->process == process) goto error; |
| 432 | |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 433 | /* don't let a debugger debug its console... won't work */ |
Alexandre Julliard | 627ca40 | 2007-05-11 12:46:32 +0200 | [diff] [blame] | 434 | if (debugger->process->console && console_get_renderer(debugger->process->console)->process == process) |
Eric Pouech | 3940d8a | 2001-12-04 20:17:43 +0000 | [diff] [blame] | 435 | goto error; |
Eric Pouech | 0b83d4c | 2001-11-23 23:04:58 +0000 | [diff] [blame] | 436 | |
Alexandre Julliard | 5f258c6 | 2001-07-14 00:50:30 +0000 | [diff] [blame] | 437 | suspend_process( process ); |
Alexandre Julliard | 820c592 | 2006-04-10 20:25:22 +0200 | [diff] [blame] | 438 | if (!set_process_debugger( process, debugger )) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 439 | { |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 440 | resume_process( process ); |
| 441 | return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 442 | } |
Alexandre Julliard | e55d593 | 2003-10-14 01:30:42 +0000 | [diff] [blame] | 443 | if (!set_process_debug_flag( process, 1 )) |
| 444 | { |
| 445 | process->debugger = NULL; |
| 446 | resume_process( process ); |
| 447 | return 0; |
| 448 | } |
Alexandre Julliard | baf0a06 | 2003-03-11 01:48:53 +0000 | [diff] [blame] | 449 | return 1; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 450 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 451 | error: |
| 452 | set_error( STATUS_ACCESS_DENIED ); |
| 453 | return 0; |
| 454 | } |
| 455 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 456 | |
| 457 | /* detach a process from a debugger thread (and resume it ?) */ |
| 458 | int debugger_detach( struct process *process, struct thread *debugger ) |
| 459 | { |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 460 | struct debug_event *event, *next; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 461 | struct debug_ctx *debug_ctx; |
| 462 | |
| 463 | if (!process->debugger || process->debugger != debugger) |
| 464 | goto error; /* not currently debugged, or debugged by another debugger */ |
| 465 | if (!debugger->debug_ctx ) goto error; /* should be a debugger */ |
| 466 | /* init should be done, otherwise wouldn't be attached */ |
Alexandre Julliard | 9d80215 | 2002-05-24 21:20:27 +0000 | [diff] [blame] | 467 | assert(is_process_init_done(process)); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 468 | |
| 469 | suspend_process( process ); |
| 470 | /* send continue indication for all events */ |
| 471 | debug_ctx = debugger->debug_ctx; |
| 472 | |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 473 | /* free all events from this process */ |
| 474 | LIST_FOR_EACH_ENTRY_SAFE( event, next, &debug_ctx->event_queue, struct debug_event, entry ) |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 475 | { |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 476 | if (event->sender->process != process) continue; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 477 | |
Alexandre Julliard | 9c18d92 | 2007-08-30 19:47:43 +0200 | [diff] [blame] | 478 | assert( event->state != EVENT_CONTINUED ); |
| 479 | event->status = DBG_CONTINUE; |
| 480 | event->state = EVENT_CONTINUED; |
| 481 | wake_up( &event->obj, 0 ); |
| 482 | unlink_event( debug_ctx, event ); |
| 483 | /* from queued debug event */ |
| 484 | resume_process( process ); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 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 */ |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 490 | |
| 491 | /* from this function */ |
| 492 | resume_process( process ); |
| 493 | return 0; |
| 494 | |
| 495 | error: |
| 496 | set_error( STATUS_ACCESS_DENIED ); |
| 497 | return 0; |
| 498 | } |
| 499 | |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 500 | /* generate all startup events of a given process */ |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 501 | void generate_startup_debug_events( struct process *process, client_ptr_t entry ) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 502 | { |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 503 | struct list *ptr; |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 504 | struct thread *thread, *first_thread = get_process_first_thread( process ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 505 | |
| 506 | /* generate creation events */ |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 507 | LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) |
| 508 | { |
| 509 | if (thread == first_thread) |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 510 | generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT, &entry ); |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 511 | else |
| 512 | generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT, NULL ); |
| 513 | } |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 514 | |
| 515 | /* generate dll events (in loading order, i.e. reverse list order) */ |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 516 | ptr = list_tail( &process->dlls ); |
| 517 | while (ptr) |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 518 | { |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 519 | struct process_dll *dll = LIST_ENTRY( ptr, struct process_dll, entry ); |
Alexandre Julliard | 0502638 | 2005-03-01 10:56:18 +0000 | [diff] [blame] | 520 | generate_debug_event( first_thread, LOAD_DLL_DEBUG_EVENT, dll ); |
Alexandre Julliard | a9e0fb1 | 2005-03-02 10:20:09 +0000 | [diff] [blame] | 521 | ptr = list_prev( &process->dlls, ptr ); |
Alexandre Julliard | 05f0b71 | 2000-03-09 18:18:41 +0000 | [diff] [blame] | 522 | } |
| 523 | } |
| 524 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 525 | /* set the debugger of a given process */ |
| 526 | int set_process_debugger( struct process *process, struct thread *debugger ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 527 | { |
| 528 | struct debug_ctx *debug_ctx; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 529 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 530 | assert( !process->debugger ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 531 | |
| 532 | if (!debugger->debug_ctx) /* need to allocate a context */ |
| 533 | { |
Alexandre Julliard | e66207e | 2003-02-19 00:33:32 +0000 | [diff] [blame] | 534 | if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0; |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 535 | debug_ctx->kill_on_exit = 1; |
Alexandre Julliard | efdb496 | 2005-02-26 17:45:29 +0000 | [diff] [blame] | 536 | list_init( &debug_ctx->event_queue ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 537 | debugger->debug_ctx = debug_ctx; |
| 538 | } |
Alexandre Julliard | 17cf810 | 1999-11-24 01:22:14 +0000 | [diff] [blame] | 539 | process->debugger = debugger; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 540 | return 1; |
| 541 | } |
| 542 | |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 543 | /* a thread is exiting */ |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 544 | void debug_exit_thread( struct thread *thread ) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 545 | { |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 546 | if (thread->debug_ctx) /* this thread is a debugger */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 547 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 548 | if (thread->debug_ctx->kill_on_exit) |
| 549 | { |
| 550 | /* kill all debugged processes */ |
Francois Gouget | b6aa247 | 2007-08-31 02:35:54 +0200 | [diff] [blame] | 551 | kill_debugged_processes( thread, STATUS_DEBUGGER_INACTIVE ); |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 552 | } |
| 553 | else |
| 554 | { |
| 555 | detach_debugged_processes( thread ); |
| 556 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 557 | release_object( thread->debug_ctx ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 558 | thread->debug_ctx = NULL; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 559 | } |
| 560 | } |
| 561 | |
| 562 | /* Wait for a debug event */ |
| 563 | DECL_HANDLER(wait_debug_event) |
| 564 | { |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 565 | struct debug_ctx *debug_ctx = current->debug_ctx; |
| 566 | struct debug_event *event; |
| 567 | |
| 568 | if (!debug_ctx) /* current thread is not a debugger */ |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 569 | { |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 570 | set_error( STATUS_INVALID_HANDLE ); |
| 571 | return; |
| 572 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 573 | reply->wait = 0; |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 574 | if ((event = find_event_to_send( debug_ctx ))) |
| 575 | { |
Alexandre Julliard | 0f273c1 | 2006-07-26 10:43:25 +0200 | [diff] [blame] | 576 | data_size_t size = get_reply_max_size(); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 577 | event->state = EVENT_SENT; |
| 578 | event->sender->debug_event = event; |
Alexandre Julliard | 54f2287 | 2002-10-03 19:54:57 +0000 | [diff] [blame] | 579 | reply->pid = get_process_id( event->sender->process ); |
| 580 | reply->tid = get_thread_id( event->sender ); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 581 | if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 582 | set_reply_data( &event->data, size ); |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 583 | } |
| 584 | else /* no event ready */ |
| 585 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 586 | reply->pid = 0; |
| 587 | reply->tid = 0; |
Alexandre Julliard | e9936d9 | 2001-01-26 00:22:26 +0000 | [diff] [blame] | 588 | if (req->get_handle) |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 589 | reply->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, 0 ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 590 | } |
| 591 | } |
| 592 | |
| 593 | /* Continue a debug event */ |
| 594 | DECL_HANDLER(continue_debug_event) |
| 595 | { |
| 596 | struct process *process = get_process_from_id( req->pid ); |
| 597 | if (process) |
| 598 | { |
| 599 | struct thread *thread = get_thread_from_id( req->tid ); |
| 600 | if (thread) |
| 601 | { |
| 602 | continue_debug_event( process, thread, req->status ); |
| 603 | release_object( thread ); |
| 604 | } |
| 605 | release_object( process ); |
| 606 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 607 | } |
| 608 | |
| 609 | /* Start debugging an existing process */ |
| 610 | DECL_HANDLER(debug_process) |
| 611 | { |
| 612 | struct process *process = get_process_from_id( req->pid ); |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 613 | if (!process) return; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 614 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 615 | if (!req->attach) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 616 | { |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 617 | debugger_detach( process, current ); |
| 618 | } |
| 619 | else if (debugger_attach( process, current )) |
| 620 | { |
Alexandre Julliard | c6c335d | 2008-12-30 22:56:15 +0100 | [diff] [blame] | 621 | generate_startup_debug_events( process, 0 ); |
Alexandre Julliard | 17de829 | 2006-04-19 19:45:39 +0200 | [diff] [blame] | 622 | break_process( process ); |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 623 | resume_process( process ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 624 | } |
Alexandre Julliard | ff81d78 | 2000-03-08 12:01:30 +0000 | [diff] [blame] | 625 | release_object( process ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 626 | } |
| 627 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 628 | /* queue an exception event */ |
| 629 | DECL_HANDLER(queue_exception_event) |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 630 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 631 | reply->handle = 0; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 632 | if (current->process->debugger) |
| 633 | { |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 634 | debug_event_t data; |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 635 | struct debug_event *event; |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 636 | |
Alexandre Julliard | 9f365e7 | 2009-01-02 20:12:46 +0100 | [diff] [blame] | 637 | if ((req->len % sizeof(client_ptr_t)) != 0 || |
| 638 | req->len > get_req_data_size() || |
| 639 | req->len > EXCEPTION_MAXIMUM_PARAMETERS * sizeof(client_ptr_t)) |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 640 | { |
| 641 | set_error( STATUS_INVALID_PARAMETER ); |
| 642 | return; |
| 643 | } |
Alexandre Julliard | 9f365e7 | 2009-01-02 20:12:46 +0100 | [diff] [blame] | 644 | memset( &data, 0, sizeof(data) ); |
| 645 | data.exception.first = req->first; |
| 646 | data.exception.exc_code = req->code; |
| 647 | data.exception.flags = req->flags; |
| 648 | data.exception.record = req->record; |
| 649 | data.exception.address = req->address; |
| 650 | data.exception.nb_params = req->len / sizeof(client_ptr_t); |
| 651 | memcpy( data.exception.params, get_req_data(), req->len ); |
| 652 | |
| 653 | if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data ))) |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 654 | { |
Alexandre Julliard | 9f365e7 | 2009-01-02 20:12:46 +0100 | [diff] [blame] | 655 | const CONTEXT *context = (const CONTEXT *)((char *)get_req_data() + req->len); |
| 656 | data_size_t size = get_req_data_size() - req->len; |
| 657 | |
| 658 | memset( &event->context, 0, sizeof(event->context) ); |
| 659 | memcpy( &event->context, context, size ); |
| 660 | current->context = &event->context; |
| 661 | |
Alexandre Julliard | 24560e7 | 2005-12-09 13:58:25 +0100 | [diff] [blame] | 662 | if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, 0 ))) |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 663 | { |
| 664 | link_event( event ); |
| 665 | suspend_process( current->process ); |
| 666 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 667 | release_object( event ); |
| 668 | } |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 669 | } |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 670 | } |
| 671 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 672 | /* retrieve the status of an exception event */ |
| 673 | DECL_HANDLER(get_exception_status) |
| 674 | { |
| 675 | struct debug_event *event; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 676 | |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 677 | if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle, |
| 678 | 0, &debug_event_ops ))) |
| 679 | { |
Alexandre Julliard | 8700c43 | 2006-11-02 20:52:05 +0100 | [diff] [blame] | 680 | close_handle( current->process, req->handle ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 681 | if (event->state == EVENT_CONTINUED) |
| 682 | { |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 683 | if (current->context == &event->context) |
| 684 | { |
Alexandre Julliard | 0f273c1 | 2006-07-26 10:43:25 +0200 | [diff] [blame] | 685 | data_size_t size = min( sizeof(CONTEXT), get_reply_max_size() ); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 686 | set_reply_data( &event->context, size ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 687 | current->context = NULL; |
| 688 | } |
Alexandre Julliard | ff7795e | 2005-11-01 21:47:07 +0000 | [diff] [blame] | 689 | set_error( event->status ); |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 690 | } |
| 691 | else set_error( STATUS_PENDING ); |
| 692 | release_object( event ); |
| 693 | } |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 694 | } |
| 695 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 696 | /* send an output string to the debugger */ |
| 697 | DECL_HANDLER(output_debug_string) |
| 698 | { |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 699 | debug_event_t data; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 700 | |
Alexandre Julliard | bc03f0e | 2009-01-02 20:09:25 +0100 | [diff] [blame] | 701 | data.output_string.string = req->string; |
| 702 | data.output_string.unicode = req->unicode; |
| 703 | data.output_string.length = req->length; |
Alexandre Julliard | e939eae | 2001-01-26 20:45:41 +0000 | [diff] [blame] | 704 | generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data ); |
Alexandre Julliard | e712e07 | 1999-05-23 19:53:30 +0000 | [diff] [blame] | 705 | } |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 706 | |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 707 | /* simulate a breakpoint in a process */ |
| 708 | DECL_HANDLER(debug_break) |
| 709 | { |
| 710 | struct process *process; |
| 711 | |
| 712 | reply->self = 0; |
Alexandre Julliard | 17de829 | 2006-04-19 19:45:39 +0200 | [diff] [blame] | 713 | if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION /*FIXME*/ ))) |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 714 | { |
Alexandre Julliard | 17de829 | 2006-04-19 19:45:39 +0200 | [diff] [blame] | 715 | if (process != current->process) break_process( process ); |
| 716 | else reply->self = 1; |
| 717 | release_object( process ); |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 718 | } |
Alexandre Julliard | 3c4538c | 2002-02-27 01:55:02 +0000 | [diff] [blame] | 719 | } |
| 720 | |
Eric Pouech | fbccb38 | 2002-02-27 01:28:30 +0000 | [diff] [blame] | 721 | /* set debugger kill on exit flag */ |
| 722 | DECL_HANDLER(set_debugger_kill_on_exit) |
| 723 | { |
| 724 | if (!current->debug_ctx) |
| 725 | { |
| 726 | set_error( STATUS_ACCESS_DENIED ); |
| 727 | return; |
| 728 | } |
| 729 | current->debug_ctx->kill_on_exit = req->kill_on_exit; |
| 730 | } |