server: Implement retrieving the debug object of a process.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-02-08 12:09:44 +01:00
parent 988dc7753a
commit 52d733b5c4
7 changed files with 97 additions and 27 deletions

View File

@ -1813,12 +1813,12 @@ static void test_query_process_debug_object_handle(int argc, char **argv)
debug_object = (HANDLE)0xdeadbeef; debug_object = (HANDLE)0xdeadbeef;
status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugObjectHandle, status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugObjectHandle,
&debug_object, sizeof(debug_object), NULL); &debug_object, sizeof(debug_object), NULL);
todo_wine
ok(status == STATUS_SUCCESS, ok(status == STATUS_SUCCESS,
"Expected NtQueryInformationProcess to return STATUS_SUCCESS, got 0x%08x\n", status); "Expected NtQueryInformationProcess to return STATUS_SUCCESS, got 0x%08x\n", status);
todo_wine
ok(debug_object != NULL, ok(debug_object != NULL,
"Expected debug object handle to be non-NULL, got %p\n", debug_object); "Expected debug object handle to be non-NULL, got %p\n", debug_object);
status = NtClose( debug_object );
ok( !status, "NtClose failed %x\n", status );
for (;;) for (;;)
{ {

View File

@ -1366,15 +1366,25 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
if (!info) ret = STATUS_ACCESS_VIOLATION; if (!info) ret = STATUS_ACCESS_VIOLATION;
else else
{ {
SERVER_START_REQ(get_process_info) HANDLE debug;
SERVER_START_REQ(get_process_debug_info)
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
if ((ret = wine_server_call( req )) == STATUS_SUCCESS) ret = wine_server_call( req );
{ debug = wine_server_ptr_handle( reply->debug );
*(DWORD_PTR *)info = reply->debugger_present ? ~(DWORD_PTR)0 : 0;
}
} }
SERVER_END_REQ; SERVER_END_REQ;
if (ret == STATUS_SUCCESS)
{
*(DWORD_PTR *)info = ~0ul;
NtClose( debug );
}
else if (ret == STATUS_PORT_NOT_SET)
{
*(DWORD_PTR *)info = 0;
ret = STATUS_SUCCESS;
}
} }
} }
else ret = STATUS_INFO_LENGTH_MISMATCH; else ret = STATUS_INFO_LENGTH_MISMATCH;
@ -1387,15 +1397,18 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
if (!info) ret = STATUS_ACCESS_VIOLATION; if (!info) ret = STATUS_ACCESS_VIOLATION;
else else
{ {
SERVER_START_REQ(get_process_info) HANDLE debug;
SERVER_START_REQ(get_process_debug_info)
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
if ((ret = wine_server_call( req )) == STATUS_SUCCESS) ret = wine_server_call( req );
{ debug = wine_server_ptr_handle( reply->debug );
*(DWORD *)info = reply->debug_children; *(DWORD *)info = reply->debug_children;
}
} }
SERVER_END_REQ; SERVER_END_REQ;
if (ret == STATUS_SUCCESS) NtClose( debug );
else if (ret == STATUS_PORT_NOT_SET) ret = STATUS_SUCCESS;
} }
} }
else ret = STATUS_INFO_LENGTH_MISMATCH; else ret = STATUS_INFO_LENGTH_MISMATCH;
@ -1408,17 +1421,19 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
break; break;
case ProcessDebugObjectHandle: case ProcessDebugObjectHandle:
/* "These are not the debuggers you are looking for." *
* set it to 0 aka "no debugger" to satisfy copy protections */
len = sizeof(HANDLE); len = sizeof(HANDLE);
if (size == len) if (size == len)
{ {
if (!info) ret = STATUS_ACCESS_VIOLATION; if (!info) ret = STATUS_ACCESS_VIOLATION;
else if (!handle) ret = STATUS_INVALID_HANDLE;
else else
{ {
memset(info, 0, size); SERVER_START_REQ(get_process_debug_info)
ret = STATUS_PORT_NOT_SET; {
req->handle = wine_server_obj_handle( handle );
ret = wine_server_call( req );
*(HANDLE *)info = wine_server_ptr_handle( reply->debug );
}
SERVER_END_REQ;
} }
} }
else ret = STATUS_INFO_LENGTH_MISMATCH; else ret = STATUS_INFO_LENGTH_MISMATCH;

