Generate CREATE_PROCESS/THREAD debug events internally in the server.
diff --git a/server/debugger.c b/server/debugger.c
index 01ce211..b62d0d3 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -97,30 +97,43 @@
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
THREAD_ALL_ACCESS, FALSE )) == -1)
return 0;
+ event->data.info.create_thread.teb = thread->teb;
+ event->data.info.create_thread.start = thread->entry;
break;
case CREATE_PROCESS_DEBUG_EVENT:
- if ((handle = event->data.info.create_process.file) != -1)
- {
- if ((handle = duplicate_handle( thread->process, handle, debugger->process,
- GENERIC_READ, FALSE, 0 )) == -1)
- return 0;
- event->data.info.create_process.file = handle;
- }
- if ((event->data.info.create_process.process = alloc_handle( debugger->process, thread->process,
- /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
- PROCESS_ALL_ACCESS, FALSE )) == -1)
- {
- if (handle != -1) close_handle( debugger->process, handle );
+ if ((handle = alloc_handle( debugger->process, thread->process,
+ /* documented: PROCESS_VM_READ | PROCESS_VM_WRITE */
+ PROCESS_ALL_ACCESS, FALSE )) == -1)
return 0;
- }
- if ((event->data.info.create_process.thread = alloc_handle( debugger->process, thread,
+ event->data.info.create_process.process = handle;
+
+ if ((handle = alloc_handle( debugger->process, thread,
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
- THREAD_ALL_ACCESS, FALSE )) == -1)
+ THREAD_ALL_ACCESS, FALSE )) == -1)
{
- if (handle != -1) close_handle( debugger->process, handle );
close_handle( debugger->process, event->data.info.create_process.process );
return 0;
}
+ event->data.info.create_process.thread = handle;
+
+ handle = -1;
+ if (thread->process->exe_file &&
+ ((handle = alloc_handle( debugger->process, thread->process->exe_file,
+ /* the doc says write access too, but this doesn't seem a good idea */
+ GENERIC_READ, FALSE )) == -1))
+ {
+ close_handle( debugger->process, event->data.info.create_process.process );
+ close_handle( debugger->process, event->data.info.create_process.thread );
+ return 0;
+ }
+ event->data.info.create_process.file = handle;
+ event->data.info.create_process.teb = thread->teb;
+ event->data.info.create_process.base = thread->process->module;
+ event->data.info.create_process.start = thread->entry;
+ event->data.info.create_process.dbg_offset = 0;
+ event->data.info.create_process.dbg_size = 0;
+ event->data.info.create_process.name = 0;
+ event->data.info.create_process.unicode = 0;
break;
case LOAD_DLL_DEBUG_EVENT:
if ((handle = event->data.info.load_dll.handle) != -1)
@@ -131,6 +144,15 @@
event->data.info.load_dll.handle = handle;
}
break;
+ case EXIT_PROCESS_DEBUG_EVENT:
+ case EXIT_THREAD_DEBUG_EVENT:
+ event->data.info.exit.exit_code = thread->exit_code;
+ break;
+ case EXCEPTION_DEBUG_EVENT:
+ case UNLOAD_DLL_DEBUG_EVENT:
+ case OUTPUT_DEBUG_STRING_EVENT:
+ case RIP_EVENT:
+ break;
}
return 1;
}
@@ -189,7 +211,6 @@
req->event.code = 0;
req->pid = 0;
req->tid = 0;
- thread->error = signaled;
}
}
@@ -330,9 +351,10 @@
}
/* queue a debug event for a debugger */
-static struct debug_event *queue_debug_event( struct thread *debugger, struct thread *thread,
+static struct debug_event *queue_debug_event( struct thread *thread, int code,
debug_event_t *data )
{
+ struct thread *debugger = thread->process->debugger;
struct debug_ctx *debug_ctx = debugger->debug_ctx;
struct debug_event *event;
@@ -347,7 +369,8 @@
event->state = EVENT_QUEUED;
event->sender = (struct thread *)grab_object( thread );
event->debugger = (struct thread *)grab_object( debugger );
- memcpy( &event->data, data, sizeof(event->data) );
+ if (data) memcpy( &event->data, data, sizeof(event->data) );
+ event->data.code = code;
if (!fill_debug_event( debugger, thread, event ))
{
@@ -361,6 +384,16 @@
return event;
}
+/* generate a debug event from inside the server and queue it */
+void generate_debug_event( struct thread *thread, int code )
+{
+ if (thread->process->debugger)
+ {
+ struct debug_event *event = queue_debug_event( thread, code, NULL );
+ if (event) release_object( event );
+ }
+}
+
/* return a pointer to the context in case the thread is inside an exception event */
CONTEXT *get_debug_context( struct thread *thread )
{
@@ -409,29 +442,14 @@
}
/* a thread is exiting */
-void debug_exit_thread( struct thread *thread, int exit_code )
+void debug_exit_thread( struct thread *thread )
{
- struct thread *debugger = thread->process->debugger;
- struct debug_ctx *debug_ctx = thread->debug_ctx;
-
- if (debugger) /* being debugged -> send an event to the debugger */
- {
- struct debug_event *event;
- debug_event_t exit;
- exit.info.exit.exit_code = exit_code;
- /* if this is the last thread, send an exit process event */
- exit.code = ((thread->process->running_threads == 1) ?
- EXIT_PROCESS_DEBUG_EVENT : EXIT_THREAD_DEBUG_EVENT);
- event = queue_debug_event( debugger, thread, &exit );
- if (event) release_object( event );
- }
-
- if (debug_ctx) /* this thread is a debugger */
+ if (thread->debug_ctx) /* this thread is a debugger */
{
/* kill all debugged processes */
- kill_debugged_processes( thread, exit_code );
+ kill_debugged_processes( thread, thread->exit_code );
+ release_object( thread->debug_ctx );
thread->debug_ctx = NULL;
- release_object( debug_ctx );
}
}
@@ -466,27 +484,30 @@
DECL_HANDLER(debug_process)
{
struct process *process = get_process_from_id( req->pid );
- if (process)
+ if (!process) return;
+ if (debugger_attach( process, current ))
{
- debugger_attach( process, current );
- /* FIXME: should notify the debugged process somehow */
- release_object( process );
+ struct thread *thread = process->thread_list;
+ generate_debug_event( thread, CREATE_PROCESS_DEBUG_EVENT );
+ while ((thread = thread->next)) generate_debug_event( thread, CREATE_THREAD_DEBUG_EVENT );
+ /* FIXME: load dll + breakpoint exception events */
}
+ release_object( process );
}
/* Send a debug event */
DECL_HANDLER(send_debug_event)
{
- struct thread *debugger = current->process->debugger;
struct debug_event *event;
+ int code = req->event.code;
- if ((req->event.code <= 0) || (req->event.code > RIP_EVENT))
+ if ((code <= 0) || (code > RIP_EVENT))
{
- fatal_protocol_error( current, "send_debug_event: bad code %d\n", req->event.code );
+ fatal_protocol_error( current, "send_debug_event: bad code %d\n", code );
return;
}
req->status = 0;
- if (debugger && ((event = queue_debug_event( debugger, current, &req->event ))))
+ if (current->process->debugger && ((event = queue_debug_event( current, code, &req->event ))))
{
/* wait for continue_debug_event */
struct object *obj = &event->obj;
diff --git a/server/object.h b/server/object.h
index 0a7ad5d..3f87b85 100644
--- a/server/object.h
+++ b/server/object.h
@@ -154,7 +154,8 @@
/* debugger functions */
extern int debugger_attach( struct process *process, struct thread *debugger );
-extern void debug_exit_thread( struct thread *thread, int exit_code );
+extern void generate_debug_event( struct thread *thread, int code );
+extern void debug_exit_thread( struct thread *thread );
extern CONTEXT *get_debug_context( struct thread *thread );
/* mapping functions */
diff --git a/server/process.c b/server/process.c
index 0dd779d..9d01b5f 100644
--- a/server/process.c
+++ b/server/process.c
@@ -584,6 +584,9 @@
fatal_protocol_error( current, "init_process_done: no event\n" );
return;
}
+ current->entry = req->entry;
+ process->module = req->module;
+ generate_debug_event( current, CREATE_PROCESS_DEBUG_EVENT );
set_event( process->init_event );
release_object( process->init_event );
process->init_event = NULL;
diff --git a/server/process.h b/server/process.h
index 873aad7..e8e7cc6 100644
--- a/server/process.h
+++ b/server/process.h
@@ -37,6 +37,7 @@
struct event *init_event; /* event for init done */
void *ldt_copy; /* pointer to LDT copy in client addr space */
void *ldt_flags; /* pointer to LDT flags in client addr space */
+ void *module; /* main module base address */
struct new_process_request *info; /* startup info (freed after startup) */
};
@@ -66,4 +67,6 @@
extern void kill_debugged_processes( struct thread *debugger, int exit_code );
extern struct process_snapshot *process_snap( int *count );
+static inline void *get_process_id( struct process *process ) { return process; }
+
#endif /* __WINE_SERVER_PROCESS_H */
diff --git a/server/thread.c b/server/thread.c
index b042158..14d7ea6 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -92,25 +92,32 @@
/* allocate the buffer for the communication with the client */
static int alloc_client_buffer( struct thread *thread )
{
+ struct get_thread_buffer_request *req;
int fd;
if ((fd = create_anonymous_file()) == -1) return -1;
if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error;
if ((thread->buffer = mmap( 0, MAX_REQUEST_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0 )) == (void*)-1) goto error;
- return fd;
+ /* build the first request into the buffer and send it */
+ req = thread->buffer;
+ req->pid = get_process_id( thread->process );
+ req->tid = get_thread_id( thread );
+ req->boot = (thread == booting_thread);
+ set_reply_fd( thread, fd );
+ send_reply( thread );
+ return 1;
error:
file_set_error();
if (fd != -1) close( fd );
- return -1;
+ return 0;
}
/* create a new thread */
struct thread *create_thread( int fd, struct process *process, int suspend )
{
struct thread *thread;
- int buf_fd;
int flags = fcntl( fd, F_GETFL, 0 );
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
@@ -150,11 +157,8 @@
first_thread = thread;
add_process_thread( process, thread );
- if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
-
set_select_events( &thread->obj, POLLIN ); /* start listening to events */
- set_reply_fd( thread, buf_fd ); /* send the fd to the client */
- send_reply( thread );
+ if (!alloc_client_buffer( thread )) goto error;
return thread;
error:
@@ -560,7 +564,9 @@
if (current == thread) current = NULL;
if (debug_level) trace_kill( thread );
if (thread->wait) end_wait( thread );
- debug_exit_thread( thread, exit_code );
+ generate_debug_event( thread, (thread->process->running_threads == 1) ?
+ EXIT_PROCESS_DEBUG_EVENT : EXIT_THREAD_DEBUG_EVENT );
+ debug_exit_thread( thread );
abandon_mutexes( thread );
remove_process_thread( thread->process, thread );
wake_up( &thread->obj, 0 );
@@ -623,10 +629,10 @@
}
current->unix_pid = req->unix_pid;
current->teb = req->teb;
+ current->entry = req->entry;
if (current->suspend + current->process->suspend > 0) stop_thread( current );
- req->pid = current->process;
- req->tid = current;
- req->boot = (current == booting_thread);
+ if (current->process->running_threads > 1)
+ generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT );
}
/* terminate a thread */
diff --git a/server/thread.h b/server/thread.h
index 5e46493..9cc088d 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -48,6 +48,7 @@
int exit_code; /* thread exit code */
int unix_pid; /* Unix pid of client */
void *teb; /* TEB address (in client address space) */
+ void *entry; /* thread entry point (in client address space) */
int priority; /* priority level */
int affinity; /* affinity mask */
int suspend; /* suspend count */
@@ -92,4 +93,6 @@
static inline void set_error( int err ) { current->error = err; }
static inline void clear_error(void) { set_error(0); }
+static inline void *get_thread_id( struct thread *thread ) { return thread; }
+
#endif /* __WINE_SERVER_THREAD_H */
diff --git a/server/trace.c b/server/trace.c
index c38f7db..79ffa2e 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -258,25 +258,26 @@
static void dump_init_process_done_request( const struct init_process_done_request *req )
{
- fprintf( stderr, " dummy=%d", req->dummy );
+ fprintf( stderr, " module=%p,", req->module );
+ fprintf( stderr, " entry=%p", req->entry );
}
static void dump_init_thread_request( const struct init_thread_request *req )
{
fprintf( stderr, " unix_pid=%d,", req->unix_pid );
- fprintf( stderr, " teb=%p", req->teb );
-}
-
-static void dump_init_thread_reply( const struct init_thread_request *req )
-{
- fprintf( stderr, " pid=%p,", req->pid );
- fprintf( stderr, " tid=%p,", req->tid );
- fprintf( stderr, " boot=%d", req->boot );
+ fprintf( stderr, " teb=%p,", req->teb );
+ fprintf( stderr, " entry=%p", req->entry );
}
static void dump_get_thread_buffer_request( const struct get_thread_buffer_request *req )
{
- fprintf( stderr, " dummy=%d", req->dummy );
+}
+
+static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request *req )
+{
+ fprintf( stderr, " pid=%p,", req->pid );
+ fprintf( stderr, " tid=%p,", req->tid );
+ fprintf( stderr, " boot=%d", req->boot );
}
static void dump_terminate_process_request( const struct terminate_process_request *req )
@@ -1329,8 +1330,8 @@
(dump_func)0,
(dump_func)dump_init_process_reply,
(dump_func)0,
- (dump_func)dump_init_thread_reply,
(dump_func)0,
+ (dump_func)dump_get_thread_buffer_reply,
(dump_func)0,
(dump_func)0,
(dump_func)dump_get_process_info_reply,