server: Store a debug object instead of a debugger thread in the process.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-01-28 11:06:09 +01:00
parent aec961e529
commit faa9f5be59
3 changed files with 44 additions and 70 deletions

View File

@ -347,6 +347,8 @@ static void debug_obj_destroy( struct object *obj )
struct debug_obj *debug_obj = (struct debug_obj *)obj;
assert( obj->ops == &debug_obj_ops );
detach_debugged_processes( debug_obj, debug_obj->kill_on_exit ? STATUS_DEBUGGER_INACTIVE : 0 );
/* free all pending events */
while ((ptr = list_head( &debug_obj->event_queue )))
unlink_event( debug_obj, LIST_ENTRY( ptr, struct debug_event, entry ));
@ -373,7 +375,7 @@ static int continue_debug_event( struct process *process, struct thread *thread,
{
struct debug_obj *debug_obj = current->debug_obj;
if (debug_obj && process->debugger == current && thread->process == process)
if (debug_obj && process->debug_obj == debug_obj && thread->process == process)
{
struct debug_event *event;
@ -424,12 +426,9 @@ static int continue_debug_event( struct process *process, struct thread *thread,
/* alloc a debug event for a debugger */
static struct debug_event *alloc_debug_event( struct thread *thread, int code, const void *arg )
{
struct thread *debugger = thread->process->debugger;
struct debug_event *event;
assert( code > 0 && code <= NB_DEBUG_EVENTS );
/* cannot queue a debug event for myself */
assert( debugger->process != thread->process );
/* build the event */
if (!(event = alloc_object( &debug_event_ops ))) return NULL;
@ -446,9 +445,10 @@ static struct debug_event *alloc_debug_event( struct thread *thread, int code, c
/* generate a debug event from inside the server and queue it */
void generate_debug_event( struct thread *thread, int code, const void *arg )
{
if (thread->process->debugger)
struct debug_obj *debug_obj = thread->process->debug_obj;
if (debug_obj)
{
struct debug_obj *debug_obj = thread->process->debugger->debug_obj;
struct debug_event *event = alloc_debug_event( thread, code, arg );
if (event)
{
@ -462,17 +462,16 @@ void generate_debug_event( struct thread *thread, int code, const void *arg )
void resume_delayed_debug_events( struct thread *thread )
{
struct thread *debugger = thread->process->debugger;
struct debug_obj *debug_obj = thread->process->debug_obj;
struct debug_event *event;
if (debugger)
if (debug_obj)
{
assert( debugger->debug_obj );
LIST_FOR_EACH_ENTRY( event, &debugger->debug_obj->event_queue, struct debug_event, entry )
LIST_FOR_EACH_ENTRY( event, &debug_obj->event_queue, struct debug_event, entry )
{
if (event->sender != thread) continue;
if (event->state != EVENT_DELAYED) continue;
resume_event( debugger->debug_obj, event );
resume_event( debug_obj, event );
suspend_process( thread->process );
}
}
@ -481,7 +480,7 @@ void resume_delayed_debug_events( struct thread *thread )
/* attach a process to a debugger thread and suspend it */
static int debugger_attach( struct process *process, struct thread *debugger )
{
if (process->debugger) goto error; /* already being debugged */
if (process->debug_obj) goto error; /* already being debugged */
if (debugger->process == process) goto error;
if (!is_process_init_done( process )) goto error; /* still starting up */
if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */
@ -502,7 +501,7 @@ static int debugger_attach( struct process *process, struct thread *debugger )
}
if (!set_process_debug_flag( process, 1 ))
{
process->debugger = NULL;
process->debug_obj = NULL;
resume_process( process );
return 0;
}
@ -515,23 +514,17 @@ static int debugger_attach( struct process *process, struct thread *debugger )
}
/* detach a process from a debugger thread (and resume it ?) */
int debugger_detach( struct process *process, struct thread *debugger )
/* detach a process from a debugger thread (and resume it) */
void debugger_detach( struct process *process, struct debug_obj *debug_obj )
{
struct debug_event *event, *next;
struct debug_obj *debug_obj;
if (!process->debugger || process->debugger != debugger)
goto error; /* not currently debugged, or debugged by another debugger */
if (!debugger->debug_obj ) goto error; /* should be a debugger */
/* init should be done, otherwise wouldn't be attached */
assert(is_process_init_done(process));
suspend_process( process );
/* send continue indication for all events */
debug_obj = debugger->debug_obj;
/* free all events from this process */
/* send continue indication for all events */
LIST_FOR_EACH_ENTRY_SAFE( event, next, &debug_obj->event_queue, struct debug_event, entry )
{
if (event->sender->process != process) continue;
@ -546,16 +539,11 @@ int debugger_detach( struct process *process, struct thread *debugger )
}
/* remove relationships between process and its debugger */
process->debugger = NULL;
process->debug_obj = NULL;
if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */
/* from this function */
resume_process( process );
return 0;
error:
set_error( STATUS_ACCESS_DENIED );
return 0;
}
/* generate all startup events of a given process */
@ -594,7 +582,7 @@ int set_process_debugger( struct process *process, struct thread *debugger )
{
struct debug_obj *debug_obj;
assert( !process->debugger );
assert( !process->debug_obj );
if (!debugger->debug_obj) /* need to allocate a context */
{
@ -603,24 +591,18 @@ int set_process_debugger( struct process *process, struct thread *debugger )
list_init( &debug_obj->event_queue );
debugger->debug_obj = debug_obj;
}
process->debugger = debugger;
process->debug_obj = debugger->debug_obj;
return 1;
}
/* a thread is exiting */
void debug_exit_thread( struct thread *thread )
{
if (thread->debug_obj) /* this thread is a debugger */
struct debug_obj *debug_obj = thread->debug_obj;
if (debug_obj) /* this thread is a debugger */
{
if (thread->debug_obj->kill_on_exit)
{
/* kill all debugged processes */
kill_debugged_processes( thread, STATUS_DEBUGGER_INACTIVE );
}
else
{
detach_debugged_processes( thread );
}
detach_debugged_processes( debug_obj, debug_obj->kill_on_exit ? STATUS_DEBUGGER_INACTIVE : 0 );
release_object( thread->debug_obj );
thread->debug_obj = NULL;
}
@ -712,7 +694,10 @@ DECL_HANDLER(debug_process)
if (!req->attach)
{
debugger_detach( process, current );
if (current->debug_obj && process->debug_obj == current->debug_obj)
debugger_detach( process, current->debug_obj );
else
set_error( STATUS_ACCESS_DENIED );
}
else if (debugger_attach( process, current ))
{
@ -725,11 +710,12 @@ DECL_HANDLER(debug_process)
/* queue an exception event */
DECL_HANDLER(queue_exception_event)
{
struct debug_obj *debug_obj = current->process->debug_obj;
reply->handle = 0;
if (current->process->debugger)
if (debug_obj)
{
debug_event_t data;
struct debug_obj *debug_obj = current->process->debugger->debug_obj;
struct debug_event *event;
struct thread *thread = current;

View File

@ -514,7 +514,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
goto error;
}
process->parent_id = 0;
process->debugger = NULL;
process->debug_obj = NULL;
process->debug_event = NULL;
process->handles = NULL;
process->msg_fd = NULL;
@ -1038,8 +1038,8 @@ void kill_process( struct process *process, int violent_death )
}
}
/* kill all processes being debugged by a given thread */
void kill_debugged_processes( struct thread *debugger, int exit_code )
/* detach all processes being debugged by a given thread */
void detach_debugged_processes( struct debug_obj *debug_obj, int exit_code )
{
for (;;) /* restart from the beginning of the list every time */
{
@ -1049,26 +1049,15 @@ void kill_debugged_processes( struct thread *debugger, int exit_code )
LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry )
{
if (!process->running_threads) continue;
if (process->debugger == debugger) break;
if (process->debug_obj == debug_obj) break;
}
if (&process->entry == &process_list) break; /* no process found */
process->debugger = NULL;
terminate_process( process, NULL, exit_code );
}
}
/* detach a debugger from all its debuggees */
void detach_debugged_processes( struct thread *debugger )
{
struct process *process;
LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry )
{
if (process->debugger == debugger && process->running_threads)
if (exit_code)
{
debugger_detach( process, debugger );
process->debug_obj = NULL;
terminate_process( process, NULL, exit_code );
}
else debugger_detach( process, debug_obj );
}
}
@ -1266,9 +1255,9 @@ DECL_HANDLER(new_process)
set_process_debugger( process, current );
process->debug_children = !(req->create_flags & DEBUG_ONLY_THIS_PROCESS);
}
else if (current->process->debugger && current->process->debug_children)
else if (current->process->debug_children)
{
set_process_debugger( process, current->process->debugger );
process->debug_obj = current->process->debug_obj;
/* debug_children is set to 1 by default */
}
@ -1382,7 +1371,7 @@ DECL_HANDLER(init_process_done)
set_process_startup_state( process, STARTUP_DONE );
if (req->gui) process->idle_event = create_event( NULL, NULL, 0, 1, 0, NULL );
if (process->debugger) set_process_debug_flag( process, 1 );
if (process->debug_obj) set_process_debug_flag( process, 1 );
reply->suspend = (current->suspend || process->suspend);
}
@ -1431,7 +1420,7 @@ DECL_HANDLER(get_process_info)
reply->start_time = process->start_time;
reply->end_time = process->end_time;
reply->cpu = process->cpu;
reply->debugger_present = !!process->debugger;
reply->debugger_present = !!process->debug_obj;
reply->debug_children = process->debug_children;
if (get_reply_max_size())
{

View File

@ -56,7 +56,7 @@ struct process
struct list entry; /* entry in system-wide process list */
process_id_t parent_id; /* parent process id (at the time of creation) */
struct list thread_list; /* thread list */
struct thread *debugger; /* thread debugging this process */
struct debug_obj *debug_obj; /* debug object debugging this process */
struct debug_event *debug_event; /* debug event being sent to debugger */
struct handle_table *handles; /* handle entries */
struct fd *msg_fd; /* fd for sendmsg/recvmsg */
@ -115,7 +115,7 @@ extern struct thread *get_process_first_thread( struct process *process );
extern struct process *get_process_from_id( process_id_t id );
extern struct process *get_process_from_handle( obj_handle_t handle, unsigned int access );
extern int process_set_debugger( struct process *process, struct thread *thread );
extern int debugger_detach( struct process* process, struct thread* debugger );
extern void debugger_detach( struct process *process, struct debug_obj *debug_obj );
extern int set_process_debug_flag( struct process *process, int flag );
extern void add_process_thread( struct process *process,
@ -126,8 +126,7 @@ extern void suspend_process( struct process *process );
extern void resume_process( struct process *process );
extern void kill_process( struct process *process, int violent_death );
extern void kill_console_processes( struct thread *renderer, int exit_code );
extern void kill_debugged_processes( struct thread *debugger, int exit_code );
extern void detach_debugged_processes( struct thread *debugger );
extern void detach_debugged_processes( struct debug_obj *debug_obj, int exit_code );
extern void enum_processes( int (*cb)(struct process*, void*), void *user);
/* console functions */