ntdll: Implement NtDebugActiveProcess() and NtRemoveProcessDebug().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-02-01 11:09:01 +01:00
parent 11e6f1007c
commit 46b84e7a83
11 changed files with 107 additions and 82 deletions

View File

@ -91,22 +91,15 @@ BOOL WINAPI DECLSPEC_HOTPATCH ContinueDebugEvent( DWORD pid, DWORD tid, DWORD st
BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcess( DWORD pid )
{
HANDLE process;
BOOL ret;
NTSTATUS status;
SERVER_START_REQ( debug_process )
{
req->pid = pid;
req->attach = 1;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
if (!ret) return FALSE;
if (!(process = OpenProcess( PROCESS_CREATE_THREAD, FALSE, pid ))) return FALSE;
ret = set_ntstatus( DbgUiIssueRemoteBreakin( process ));
if (!set_ntstatus( DbgUiConnectToDbg() )) return FALSE;
if (!(process = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME |
PROCESS_CREATE_THREAD, FALSE, pid )))
return FALSE;
status = DbgUiDebugActiveProcess( process );
NtClose( process );
if (!ret) DebugActiveProcessStop( pid );
return ret;
return set_ntstatus( status );
}
@ -115,16 +108,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcess( DWORD pid )
*/
BOOL WINAPI DECLSPEC_HOTPATCH DebugActiveProcessStop( DWORD pid )
{
BOOL ret;
HANDLE process;
NTSTATUS status;
SERVER_START_REQ( debug_process )
{
req->pid = pid;
req->attach = 0;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
return ret;
if (!(process = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME, FALSE, pid )))
return FALSE;
status = DbgUiStopDebugging( process );
NtClose( process );
return set_ntstatus( status );
}

View File

@ -37,12 +37,12 @@
@ stdcall DbgUiConnectToDbg()
@ stub DbgUiContinue
@ stub DbgUiConvertStateChangeStructure
# @ stub DbgUiDebugActiveProcess
@ stdcall DbgUiDebugActiveProcess(long)
@ stdcall DbgUiGetThreadDebugObject()
@ stdcall DbgUiIssueRemoteBreakin(long)
@ stdcall DbgUiRemoteBreakin(ptr)
@ stdcall DbgUiSetThreadDebugObject(long)
# @ stub DbgUiStopDebugging
@ stdcall DbgUiStopDebugging(long)
@ stub DbgUiWaitStateChange
@ stdcall DbgUserBreakPoint()
@ stdcall EtwEventActivityIdControl(long ptr)
@ -340,7 +340,7 @@
@ stdcall -syscall NtReleaseSemaphore(long long ptr)
@ stdcall -syscall NtRemoveIoCompletion(ptr ptr ptr ptr ptr)
@ stdcall -syscall NtRemoveIoCompletionEx(ptr ptr long ptr ptr long)
# @ stub NtRemoveProcessDebug
@ stdcall -syscall NtRemoveProcessDebug(long long)
@ stdcall -syscall NtRenameKey(long ptr)
@ stdcall -syscall NtReplaceKey(ptr long ptr)
@ stub NtReplyPort
@ -1345,7 +1345,7 @@
@ stdcall -private -syscall ZwReleaseSemaphore(long long ptr) NtReleaseSemaphore
@ stdcall -private -syscall ZwRemoveIoCompletion(ptr ptr ptr ptr ptr) NtRemoveIoCompletion
@ stdcall -private -syscall ZwRemoveIoCompletionEx(ptr ptr long ptr ptr long) NtRemoveIoCompletionEx
# @ stub ZwRemoveProcessDebug
@ stdcall -private -syscall ZwRemoveProcessDebug(long long) NtRemoveProcessDebug
@ stdcall -private -syscall ZwRenameKey(long ptr) NtRenameKey
@ stdcall -private -syscall ZwReplaceKey(ptr long ptr) NtReplaceKey
@ stub ZwReplyPort

View File

@ -150,6 +150,26 @@ NTSTATUS WINAPI DbgUiConnectToDbg(void)
return status;
}
/***********************************************************************
* DbgUiDebugActiveProcess (NTDLL.@)
*/
NTSTATUS WINAPI DbgUiDebugActiveProcess( HANDLE process )
{
NTSTATUS status;
if ((status = NtDebugActiveProcess( process, DbgUiGetThreadDebugObject() ))) return status;
if ((status = DbgUiIssueRemoteBreakin( process ))) DbgUiStopDebugging( process );
return status;
}
/***********************************************************************
* DbgUiStopDebugging (NTDLL.@)
*/
NTSTATUS WINAPI DbgUiStopDebugging( HANDLE process )
{
return NtRemoveProcessDebug( process, DbgUiGetThreadDebugObject() );
}
/***********************************************************************
* DbgUiRemoteBreakin (NTDLL.@)
*/