View File

@ -1008,8 +1008,22 @@ struct get_process_info_reply
int exit_code; int exit_code;
int priority; int priority;
client_cpu_t cpu; client_cpu_t cpu;
short int debugger_present; /* VARARG(image,pe_image_info); */
short int debug_children; char __pad_60[4];
};
struct get_process_debug_info_request
{
struct request_header __header;
obj_handle_t handle;
};
struct get_process_debug_info_reply
{
struct reply_header __header;
obj_handle_t debug;
int debug_children;
/* VARARG(image,pe_image_info); */ /* VARARG(image,pe_image_info); */
}; };
@ -5427,6 +5441,7 @@ enum request
REQ_terminate_process, REQ_terminate_process,
REQ_terminate_thread, REQ_terminate_thread,
REQ_get_process_info, REQ_get_process_info,
REQ_get_process_debug_info,
REQ_get_process_vm_counters, REQ_get_process_vm_counters,
REQ_set_process_info, REQ_set_process_info,
REQ_get_thread_info, REQ_get_thread_info,
@ -5711,6 +5726,7 @@ union generic_request
struct terminate_process_request terminate_process_request; struct terminate_process_request terminate_process_request;
struct terminate_thread_request terminate_thread_request; struct terminate_thread_request terminate_thread_request;
struct get_process_info_request get_process_info_request; struct get_process_info_request get_process_info_request;
struct get_process_debug_info_request get_process_debug_info_request;
struct get_process_vm_counters_request get_process_vm_counters_request; struct get_process_vm_counters_request get_process_vm_counters_request;
struct set_process_info_request set_process_info_request; struct set_process_info_request set_process_info_request;
struct get_thread_info_request get_thread_info_request; struct get_thread_info_request get_thread_info_request;
@ -5993,6 +6009,7 @@ union generic_reply
struct terminate_process_reply terminate_process_reply; struct terminate_process_reply terminate_process_reply;
struct terminate_thread_reply terminate_thread_reply; struct terminate_thread_reply terminate_thread_reply;
struct get_process_info_reply get_process_info_reply; struct get_process_info_reply get_process_info_reply;
struct get_process_debug_info_reply get_process_debug_info_reply;
struct get_process_vm_counters_reply get_process_vm_counters_reply; struct get_process_vm_counters_reply get_process_vm_counters_reply;
struct set_process_info_reply set_process_info_reply; struct set_process_info_reply set_process_info_reply;
struct get_thread_info_reply get_thread_info_reply; struct get_thread_info_reply get_thread_info_reply;
@ -6263,7 +6280,7 @@ union generic_reply
/* ### protocol_version begin ### */ /* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 668 #define SERVER_PROTOCOL_VERSION 669
/* ### protocol_version end ### */ /* ### protocol_version end ### */

View File

