From e55d5937acdd1e759e6c53f239dea7a920bc67c6 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 14 Oct 2003 01:30:42 +0000 Subject: [PATCH] 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. --- dlls/kernel/debugger.c | 9 +---- dlls/kernel/except.c | 72 +++++++++++++++------------------- dlls/kernel/process.c | 3 +- dlls/ntdll/exception.c | 4 +- dlls/ntdll/loader.c | 1 - include/wine/server_protocol.h | 5 +-- server/debugger.c | 9 ++++- server/process.c | 71 +++++++++++++++++++-------------- server/process.h | 3 +- server/protocol.def | 4 +- server/trace.c | 9 +---- 11 files changed, 93 insertions(+), 97 deletions(-) diff --git a/dlls/kernel/debugger.c b/dlls/kernel/debugger.c index 94c0fc1cc78..dd2e015dfa4 100644 --- a/dlls/kernel/debugger.c +++ b/dlls/kernel/debugger.c @@ -334,14 +334,7 @@ void WINAPI DebugBreak16( */ BOOL WINAPI IsDebuggerPresent(void) { - BOOL ret = FALSE; - SERVER_START_REQ( get_process_info ) - { - req->handle = GetCurrentProcess(); - if (!wine_server_call_err( req )) ret = reply->debugged; - } - SERVER_END_REQ; - return ret; + return NtCurrentTeb()->Peb->BeingDebugged; } diff --git a/dlls/kernel/except.c b/dlls/kernel/except.c index 1d1910cc4b8..10042e2ea52 100644 --- a/dlls/kernel/except.c +++ b/dlls/kernel/except.c @@ -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. */ -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; 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; wine_server_add_data( req, context, sizeof(*context) ); 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; - 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 * 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) { - int status; - int loop = 0; + NTSTATUS status; 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 */ - 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 */ - 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; - } + if (epointers->ExceptionRecord->ExceptionCode == CONTROL_C_EXIT) + { + /* do not launch the debugger on ^C, simply terminate the process */ + TerminateProcess( GetCurrentProcess(), 1 ); + } - /* 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) - { - DWORD ret = top_filter( epointers ); - if (ret != EXCEPTION_CONTINUE_SEARCH) return ret; - } + /* FIXME: Should check the current error mode */ - /* FIXME: Should check the current error mode */ - - if (!start_debugger_atomic( epointers )) - return EXCEPTION_EXECUTE_HANDLER; - /* now that we should have a debugger attached, try to resend event */ + if (!start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged) + return EXCEPTION_EXECUTE_HANDLER; } + /* 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; } diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c index 2dbc53d00a0..6525129aa5f 100644 --- a/dlls/kernel/process.c +++ b/dlls/kernel/process.c @@ -617,7 +617,8 @@ static BOOL process_init( char *argv[], char **environ ) /* Retrieve startup info from the server */ 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 ))) { main_exe_file = reply->exe_file; diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index fab08ab0840..6a22c615e7c 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -130,6 +130,8 @@ static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *c int ret; HANDLE handle = 0; + if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */ + SERVER_START_REQ( queue_exception_event ) { 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; } 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 * once the event is passed to the debugger, so when we get back diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 1db8853d4c0..d2ec43a4a98 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1820,7 +1820,6 @@ void WINAPI LdrInitializeThunk( HANDLE main_file, void *CreateFileW_ptr, ULONG u req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI); wine_server_add_data( req, main_exe_name->Buffer, main_exe_name->Length ); wine_server_call( req ); - peb->BeingDebugged = reply->debugged; } SERVER_END_REQ; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index b00233ce4a3..e766d704e5b 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -236,6 +236,7 @@ struct boot_done_reply struct init_process_request { struct request_header __header; + void* peb; void* ldt_copy; }; struct init_process_reply @@ -278,7 +279,6 @@ struct init_process_done_request struct init_process_done_reply { struct reply_header __header; - int debugged; }; @@ -342,7 +342,6 @@ struct get_process_info_reply { struct reply_header __header; process_id_t pid; - int debugged; int exit_code; int priority; int process_affinity; @@ -3668,6 +3667,6 @@ union generic_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 */ diff --git a/server/debugger.c b/server/debugger.c index 567061721fd..e7c1b9a0e02 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -436,6 +436,12 @@ static int debugger_attach( struct process *process, struct thread *debugger ) resume_process( process ); return 0; } + if (!set_process_debug_flag( process, 1 )) + { + process->debugger = NULL; + resume_process( process ); + return 0; + } return 1; error: @@ -480,8 +486,7 @@ int debugger_detach( struct process *process, struct thread *debugger ) /* remove relationships between process and its debugger */ process->debugger = NULL; - release_object( debugger->debug_ctx ); - debugger->debug_ctx = NULL; + if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */ detach_process( process ); /* from this function */ diff --git a/server/process.c b/server/process.c index 7be8afd5ad0..fd96614dc7d 100644 --- a/server/process.c +++ b/server/process.c @@ -271,6 +271,7 @@ struct thread *create_process( int fd ) process->idle_event = NULL; process->queue = NULL; process->atom_table = NULL; + process->peb = NULL; process->ldt_copy = NULL; process->exe.next = 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 */ /* len is the total size (in ints) */ 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 */ /* 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 */ -static void write_process_memory( struct process *process, int *addr, size_t len, - unsigned int first_mask, unsigned int last_mask, const int *src ) +static int write_process_memory( struct process *process, int *addr, size_t len, + unsigned int first_mask, unsigned int last_mask, const int *src ) { struct thread *thread = process->thread_list; + int ret = 0; assert( !((unsigned int)addr % sizeof(int) )); /* address must be aligned */ if (!thread) /* process is dead */ { set_error( STATUS_ACCESS_DENIED ); - return; + return 0; } 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 */ if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done; + ret = 1; done: 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 */ @@ -965,7 +956,18 @@ DECL_HANDLER(init_process) fatal_protocol_error( current, "init_process: called twice\n" ); 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; + current->process->peb = req->peb; current->process->ldt_copy = req->ldt_copy; 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 (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 */ @@ -1037,7 +1039,11 @@ DECL_HANDLER(get_process_info) 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 ); } } @@ -1049,7 +1055,12 @@ DECL_HANDLER(set_process_info) 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 ); } } diff --git a/server/process.h b/server/process.h index 10709d4ae4d..cd759f2efb2 100644 --- a/server/process.h +++ b/server/process.h @@ -76,8 +76,8 @@ struct process struct atom_table *atom_table; /* pointer to local atom table */ struct token *token; /* security token associated with this process */ 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_flags; /* pointer to LDT flags in client addr space */ }; 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 int process_set_debugger( struct process *process, struct thread *thread ); 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, struct thread *thread ); diff --git a/server/protocol.def b/server/protocol.def index e11111c0578..384eb24418f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -229,6 +229,7 @@ typedef struct /* Initialize a process; called from the new process context */ @REQ(init_process) + void* peb; /* addr of PEB */ void* ldt_copy; /* addr of LDT copy */ @REPLY int create_flags; /* creation flags */ @@ -257,8 +258,6 @@ typedef struct obj_handle_t exe_file; /* file handle for main exe */ int gui; /* is it a GUI process? */ VARARG(filename,unicode_str); /* file name of main exe */ -@REPLY - int debugged; /* being debugged? */ @END @@ -302,7 +301,6 @@ typedef struct obj_handle_t handle; /* process handle */ @REPLY process_id_t pid; /* server process id */ - int debugged; /* debugged? */ int exit_code; /* process exit code */ int priority; /* priority class */ int process_affinity; /* process affinity mask */ diff --git a/server/trace.c b/server/trace.c index 99ae64955c3..fb93e53a479 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ) { + fprintf( stderr, " peb=%p,", req->peb ); 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 ); } -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 ) { 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 ) { fprintf( stderr, " pid=%04x,", req->pid ); - fprintf( stderr, " debugged=%d,", req->debugged ); fprintf( stderr, " exit_code=%d,", req->exit_code ); fprintf( stderr, " priority=%d,", req->priority ); 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)dump_init_process_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_terminate_process_reply, (dump_func)dump_terminate_thread_reply,