From e55d5937acdd1e759e6c53f239dea7a920bc67c6 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
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;
-	}
-
-	/* should only be there when loop == 0 */
+        if (epointers->ExceptionRecord->ExceptionCode == CONTROL_C_EXIT)
+        {
+            /* do not launch the debugger on ^C, simply terminate the process */
+            TerminateProcess( GetCurrentProcess(), 1 );
+        }
 
-	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,
-- 
GitLab