Set or clear the BeingDebugged flag in the PEB when a debugger is

attached to or detached from a process.
Don't send exception events to the server unless a debugger is
present.
This commit is contained in:
Alexandre Julliard 2003-10-14 01:30:42 +00:00
parent 0b1a82aa5e
commit e55d5937ac
11 changed files with 93 additions and 97 deletions

View File

@ -334,14 +334,7 @@ void WINAPI DebugBreak16(
*/ */
BOOL WINAPI IsDebuggerPresent(void) BOOL WINAPI IsDebuggerPresent(void)
{ {
BOOL ret = FALSE; return NtCurrentTeb()->Peb->BeingDebugged;
SERVER_START_REQ( get_process_info )
{
req->handle = GetCurrentProcess();
if (!wine_server_call_err( req )) ret = reply->debugged;
}
SERVER_END_REQ;
return ret;
} }

View File

@ -179,9 +179,9 @@ static int format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer, in
* *
* Send an EXCEPTION_DEBUG_EVENT event to the debugger. * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
*/ */
static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
{ {
int ret; NTSTATUS ret;
HANDLE handle = 0; HANDLE handle = 0;
SERVER_START_REQ( queue_exception_event ) SERVER_START_REQ( queue_exception_event )
@ -189,10 +189,10 @@ static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *c
req->first = first_chance; req->first = first_chance;
wine_server_add_data( req, context, sizeof(*context) ); wine_server_add_data( req, context, sizeof(*context) );
wine_server_add_data( req, rec, sizeof(*rec) ); wine_server_add_data( req, rec, sizeof(*rec) );
if (!wine_server_call(req)) handle = reply->handle; if (!(ret = wine_server_call( req ))) handle = reply->handle;
} }
SERVER_END_REQ; SERVER_END_REQ;
if (!handle) return 0; /* no debugger present or other error */ if (ret) return ret;
/* No need to wait on the handle since the process gets suspended /* No need to wait on the handle since the process gets suspended
* once the event is passed to the debugger, so when we get back * once the event is passed to the debugger, so when we get back
@ -433,51 +433,43 @@ inline static BOOL check_resource_write( const EXCEPTION_RECORD *rec )
*/ */
DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers) DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
{ {
int status; NTSTATUS status;
int loop = 0;
if (check_resource_write( epointers->ExceptionRecord )) return EXCEPTION_CONTINUE_EXECUTION; if (check_resource_write( epointers->ExceptionRecord )) return EXCEPTION_CONTINUE_EXECUTION;
for (loop = 0; loop <= 1; loop++) if (!NtCurrentTeb()->Peb->BeingDebugged)
{ {
/* send a last chance event to the debugger */ if (epointers->ExceptionRecord->ExceptionCode == CONTROL_C_EXIT)
status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord ); {
switch (status) /* do not launch the debugger on ^C, simply terminate the process */
{ TerminateProcess( GetCurrentProcess(), 1 );
case DBG_CONTINUE: }
return EXCEPTION_CONTINUE_EXECUTION;
case DBG_EXCEPTION_NOT_HANDLED:
TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
break; /* not reached */
case 0: /* no debugger is present */
if (epointers->ExceptionRecord->ExceptionCode == CONTROL_C_EXIT)
{
/* do not launch the debugger on ^C, simply terminate the process */
TerminateProcess( GetCurrentProcess(), 1 );
}
/* second try, the debugger isn't present... */
if (loop == 1) return EXCEPTION_EXECUTE_HANDLER;
break;
default:
FIXME("Unsupported yet debug continue value %d (please report)\n", status);
return EXCEPTION_EXECUTE_HANDLER;
}
/* should only be there when loop == 0 */ if (top_filter)
{
DWORD ret = top_filter( epointers );
if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
}
if (top_filter) /* FIXME: Should check the current error mode */
{
DWORD ret = top_filter( epointers );
if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
}
/* FIXME: Should check the current error mode */ if (!start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged)
return EXCEPTION_EXECUTE_HANDLER;
if (!start_debugger_atomic( epointers ))
return EXCEPTION_EXECUTE_HANDLER;
/* now that we should have a debugger attached, try to resend event */
} }
/* send a last chance event to the debugger */
status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord );
switch (status)
{
case DBG_CONTINUE:
return EXCEPTION_CONTINUE_EXECUTION;
case DBG_EXCEPTION_NOT_HANDLED:
TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
break; /* not reached */
default:
FIXME("Unhandled error on debug event: %lx\n", status);
break;
}
return EXCEPTION_EXECUTE_HANDLER; return EXCEPTION_EXECUTE_HANDLER;
} }

View File