@ -1422,8 +1422,6 @@ DECL_HANDLER(get_process_info)
reply->start_time = process->start_time; reply->start_time = process->start_time;
reply->end_time = process->end_time; reply->end_time = process->end_time;
reply->cpu = process->cpu; reply->cpu = process->cpu;
reply->debugger_present = !!process->debug_obj;
reply->debug_children = process->debug_children;
if (get_reply_max_size()) if (get_reply_max_size())
{ {
client_ptr_t base; client_ptr_t base;
@ -1436,6 +1434,19 @@ DECL_HANDLER(get_process_info)
} }
} }
/* retrieve debug information about a process */
DECL_HANDLER(get_process_debug_info)
{
struct process *process;
if (!(process = get_process_from_handle( req->handle, PROCESS_QUERY_LIMITED_INFORMATION ))) return;
reply->debug_children = process->debug_children;
if (!process->debug_obj) set_error( STATUS_PORT_NOT_SET );
else reply->debug = alloc_handle( current->process, process->debug_obj, DEBUG_ALL_ACCESS, 0 );
release_object( process );
}
/* retrieve information about a process memory usage */ /* retrieve information about a process memory usage */
DECL_HANDLER(get_process_vm_counters) DECL_HANDLER(get_process_vm_counters)
{ {

View File

@ -955,8 +955,16 @@ typedef struct
int exit_code; /* process exit code */ int exit_code; /* process exit code */
int priority; /* priority class */ int priority; /* priority class */
client_cpu_t cpu; /* CPU that this process is running on */ client_cpu_t cpu; /* CPU that this process is running on */
short int debugger_present; /* process is being debugged */ VARARG(image,pe_image_info); /* image info for main exe */
short int debug_children; /* inherit debugger to child processes */ @END
/* Retrieve debug information about a process */
@REQ(get_process_debug_info)
obj_handle_t handle; /* process handle */
@REPLY
obj_handle_t debug; /* handle to debug port */
int debug_children; /* inherit debugger to child processes */
VARARG(image,pe_image_info); /* image info for main exe */ VARARG(image,pe_image_info); /* image info for main exe */
@END @END

View File

@ -130,6 +130,7 @@ DECL_HANDLER(init_thread);
DECL_HANDLER(terminate_process); DECL_HANDLER(terminate_process);
DECL_HANDLER(terminate_thread); DECL_HANDLER(terminate_thread);
DECL_HANDLER(get_process_info); DECL_HANDLER(get_process_info);
DECL_HANDLER(get_process_debug_info);
DECL_HANDLER(get_process_vm_counters); DECL_HANDLER(get_process_vm_counters);
DECL_HANDLER(set_process_info); DECL_HANDLER(set_process_info);
DECL_HANDLER(get_thread_info); DECL_HANDLER(get_thread_info);
@ -413,6 +414,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_terminate_process, (req_handler)req_terminate_process,
(req_handler)req_terminate_thread, (req_handler)req_terminate_thread,
(req_handler)req_get_process_info, (req_handler)req_get_process_info,
(req_handler)req_get_process_debug_info,
(req_handler)req_get_process_vm_counters, (req_handler)req_get_process_vm_counters,
(req_handler)req_set_process_info, (req_handler)req_set_process_info,
(req_handler)req_get_thread_info, (req_handler)req_get_thread_info,
@ -799,9 +801,12 @@ C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, end_time) == 40 );
C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, exit_code) == 48 ); C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, exit_code) == 48 );
C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, priority) == 52 ); C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, priority) == 52 );
C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, cpu) == 56 ); C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, cpu) == 56 );
C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, debugger_present) == 60 );
C_ASSERT( FIELD_OFFSET(struct get_process_info_reply, debug_children) == 62 );
C_ASSERT( sizeof(struct get_process_info_reply) == 64 ); C_ASSERT( sizeof(struct get_process_info_reply) == 64 );
C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_request, handle) == 12 );
C_ASSERT( sizeof(struct get_process_debug_info_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_reply, debug) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_process_debug_info_reply, debug_children) == 12 );
C_ASSERT( sizeof(struct get_process_debug_info_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_process_vm_counters_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_process_vm_counters_request, handle) == 12 );
C_ASSERT( sizeof(struct get_process_vm_counters_request) == 16 ); C_ASSERT( sizeof(struct get_process_vm_counters_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_process_vm_counters_reply, peak_virtual_size) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_process_vm_counters_reply, peak_virtual_size) == 8 );

View File

