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 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;
}

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.
*/
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;
}

View File

@ -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;

View 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

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);
wine_server_add_data( req, main_exe_name->Buffer, main_exe_name->Length );
wine_server_call( req );
peb->BeingDebugged = reply->debugged;
}
SERVER_END_REQ;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 );
}
}

View File

@ -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 );

View File

@ -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 */

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 )
{
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,