@ -617,7 +617,8 @@ static BOOL process_init( char *argv[], char **environ )
/* Retrieve startup info from the server */ /* Retrieve startup info from the server */
SERVER_START_REQ( init_process ) SERVER_START_REQ( init_process )
{ {
req->ldt_copy = &wine_ldt_copy; req->peb = peb;
req->ldt_copy = &wine_ldt_copy;
if ((ret = !wine_server_call_err( req ))) if ((ret = !wine_server_call_err( req )))
{ {
main_exe_file = reply->exe_file; main_exe_file = reply->exe_file;

View File

@ -130,6 +130,8 @@ static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *c
int ret; int ret;
HANDLE handle = 0; HANDLE handle = 0;
if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */
SERVER_START_REQ( queue_exception_event ) SERVER_START_REQ( queue_exception_event )
{ {
req->first = first_chance; req->first = first_chance;
@ -138,7 +140,7 @@ static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *c
if (!wine_server_call( req )) handle = reply->handle; if (!wine_server_call( req )) handle = reply->handle;
} }
SERVER_END_REQ; SERVER_END_REQ;
if (!handle) return 0; /* no debugger present or other error */ if (!handle) return 0;
/* No need to wait on the handle since the process gets suspended /* No need to wait on the handle since the process gets suspended
* once the event is passed to the debugger, so when we get back * once the event is passed to the debugger, so when we get back

View File

@ -1820,7 +1820,6 @@ void WINAPI LdrInitializeThunk( HANDLE main_file, void *CreateFileW_ptr, ULONG u
req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI); req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI);
wine_server_add_data( req, main_exe_name->Buffer, main_exe_name->Length ); wine_server_add_data( req, main_exe_name->Buffer, main_exe_name->Length );
wine_server_call( req ); wine_server_call( req );
peb->BeingDebugged = reply->debugged;
} }
SERVER_END_REQ; SERVER_END_REQ;

View File

@ -236,6 +236,7 @@ struct boot_done_reply
struct init_process_request struct init_process_request
{ {
struct request_header __header; struct request_header __header;
void* peb;
void* ldt_copy; void* ldt_copy;
}; };
struct init_process_reply struct init_process_reply
@ -278,7 +279,6 @@ struct init_process_done_request
struct init_process_done_reply struct init_process_done_reply
{ {
struct reply_header __header; struct reply_header __header;
int debugged;
}; };
@ -342,7 +342,6 @@ struct get_process_info_reply
{ {
struct reply_header __header; struct reply_header __header;
process_id_t pid; process_id_t pid;
int debugged;
int exit_code; int exit_code;
int priority; int priority;
int process_affinity; int process_affinity;
@ -3668,6 +3667,6 @@ union generic_reply
struct set_global_windows_reply set_global_windows_reply; struct set_global_windows_reply set_global_windows_reply;
}; };
#define SERVER_PROTOCOL_VERSION 125 #define SERVER_PROTOCOL_VERSION 126
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -436,6 +436,12 @@ static int debugger_attach( struct process *process, struct thread *debugger )
resume_process( process ); resume_process( process );
return 0; return 0;
} }
if (!set_process_debug_flag( process, 1 ))
{
process->debugger = NULL;
resume_process( process );
return 0;
}
return 1; return 1;
error: error:
@ -480,8 +486,7 @@ int debugger_detach( struct process *process, struct thread *debugger )
/* remove relationships between process and its debugger */ /* remove relationships between process and its debugger */
process->debugger = NULL; process->debugger = NULL;
release_object( debugger->debug_ctx ); if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */
debugger->debug_ctx = NULL;
detach_process( process ); detach_process( process );
/* from this function */ /* from this function */

View File

@ -271,6 +271,7 @@ struct thread *create_process( int fd )
process->idle_event = NULL; process->idle_event = NULL;
process->queue = NULL; process->queue = NULL;
process->atom_table = NULL; process->atom_table = NULL;
process->peb = NULL;
process->ldt_copy = NULL; process->ldt_copy = NULL;
process->exe.next = NULL; process->exe.next = NULL;
process->exe.prev = NULL; process->exe.prev = NULL;
@ -720,30 +721,6 @@ void enum_processes( int (*cb)(struct process*, void*), void *user )
} }
/* get all information about a process */
static void get_process_info( struct process *process, struct get_process_info_reply *reply )
{
reply->pid = get_process_id( process );
reply->debugged = (process->debugger != 0);
reply->exit_code = process->exit_code;
reply->priority = process->priority;
reply->process_affinity = process->affinity;
reply->system_affinity = 1;
}
/* set all information about a process */
static void set_process_info( struct process *process,
const struct set_process_info_request *req )
{
if (req->mask & SET_PROCESS_INFO_PRIORITY)
process->priority = req->priority;
if (req->mask & SET_PROCESS_INFO_AFFINITY)
{
if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
else process->affinity = req->affinity;
}
}
/* read data from a process memory space */ /* read data from a process memory space */
/* len is the total size (in ints) */ /* len is the total size (in ints) */
static int read_process_memory( struct process *process, const int *addr, size_t len, int *dest ) static int read_process_memory( struct process *process, const int *addr, size_t len, int *dest )
@ -788,17 +765,18 @@ static int check_process_write_access( struct thread *thread, int *addr, size_t
/* write data to a process memory space */ /* write data to a process memory space */
/* len is the total size (in ints), max is the size we can actually read from the input buffer */ /* len is the total size (in ints), max is the size we can actually read from the input buffer */
/* we check the total size for write permissions */ /* we check the total size for write permissions */
static void write_process_memory( struct process *process, int *addr, size_t len, static int write_process_memory( struct process *process, int *addr, size_t len,
unsigned int first_mask, unsigned int last_mask, const int *src ) unsigned int first_mask, unsigned int last_mask, const int *src )
{ {
struct thread *thread = process->thread_list; struct thread *thread = process->thread_list;
int ret = 0;
assert( !((unsigned int)addr % sizeof(int) )); /* address must be aligned */ assert( !((unsigned int)addr % sizeof(int) )); /* address must be aligned */
if (!thread) /* process is dead */ if (!thread) /* process is dead */
{ {
set_error( STATUS_ACCESS_DENIED ); set_error( STATUS_ACCESS_DENIED );
return; return 0;
} }
if (suspend_for_ptrace( thread )) if (suspend_for_ptrace( thread ))
{ {
@ -823,10 +801,23 @@ static void write_process_memory( struct process *process, int *addr, size_t len
/* last word is special too */ /* last word is special too */
if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done; if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done;
ret = 1;
done: done:
resume_after_ptrace( thread ); resume_after_ptrace( thread );
} }
return ret;
}
/* set the debugged flag in the process PEB */
int set_process_debug_flag( struct process *process, int flag )
{
int mask = 0, data = 0;
/* BeingDebugged flag is the byte at offset 2 in the PEB */
memset( (char *)&mask + 2, 0xff, 1 );
memset( (char *)&data + 2, flag, 1 );
return write_process_memory( process, process->peb, 1, mask, mask, &data );
} }
/* take a snapshot of currently running processes */ /* take a snapshot of currently running processes */
@ -965,7 +956,18 @@ DECL_HANDLER(init_process)
fatal_protocol_error( current, "init_process: called twice\n" ); fatal_protocol_error( current, "init_process: called twice\n" );
return; return;
} }
if (!req->peb || (unsigned int)req->peb % sizeof(int))
{
fatal_protocol_error( current, "init_process: bad peb address\n" );
return;
}
if (!req->ldt_copy || (unsigned int)req->ldt_copy % sizeof(int))
{
fatal_protocol_error( current, "init_process: bad ldt_copy address\n" );
return;
}
reply->info_size = 0; reply->info_size = 0;
current->process->peb = req->peb;
current->process->ldt_copy = req->ldt_copy; current->process->ldt_copy = req->ldt_copy;
current->process->startup_info = init_process( reply ); current->process->startup_info = init_process( reply );
} }
@ -1002,7 +1004,7 @@ DECL_HANDLER(init_process_done)
if (req->gui) process->idle_event = create_event( NULL, 0, 1, 0 ); if (req->gui) process->idle_event = create_event( NULL, 0, 1, 0 );
if (current->suspend + process->suspend > 0) stop_thread( current ); if (current->suspend + process->suspend > 0) stop_thread( current );
reply->debugged = (process->debugger != 0); if (process->debugger) set_process_debug_flag( process, 1 );
} }
/* open a handle to a process */ /* open a handle to a process */
@ -1037,7 +1039,11 @@ DECL_HANDLER(get_process_info)
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION ))) if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
{ {
get_process_info( process, reply ); reply->pid = get_process_id( process );
reply->exit_code = process->exit_code;
reply->priority = process->priority;
reply->process_affinity = process->affinity;
reply->system_affinity = 1;
release_object( process ); release_object( process );
} }
} }
@ -1049,7 +1055,12 @@ DECL_HANDLER(set_process_info)
if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION ))) if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION )))
{ {
set_process_info( process, req ); if (req->mask & SET_PROCESS_INFO_PRIORITY) process->priority = req->priority;
if (req->mask & SET_PROCESS_INFO_AFFINITY)
{
if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
else process->affinity = req->affinity;
}
release_object( process ); release_object( process );
} }
} }