View File

@ -1746,10 +1746,38 @@ NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
/**********************************************************************
* NtDebugActiveProcess (NTDLL.@)
*/
NTSTATUS WINAPI NtDebugActiveProcess( HANDLE process, HANDLE debug_object )
NTSTATUS WINAPI NtDebugActiveProcess( HANDLE process, HANDLE debug )
{
FIXME( "(%p %p), stub!\n", process, debug_object );
return STATUS_SUCCESS;
NTSTATUS ret;
SERVER_START_REQ( debug_process )
{
req->handle = wine_server_obj_handle( process );
req->debug = wine_server_obj_handle( debug );
req->attach = 1;
ret = wine_server_call( req );
}
SERVER_END_REQ;
return ret;
}
/**********************************************************************
* NtRemoveProcessDebug (NTDLL.@)
*/
NTSTATUS WINAPI NtRemoveProcessDebug( HANDLE process, HANDLE debug )
{
NTSTATUS ret;
SERVER_START_REQ( debug_process )
{
req->handle = wine_server_obj_handle( process );
req->debug = wine_server_obj_handle( debug );
req->attach = 0;
ret = wine_server_call( req );
}
SERVER_END_REQ;
return ret;
}

View File

@ -2094,9 +2094,9 @@ struct continue_debug_event_reply
struct debug_process_request
{
struct request_header __header;
process_id_t pid;
obj_handle_t handle;
obj_handle_t debug;
int attach;
char __pad_20[4];
};
struct debug_process_reply
{
@ -6211,7 +6211,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 658
#define SERVER_PROTOCOL_VERSION 659
/* ### protocol_version end ### */

View File

@ -3023,10 +3023,12 @@ NTSYSAPI void WINAPI DbgBreakPoint(void);
NTSYSAPI NTSTATUS WINAPIV DbgPrint(LPCSTR fmt, ...);
NTSYSAPI NTSTATUS WINAPIV DbgPrintEx(ULONG iComponentId, ULONG Level, LPCSTR fmt, ...);
NTSYSAPI NTSTATUS WINAPI DbgUiConnectToDbg(void);
NTSYSAPI NTSTATUS WINAPI DbgUiDebugActiveProcess(HANDLE);
NTSYSAPI HANDLE WINAPI DbgUiGetThreadDebugObject(void);
NTSYSAPI NTSTATUS WINAPI DbgUiIssueRemoteBreakin(HANDLE);
NTSYSAPI void WINAPI DbgUiRemoteBreakin(void*);
NTSYSAPI void WINAPI DbgUiSetThreadDebugObject(HANDLE);
NTSYSAPI NTSTATUS WINAPI DbgUiStopDebugging(HANDLE);
NTSYSAPI void WINAPI DbgUserBreakPoint(void);
NTSYSAPI NTSTATUS WINAPI LdrAccessResource(HMODULE,const IMAGE_RESOURCE_DATA_ENTRY*,void**,PULONG);
NTSYSAPI NTSTATUS WINAPI LdrAddDllDirectory(const UNICODE_STRING*,void**);
@ -3104,6 +3106,7 @@ NTSYSAPI NTSTATUS WINAPI NtCreateThreadEx(HANDLE*,ACCESS_MASK,OBJECT_ATTRIBUTES
NTSYSAPI NTSTATUS WINAPI NtCreateTimer(HANDLE*, ACCESS_MASK, const OBJECT_ATTRIBUTES*, TIMER_TYPE);
NTSYSAPI NTSTATUS WINAPI NtCreateToken(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,TOKEN_TYPE,PLUID,PLARGE_INTEGER,PTOKEN_USER,PTOKEN_GROUPS,PTOKEN_PRIVILEGES,PTOKEN_OWNER,PTOKEN_PRIMARY_GROUP,PTOKEN_DEFAULT_DACL,PTOKEN_SOURCE);
NTSYSAPI NTSTATUS WINAPI NtCreateUserProcess(HANDLE*,HANDLE*,ACCESS_MASK,ACCESS_MASK,OBJECT_ATTRIBUTES*,OBJECT_ATTRIBUTES*,ULONG,ULONG,RTL_USER_PROCESS_PARAMETERS*,PS_CREATE_INFO*,PS_ATTRIBUTE_LIST*);
NTSYSAPI NTSTATUS WINAPI NtDebugActiveProcess(HANDLE,HANDLE);
NTSYSAPI NTSTATUS WINAPI NtDelayExecution(BOOLEAN,const LARGE_INTEGER*);
NTSYSAPI NTSTATUS WINAPI NtDeleteAtom(RTL_ATOM);
NTSYSAPI NTSTATUS WINAPI NtDeleteFile(POBJECT_ATTRIBUTES);
@ -3228,6 +3231,7 @@ NTSYSAPI NTSTATUS WINAPI NtReleaseMutant(HANDLE,PLONG);
NTSYSAPI NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG);
NTSYSAPI NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,PULONG_PTR,PIO_STATUS_BLOCK,PLARGE_INTEGER);
NTSYSAPI NTSTATUS WINAPI NtRemoveIoCompletionEx(HANDLE,FILE_IO_COMPLETION_INFORMATION*,ULONG,ULONG*,LARGE_INTEGER*,BOOLEAN);
NTSYSAPI NTSTATUS WINAPI NtRemoveProcessDebug(HANDLE,HANDLE);
NTSYSAPI NTSTATUS WINAPI NtRenameKey(HANDLE,UNICODE_STRING*);
NTSYSAPI NTSTATUS WINAPI NtReplaceKey(POBJECT_ATTRIBUTES,HANDLE,POBJECT_ATTRIBUTES);
NTSYSAPI NTSTATUS WINAPI NtReplyPort(HANDLE,PLPC_MESSAGE);

View File

@ -485,34 +485,30 @@ void resume_delayed_debug_events( struct thread *thread )
}
/* attach a process to a debugger thread and suspend it */
static int debugger_attach( struct process *process, struct thread *debugger )
static int debugger_attach( struct process *process, struct thread *debugger, struct debug_obj *debug_obj )
{
if (process->debug_obj) goto error; /* already being debugged */
if (debugger->process == process) goto error;
if (!is_process_init_done( process )) goto error; /* still starting up */
if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */
/* don't let a debugger debug its console... won't work */
if (debugger->process->console)
{
struct thread *renderer = console_get_renderer(debugger->process->console);
if (renderer && renderer->process == process)
goto error;
if (renderer && renderer->process == process) goto error;
}
if (!debugger->debug_obj) debugger->debug_obj = (struct debug_obj *)grab_object( debug_obj );
suspend_process( process );
if (!set_process_debugger( process, debugger ))
{
resume_process( process );
return 0;
}
if (!set_process_debug_flag( process, 1 ))
{
process->debug_obj = NULL;
resume_process( process );
return 0;
}
process->debug_obj = debug_obj;
process->debug_children = 0;
generate_startup_debug_events( process, 0 );
resume_process( process );
return 1;
error:
@ -526,9 +522,6 @@ void debugger_detach( struct process *process, struct debug_obj *debug_obj )
{
struct debug_event *event, *next;
/* init should be done, otherwise wouldn't be attached */
assert(is_process_init_done(process));
suspend_process( process );
/* send continue indication for all events */
@ -549,7 +542,6 @@ void debugger_detach( struct process *process, struct debug_obj *debug_obj )
process->debug_obj = NULL;
if (!set_process_debug_flag( process, 0 )) clear_error(); /* ignore error */
/* from this function */
resume_process( process );
}
@ -584,22 +576,6 @@ void generate_startup_debug_events( struct process *process, client_ptr_t entry
}
}
/* set the debugger of a given process */
int set_process_debugger( struct process *process, struct thread *debugger )
{
struct debug_obj *debug_obj;
assert( !process->debug_obj );
if (!debugger->debug_obj) /* need to allocate a context */
{
if (!(debug_obj = create_debug_obj( NULL, NULL, 0, DEBUG_KILL_ON_CLOSE, NULL ))) return 0;
debugger->debug_obj = debug_obj;
}
process->debug_obj = debugger->debug_obj;
return 1;
}
/* a thread is exiting */
void debug_exit_thread( struct thread *thread )
{
@ -692,23 +668,27 @@ DECL_HANDLER(continue_debug_event)
}
}
/* Start debugging an existing process */
/* start or stop debugging an existing process */
DECL_HANDLER(debug_process)
{
struct process *process = get_process_from_id( req->pid );
if (!process) return;
struct debug_obj *debug_obj;
struct process *process = get_process_from_handle( req->handle,
PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME );
if (!req->attach)
if (!process) return;
if ((debug_obj = get_debug_obj( current->process, req->debug, DEBUG_PROCESS_ASSIGN )))
{
if (current->debug_obj && process->debug_obj == current->debug_obj)
debugger_detach( process, current->debug_obj );
else
set_error( STATUS_ACCESS_DENIED );
if (req->attach)
{
if (!process->debug_obj) debugger_attach( process, current, debug_obj );
else set_error( STATUS_ACCESS_DENIED );
}
else if (debugger_attach( process, current ))
else
{
generate_startup_debug_events( process, 0 );
resume_process( process );
if (process->debug_obj == debug_obj) debugger_detach( process, debug_obj );
else set_error( STATUS_ACCESS_DENIED );
}
release_object( debug_obj );
}
release_object( process );
}

