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:
parent
0b1a82aa5e
commit
e55d5937ac
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue