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;
status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugObjectHandle,
&debug_object, sizeof(debug_object), NULL);
todo_wine
ok(status == STATUS_SUCCESS,
"Expected NtQueryInformationProcess to return STATUS_SUCCESS, got 0x%08x\n", status);
todo_wine
ok(debug_object != NULL,
"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 (;;)
{

View File

@ -1366,15 +1366,25 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
if (!info) ret = STATUS_ACCESS_VIOLATION;
else
{
SERVER_START_REQ(get_process_info)
HANDLE debug;
SERVER_START_REQ(get_process_debug_info)
{
req->handle = wine_server_obj_handle( handle );
if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
{
*(DWORD_PTR *)info = reply->debugger_present ? ~(DWORD_PTR)0 : 0;
}
ret = wine_server_call( req );
debug = wine_server_ptr_handle( reply->debug );
}
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;
@ -1387,15 +1397,18 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
if (!info) ret = STATUS_ACCESS_VIOLATION;
else
{
SERVER_START_REQ(get_process_info)
HANDLE debug;
SERVER_START_REQ(get_process_debug_info)
{
req->handle = wine_server_obj_handle( handle );
if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
{
*(DWORD *)info = reply->debug_children;
}
ret = wine_server_call( req );
debug = wine_server_ptr_handle( reply->debug );
*(DWORD *)info = reply->debug_children;
}
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;
@ -1408,17 +1421,19 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
break;
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);
if (size == len)
{
if (!info) ret = STATUS_ACCESS_VIOLATION;
else if (!handle) ret = STATUS_INVALID_HANDLE;
else
{
memset(info, 0, size);
ret = STATUS_PORT_NOT_SET;
SERVER_START_REQ(get_process_debug_info)
{
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;

View File

@ -1008,8 +1008,22 @@ struct get_process_info_reply
int exit_code;
int priority;
client_cpu_t cpu;
short int debugger_present;
short int debug_children;
/* VARARG(image,pe_image_info); */
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); */
};
@ -5427,6 +5441,7 @@ enum request
REQ_terminate_process,
REQ_terminate_thread,
REQ_get_process_info,
REQ_get_process_debug_info,
REQ_get_process_vm_counters,
REQ_set_process_info,
REQ_get_thread_info,
@ -5711,6 +5726,7 @@ union generic_request
struct terminate_process_request terminate_process_request;
struct terminate_thread_request terminate_thread_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 set_process_info_request set_process_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_thread_reply terminate_thread_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 set_process_info_reply set_process_info_reply;
struct get_thread_info_reply get_thread_info_reply;
@ -6263,7 +6280,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 668
#define SERVER_PROTOCOL_VERSION 669
/* ### protocol_version end ### */

View File

@ -1422,8 +1422,6 @@ DECL_HANDLER(get_process_info)
reply->start_time = process->start_time;
reply->end_time = process->end_time;
reply->cpu = process->cpu;
reply->debugger_present = !!process->debug_obj;
reply->debug_children = process->debug_children;
if (get_reply_max_size())
{
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 */
DECL_HANDLER(get_process_vm_counters)
{

View File

@ -955,8 +955,16 @@ typedef struct
int exit_code; /* process exit code */
int priority; /* priority class */
client_cpu_t cpu; /* CPU that this process is running on */
short int debugger_present; /* process is being debugged */
short int debug_children; /* inherit debugger to child processes */
VARARG(image,pe_image_info); /* image info for main exe */
@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 */
@END

View File

@ -130,6 +130,7 @@ DECL_HANDLER(init_thread);
DECL_HANDLER(terminate_process);
DECL_HANDLER(terminate_thread);
DECL_HANDLER(get_process_info);
DECL_HANDLER(get_process_debug_info);
DECL_HANDLER(get_process_vm_counters);
DECL_HANDLER(set_process_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_thread,
(req_handler)req_get_process_info,
(req_handler)req_get_process_debug_info,
(req_handler)req_get_process_vm_counters,
(req_handler)req_set_process_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, priority) == 52 );
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( 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( sizeof(struct get_process_vm_counters_request) == 16 );
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, ", priority=%d", req->priority );
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 );
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_thread_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_set_process_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_thread_reply,
(dump_func)dump_get_process_info_reply,
(dump_func)dump_get_process_debug_info_reply,
(dump_func)dump_get_process_vm_counters_reply,
NULL,
(dump_func)dump_get_thread_info_reply,
@ -5031,6 +5043,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"terminate_process",
"terminate_thread",
"get_process_info",
"get_process_debug_info",
"get_process_vm_counters",
"set_process_info",
"get_thread_info",
@ -5408,6 +5421,7 @@ static const struct
{ "PIPE_EMPTY", STATUS_PIPE_EMPTY },
{ "PIPE_LISTENING", STATUS_PIPE_LISTENING },
{ "PIPE_NOT_AVAILABLE", STATUS_PIPE_NOT_AVAILABLE },
{ "PORT_NOT_SET", STATUS_PORT_NOT_SET },
{ "PRIVILEGE_NOT_HELD", STATUS_PRIVILEGE_NOT_HELD },
{ "PROCESS_IN_JOB", STATUS_PROCESS_IN_JOB },
{ "PROCESS_IS_TERMINATING", STATUS_PROCESS_IS_TERMINATING },