Generate CREATE_PROCESS/THREAD debug events internally in the server.

oldstable
Alexandre Julliard 2000-03-08 12:01:30 +00:00
parent ca3c9ba4ec
commit ff81d78708
13 changed files with 135 additions and 153 deletions

View File

@ -170,8 +170,6 @@ extern void PROCESS_WalkProcess( void );
/* scheduler/debugger.c */
extern DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEXT *ctx );
extern DWORD DEBUG_SendCreateProcessEvent( HFILE file, HMODULE module, void *entry );
extern DWORD DEBUG_SendCreateThreadEvent( void *entry );
extern DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name );
extern DWORD DEBUG_SendUnloadDLLEvent( HMODULE module );

View File

@ -165,7 +165,8 @@ struct init_process_request
/* Signal the end of the process initialization */
struct init_process_done_request
{
IN int dummy;
IN void* module; /* main module base address */
IN void* entry; /* process entry point */
};
@ -174,9 +175,7 @@ struct init_thread_request
{
IN int unix_pid; /* Unix pid of new thread */
IN void* teb; /* TEB of new thread (in thread address space) */
OUT void* pid; /* process id of the new thread's process */
OUT void* tid; /* thread id of the new thread */
OUT int boot; /* is this the boot thread? */
IN void* entry; /* thread entry point (in thread address space) */
};
@ -185,7 +184,9 @@ struct init_thread_request
/* created thread gets (without having to request it) */
struct get_thread_buffer_request
{
IN int dummy;
OUT void* pid; /* process id of the new thread's process */
OUT void* tid; /* thread id of the new thread */
OUT int boot; /* is this the boot thread? */
};

View File