View File

@ -212,7 +212,6 @@ extern void sock_init(void);
/* debugger functions */
extern int set_process_debugger( struct process *process, struct thread *debugger );
extern void generate_debug_event( struct thread *thread, int code, const void *arg );
extern void resume_delayed_debug_events( struct thread *thread );
extern void generate_startup_debug_events( struct process *process, client_ptr_t entry );

View File

@ -1637,9 +1637,10 @@ struct process_info
@END
/* Start/stop debugging an existing process */
/* Start or stop debugging an existing process */
@REQ(debug_process)
process_id_t pid; /* id of the process to debug */
obj_handle_t handle; /* process handle */
obj_handle_t debug; /* debug object to attach to the process */
int attach; /* 1=attaching / 0=detaching from the process */
@END

View File

@ -1159,8 +1159,9 @@ C_ASSERT( FIELD_OFFSET(struct continue_debug_event_request, pid) == 12 );
C_ASSERT( FIELD_OFFSET(struct continue_debug_event_request, tid) == 16 );
C_ASSERT( FIELD_OFFSET(struct continue_debug_event_request, status) == 20 );
C_ASSERT( sizeof(struct continue_debug_event_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct debug_process_request, pid) == 12 );
C_ASSERT( FIELD_OFFSET(struct debug_process_request, attach) == 16 );
C_ASSERT( FIELD_OFFSET(struct debug_process_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct debug_process_request, debug) == 16 );
C_ASSERT( FIELD_OFFSET(struct debug_process_request, attach) == 20 );
C_ASSERT( sizeof(struct debug_process_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct set_debugger_kill_on_exit_request, kill_on_exit) == 12 );
C_ASSERT( sizeof(struct set_debugger_kill_on_exit_request) == 16 );

View File

@ -2206,7 +2206,8 @@ static void dump_continue_debug_event_request( const struct continue_debug_event
static void dump_debug_process_request( const struct debug_process_request *req )
{
fprintf( stderr, " pid=%04x", req->pid );
fprintf( stderr, " handle=%04x", req->handle );
fprintf( stderr, ", debug=%04x", req->debug );
fprintf( stderr, ", attach=%d", req->attach );
}