View File

@ -76,8 +76,8 @@ struct process
struct atom_table *atom_table; /* pointer to local atom table */ struct atom_table *atom_table; /* pointer to local atom table */
struct token *token; /* security token associated with this process */ struct token *token; /* security token associated with this process */
struct process_dll exe; /* main exe file */ struct process_dll exe; /* main exe file */
void *peb; /* PEB address in client address space */
void *ldt_copy; /* pointer to LDT copy in client addr space */ void *ldt_copy; /* pointer to LDT copy in client addr space */
void *ldt_flags; /* pointer to LDT flags in client addr space */
}; };
struct process_snapshot struct process_snapshot
@ -107,6 +107,7 @@ 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 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 process_set_debugger( struct process *process, struct thread *thread );
extern int debugger_detach( struct process* process, struct thread* debugger ); extern int debugger_detach( struct process* process, struct thread* debugger );
extern int set_process_debug_flag( struct process *process, int flag );
extern void add_process_thread( struct process *process, extern void add_process_thread( struct process *process,
struct thread *thread ); struct thread *thread );

View File

@ -229,6 +229,7 @@ typedef struct
/* Initialize a process; called from the new process context */ /* Initialize a process; called from the new process context */
@REQ(init_process) @REQ(init_process)
void* peb; /* addr of PEB */
void* ldt_copy; /* addr of LDT copy */ void* ldt_copy; /* addr of LDT copy */
@REPLY @REPLY
int create_flags; /* creation flags */ int create_flags; /* creation flags */
@ -257,8 +258,6 @@ typedef struct
obj_handle_t exe_file; /* file handle for main exe */ obj_handle_t exe_file; /* file handle for main exe */
int gui; /* is it a GUI process? */ int gui; /* is it a GUI process? */
VARARG(filename,unicode_str); /* file name of main exe */ VARARG(filename,unicode_str); /* file name of main exe */
@REPLY
int debugged; /* being debugged? */
@END @END
@ -302,7 +301,6 @@ typedef struct
obj_handle_t handle; /* process handle */ obj_handle_t handle; /* process handle */
@REPLY @REPLY
process_id_t pid; /* server process id */ process_id_t pid; /* server process id */
int debugged; /* debugged? */
int exit_code; /* process exit code */ int exit_code; /* process exit code */
int priority; /* priority class */ int priority; /* priority class */
int process_affinity; /* process affinity mask */ int process_affinity; /* process affinity mask */