@ -453,6 +453,7 @@ int CLIENT_InitServer(void)
*/
int CLIENT_InitThread(void)
{
struct get_thread_buffer_request *first_req;
struct init_thread_request *req;
TEB *teb = NtCurrentTeb();
int fd;
@ -463,16 +464,17 @@ int CLIENT_InitThread(void)
teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
close( fd );
if (teb->buffer == (void*)-1) server_perror( "mmap" );
first_req = teb->buffer;
teb->process->server_pid = first_req->pid;
teb->tid = first_req->tid;
if (first_req->boot) boot_thread_id = teb->tid;
else if (boot_thread_id == teb->tid) boot_thread_id = 0;
req = get_req_buffer();
req = teb->buffer;
req->unix_pid = getpid();
req->teb = teb;
if (server_call( REQ_INIT_THREAD )) return -1;
teb->process->server_pid = req->pid;
teb->tid = req->tid;
if (req->boot) boot_thread_id = req->tid;
else if (boot_thread_id == req->tid) boot_thread_id = 0;
return 0;
req->entry = teb->entry_point;
return server_call_noerr( REQ_INIT_THREAD );
}
/***********************************************************************

View File

@ -6,8 +6,8 @@
#include <string.h>
#include "winerror.h"
#include "process.h"
#include "thread.h"
#include "server.h"
#include "debugtools.h"
@ -22,7 +22,6 @@ DEFAULT_DEBUG_CHANNEL(debugstr);
DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEXT *context )
{
int i;
DWORD ret = 0;
struct send_debug_event_request *req = get_req_buffer();
req->event.code = EXCEPTION_DEBUG_EVENT;
@ -35,58 +34,9 @@ DWORD DEBUG_SendExceptionEvent( EXCEPTION_RECORD *rec, BOOL first_chance, CONTEX
req->event.info.exception.context = *context;
for (i = 0; i < req->event.info.exception.nb_params; i++)
req->event.info.exception.params[i] = rec->ExceptionInformation[i];
if (!server_call( REQ_SEND_DEBUG_EVENT ))
{
ret = req->status;
if (!server_call_noerr( REQ_SEND_DEBUG_EVENT ))
*context = req->event.info.exception.context;
}
return ret;
}
/**********************************************************************
* DEBUG_SendCreateProcessEvent
*
* Send an CREATE_PROCESS_DEBUG_EVENT event to the current process debugger.
* Must be called from the context of the new process.
*/
DWORD DEBUG_SendCreateProcessEvent( HFILE file, HMODULE module, void *entry )
{
DWORD ret = 0;
struct send_debug_event_request *req = get_req_buffer();
req->event.code = CREATE_PROCESS_DEBUG_EVENT;
req->event.info.create_process.file = file;
req->event.info.create_process.process = 0; /* will be filled by server */
req->event.info.create_process.thread = 0; /* will be filled by server */
req->event.info.create_process.base = (void *)module;
req->event.info.create_process.dbg_offset = 0; /* FIXME */
req->event.info.create_process.dbg_size = 0; /* FIXME */
req->event.info.create_process.teb = NtCurrentTeb();
req->event.info.create_process.start = entry;
req->event.info.create_process.name = 0; /* FIXME */
req->event.info.create_process.unicode = 0; /* FIXME */
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
return ret;
}
/**********************************************************************
* DEBUG_SendCreateThreadEvent
*
* Send an CREATE_THREAD_DEBUG_EVENT event to the current process debugger.
* Must be called from the context of the new thread.
*/
DWORD DEBUG_SendCreateThreadEvent( void *entry )
{
DWORD ret = 0;
struct send_debug_event_request *req = get_req_buffer();
req->event.code = CREATE_THREAD_DEBUG_EVENT;
req->event.info.create_thread.handle = 0; /* will be filled by server */
req->event.info.create_thread.teb = NtCurrentTeb();
req->event.info.create_thread.start = entry;
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
return ret;
return req->status;
}
@ -97,7 +47,6 @@ DWORD DEBUG_SendCreateThreadEvent( void *entry )
*/
DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name )
{
DWORD ret = 0;
struct send_debug_event_request *req = get_req_buffer();
req->event.code = LOAD_DLL_DEBUG_EVENT;
@ -107,8 +56,8 @@ DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name )
req->event.info.load_dll.dbg_size = 0; /* FIXME */
req->event.info.load_dll.name = name;
req->event.info.load_dll.unicode = 0;
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
return ret;
server_call_noerr( REQ_SEND_DEBUG_EVENT );
return req->status;
}
@ -119,13 +68,12 @@ DWORD DEBUG_SendLoadDLLEvent( HFILE file, HMODULE module, LPSTR *name )
*/
DWORD DEBUG_SendUnloadDLLEvent( HMODULE module )
{
DWORD ret = 0;
struct send_debug_event_request *req = get_req_buffer();
req->event.code = UNLOAD_DLL_DEBUG_EVENT;
req->event.info.unload_dll.base = (void *)module;
if (!server_call( REQ_SEND_DEBUG_EVENT )) ret = req->status;
return ret;
server_call_noerr( REQ_SEND_DEBUG_EVENT );
return req->status;
}
@ -155,6 +103,9 @@ BOOL WINAPI WaitForDebugEvent( LPDEBUG_EVENT event, DWORD timeout )
event->dwThreadId = (DWORD)req->tid;
switch(req->event.code)
{
case 0: /* timeout */
SetLastError( ERROR_SEM_TIMEOUT );
return FALSE;
case EXCEPTION_DEBUG_EVENT:
event->u.Exception.ExceptionRecord.ExceptionCode = req->event.info.exception.code;
event->u.Exception.ExceptionRecord.ExceptionFlags = req->event.info.exception.flags;

View File

@ -26,7 +26,6 @@
#include "server.h"
#include "options.h"
#include "callback.h"
#include "debugger.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(process)
@ -371,6 +370,7 @@ BOOL PROCESS_Init( BOOL win32 )
*/
void PROCESS_Start(void)
{
struct init_process_done_request *req = get_req_buffer();
UINT cmdShow = SW_SHOWNORMAL;
LPTHREAD_START_ROUTINE entry = NULL;
PDB *pdb = PROCESS_Current();
@ -452,16 +452,15 @@ void PROCESS_Start(void)
PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0, 0 );
/* Signal the parent process to continue */
req->module = (void *)pModule->module32;
req->entry = entry;
server_call( REQ_INIT_PROCESS_DONE );
/* Send all required start-up debugger events */
if ( type == PROC_WIN32 && (pdb->flags & PDB32_DEBUGGED) )
{
EnterCriticalSection( &pdb->crit_section );
DEBUG_SendCreateProcessEvent( -1 /*FIXME*/, pModule->module32, entry );
MODULE_SendLoadDLLEvents();
LeaveCriticalSection( &pdb->crit_section );
}
@ -479,10 +478,6 @@ void PROCESS_Start(void)
LeaveCriticalSection( &pdb->crit_section );
}
/* If requested, add entry point breakpoint */
if ( Options.debug || (pdb->flags & PDB32_DEBUGGED) )
DEBUG_AddTaskEntryBreakpoint( pdb->task );
/* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
if ( type != PROC_WIN16 && (pdb->flags & PDB32_CONSOLE_PROC))
PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 );

View File

@ -276,9 +276,6 @@ static void THREAD_Start(void)
PROCESS_CallUserSignalProc( USIG_THREAD_INIT, (DWORD)NtCurrentTeb()->tid, 0 );
PE_InitTls();
MODULE_DllThreadAttach( NULL );
if (NtCurrentTeb()->process->flags & PDB32_DEBUGGED) DEBUG_SendCreateThreadEvent( func );
ExitThread( func( NtCurrentTeb()->entry_arg ) );
}

View File

@ -97,30 +97,43 @@ static int fill_debug_event( struct thread *debugger, struct thread *thread,
/* 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 @@ static int fill_debug_event( struct thread *debugger, struct thread *thread,
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 @@ static void build_wait_debug_reply( struct thread *thread, struct object *obj, i
req->event.code = 0;
req->pid = 0;
req->tid = 0;
thread->error = signaled;
}
}
@ -330,9 +351,10 @@ static int continue_debug_event( struct process *process, struct thread *thread,
}
/* 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 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
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 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
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 @@ int debugger_attach( struct process *process, struct thread *debugger )
}
/* 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(continue_debug_event)
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;

View File

@ -154,7 +154,8 @@ extern int free_console( struct process *process );
/* 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 */

View File

@ -584,6 +584,9 @@ DECL_HANDLER(init_process_done)
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;

View File

@ -37,6 +37,7 @@ struct process
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_process( struct process *process, int exit_code );
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 */

View File

@ -92,25 +92,32 @@ static struct thread *booting_thread;
/* 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 @@ struct thread *create_thread( int fd, struct process *process, int suspend )
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 @@ void kill_thread( struct thread *thread, int exit_code )
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 @@ DECL_HANDLER(init_thread)
}
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 */

View File

@ -48,6 +48,7 @@ struct thread
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 int get_error(void) { return current->error; }
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 */

View File

@ -258,25 +258,26 @@ static void dump_init_process_reply( const struct init_process_request *req )
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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(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,