@ -1506,7 +1506,17 @@ static void dump_get_process_info_reply( const struct get_process_info_reply *re
fprintf( stderr, ", exit_code=%d", req->exit_code ); fprintf( stderr, ", exit_code=%d", req->exit_code );
fprintf( stderr, ", priority=%d", req->priority ); fprintf( stderr, ", priority=%d", req->priority );
dump_client_cpu( ", cpu=", &req->cpu ); dump_client_cpu( ", cpu=", &req->cpu );
fprintf( stderr, ", debugger_present=%d", req->debugger_present ); dump_varargs_pe_image_info( ", image=", cur_size );
}
static void dump_get_process_debug_info_request( const struct get_process_debug_info_request *req )
{
fprintf( stderr, " handle=%04x", req->handle );
}
static void dump_get_process_debug_info_reply( const struct get_process_debug_info_reply *req )
{
fprintf( stderr, " debug=%04x", req->debug );
fprintf( stderr, ", debug_children=%d", req->debug_children ); fprintf( stderr, ", debug_children=%d", req->debug_children );
dump_varargs_pe_image_info( ", image=", cur_size ); dump_varargs_pe_image_info( ", image=", cur_size );
} }
@ -4471,6 +4481,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_terminate_process_request, (dump_func)dump_terminate_process_request,
(dump_func)dump_terminate_thread_request, (dump_func)dump_terminate_thread_request,
(dump_func)dump_get_process_info_request, (dump_func)dump_get_process_info_request,
(dump_func)dump_get_process_debug_info_request,
(dump_func)dump_get_process_vm_counters_request, (dump_func)dump_get_process_vm_counters_request,
(dump_func)dump_set_process_info_request, (dump_func)dump_set_process_info_request,
(dump_func)dump_get_thread_info_request, (dump_func)dump_get_thread_info_request,
@ -4751,6 +4762,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_terminate_process_reply, (dump_func)dump_terminate_process_reply,
(dump_func)dump_terminate_thread_reply, (dump_func)dump_terminate_thread_reply,
(dump_func)dump_get_process_info_reply, (dump_func)dump_get_process_info_reply,
(dump_func)dump_get_process_debug_info_reply,
(dump_func)dump_get_process_vm_counters_reply, (dump_func)dump_get_process_vm_counters_reply,
NULL, NULL,
(dump_func)dump_get_thread_info_reply, (dump_func)dump_get_thread_info_reply,
@ -5031,6 +5043,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"terminate_process", "terminate_process",
"terminate_thread", "terminate_thread",
"get_process_info", "get_process_info",
"get_process_debug_info",
"get_process_vm_counters", "get_process_vm_counters",
"set_process_info", "set_process_info",
"get_thread_info", "get_thread_info",
@ -5408,6 +5421,7 @@ static const struct
{ "PIPE_EMPTY", STATUS_PIPE_EMPTY }, { "PIPE_EMPTY", STATUS_PIPE_EMPTY },
{ "PIPE_LISTENING", STATUS_PIPE_LISTENING }, { "PIPE_LISTENING", STATUS_PIPE_LISTENING },
{ "PIPE_NOT_AVAILABLE", STATUS_PIPE_NOT_AVAILABLE }, { "PIPE_NOT_AVAILABLE", STATUS_PIPE_NOT_AVAILABLE },
{ "PORT_NOT_SET", STATUS_PORT_NOT_SET },
{ "PRIVILEGE_NOT_HELD", STATUS_PRIVILEGE_NOT_HELD }, { "PRIVILEGE_NOT_HELD", STATUS_PRIVILEGE_NOT_HELD },
{ "PROCESS_IN_JOB", STATUS_PROCESS_IN_JOB }, { "PROCESS_IN_JOB", STATUS_PROCESS_IN_JOB },
{ "PROCESS_IS_TERMINATING", STATUS_PROCESS_IS_TERMINATING }, { "PROCESS_IS_TERMINATING", STATUS_PROCESS_IS_TERMINATING },