View File

@ -451,6 +451,7 @@ static void dump_boot_done_request( const struct boot_done_request *req )
static void dump_init_process_request( const struct init_process_request *req ) static void dump_init_process_request( const struct init_process_request *req )
{ {
fprintf( stderr, " peb=%p,", req->peb );
fprintf( stderr, " ldt_copy=%p", req->ldt_copy ); fprintf( stderr, " ldt_copy=%p", req->ldt_copy );
} }
@ -487,11 +488,6 @@ static void dump_init_process_done_request( const struct init_process_done_reque
dump_varargs_unicode_str( cur_size ); dump_varargs_unicode_str( cur_size );
} }
static void dump_init_process_done_reply( const struct init_process_done_reply *req )
{
fprintf( stderr, " debugged=%d", req->debugged );
}
static void dump_init_thread_request( const struct init_thread_request *req ) static void dump_init_thread_request( const struct init_thread_request *req )
{ {
fprintf( stderr, " unix_pid=%d,", req->unix_pid ); fprintf( stderr, " unix_pid=%d,", req->unix_pid );
@ -541,7 +537,6 @@ static void dump_get_process_info_request( const struct get_process_info_request
static void dump_get_process_info_reply( const struct get_process_info_reply *req ) static void dump_get_process_info_reply( const struct get_process_info_reply *req )
{ {
fprintf( stderr, " pid=%04x,", req->pid ); fprintf( stderr, " pid=%04x,", req->pid );
fprintf( stderr, " debugged=%d,", req->debugged );
fprintf( stderr, " exit_code=%d,", req->exit_code ); fprintf( stderr, " exit_code=%d,", req->exit_code );
fprintf( stderr, " priority=%d,", req->priority ); fprintf( stderr, " priority=%d,", req->priority );
fprintf( stderr, " process_affinity=%d,", req->process_affinity ); fprintf( stderr, " process_affinity=%d,", req->process_affinity );
@ -2738,7 +2733,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0, (dump_func)0,
(dump_func)dump_init_process_reply, (dump_func)dump_init_process_reply,
(dump_func)dump_get_startup_info_reply, (dump_func)dump_get_startup_info_reply,
(dump_func)dump_init_process_done_reply, (dump_func)0,
(dump_func)dump_init_thread_reply, (dump_func)dump_init_thread_reply,
(dump_func)dump_terminate_process_reply, (dump_func)dump_terminate_process_reply,
(dump_func)dump_terminate_thread_reply, (dump_func)dump_terminate_thread_reply,