ntdll: Implement NtSetInformationDebugObject().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-02-01 11:10:06 +01:00
parent 46b84e7a83
commit 7bebf7db8c
11 changed files with 154 additions and 37 deletions

View File

@ -23,8 +23,10 @@
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/server.h"
#include "winternl.h"
#include "kernel_private.h"
#include "wine/asm.h"
#include "wine/debug.h"
@ -165,13 +167,9 @@ BOOL WINAPI DebugBreakProcess(HANDLE process)
*/
BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill)
{
BOOL ret = FALSE;
ULONG flag = kill ? DEBUG_KILL_ON_CLOSE : 0;
SERVER_START_REQ( set_debugger_kill_on_exit )
{
req->kill_on_exit = kill;
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
return ret;
return set_ntstatus( NtSetInformationDebugObject( DbgUiGetThreadDebugObject(),
DebugObjectKillProcessOnExitInformation,
&flag, sizeof(flag), NULL ));
}

View File

@ -46,6 +46,7 @@ static void (WINAPI *pDbgBreakPoint)(void);
static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process);
static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process);
static NTSTATUS (WINAPI *pNtCreateDebugObject)(HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG);
static NTSTATUS (WINAPI *pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,void *,ULONG,ULONG*);
static NTSTATUS (WINAPI *pDbgUiConnectToDbg)(void);
static HANDLE (WINAPI *pDbgUiGetThreadDebugObject)(void);
static void (WINAPI *pDbgUiSetThreadDebugObject)(HANDLE);
@ -1735,6 +1736,7 @@ static void test_kill_on_exit(const char *argv0)
HANDLE event, debug;
DWORD exit_code;
char *cmd;
ULONG val;
event = CreateEventW(&sa, FALSE, FALSE, NULL);
ok(event != NULL, "CreateEvent failed: %u\n", GetLastError());
@ -1757,6 +1759,26 @@ static void test_kill_on_exit(const char *argv0)
status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0xfffe );
ok( status == STATUS_INVALID_PARAMETER, "NtCreateDebugObject failed %x\n", status );
status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 );
ok( !status, "NtCreateDebugObject failed %x\n", status );
pDbgUiSetThreadDebugObject( debug );
val = DEBUG_KILL_ON_CLOSE;
status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
&val, sizeof(val), NULL );
ok( !status, "NtSetInformationDebugObject failed %x\n", status );
exit_code = run_child_wait( cmd, event );
ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
ok( !status, "NtCreateDebugObject failed %x\n", status );
pDbgUiSetThreadDebugObject( debug );
val = 0;
status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation,
&val, sizeof(val), NULL );
ok( !status, "NtSetInformationDebugObject failed %x\n", status );
exit_code = run_child_wait( cmd, event );
ok( exit_code == 0, "exit code = %08x\n", exit_code);
status = pDbgUiConnectToDbg();
ok( !status, "DbgUiConnectToDbg failed %x\n", status );
exit_code = run_child_wait( cmd, event );
@ -1777,6 +1799,7 @@ START_TEST(debugger)
pNtSuspendProcess = (void*)GetProcAddress(ntdll, "NtSuspendProcess");
pNtResumeProcess = (void*)GetProcAddress(ntdll, "NtResumeProcess");
pNtCreateDebugObject = (void*)GetProcAddress(ntdll, "NtCreateDebugObject");
pNtSetInformationDebugObject = (void*)GetProcAddress(ntdll, "NtSetInformationDebugObject");
pDbgUiConnectToDbg = (void*)GetProcAddress(ntdll, "DbgUiConnectToDbg");
pDbgUiGetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiGetThreadDebugObject");
pDbgUiSetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiSetThreadDebugObject");

View File

@ -373,7 +373,7 @@
@ stub NtSetHighEventPair
@ stub NtSetHighWaitLowEventPair
@ stub NtSetHighWaitLowThread
# @ stub NtSetInformationDebugObject
@ stdcall -syscall NtSetInformationDebugObject(long long ptr long ptr)
@ stdcall -syscall NtSetInformationFile(long ptr ptr long long)
@ stdcall -syscall NtSetInformationJobObject(long long ptr long)
@ stdcall -syscall NtSetInformationKey(long long ptr long)
@ -1378,7 +1378,7 @@
@ stub ZwSetHighEventPair
@ stub ZwSetHighWaitLowEventPair
@ stub ZwSetHighWaitLowThread
# @ stub ZwSetInformationDebugObject
@ stdcall -private -syscall ZwSetInformationDebugObject(long long ptr long ptr) NtSetInformationDebugObject
@ stdcall -private -syscall ZwSetInformationFile(long ptr ptr long long) NtSetInformationFile
@ stdcall -private -syscall ZwSetInformationJobObject(long long ptr long) NtSetInformationJobObject
@ stdcall -private -syscall ZwSetInformationKey(long long ptr long) NtSetInformationKey

View File

@ -43,6 +43,8 @@ static BOOL (WINAPI * pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_R
static DEP_SYSTEM_POLICY_TYPE (WINAPI * pGetSystemDEPPolicy)(void);
static NTSTATUS (WINAPI * pNtOpenThread)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const CLIENT_ID *);
static NTSTATUS (WINAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, void *, ULONG, ULONG *);
static NTSTATUS (WINAPI * pNtCreateDebugObject)( HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG );
static NTSTATUS (WINAPI * pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,PVOID,ULONG,ULONG*);
static BOOL is_wow64;
@ -92,6 +94,8 @@ static BOOL InitFunctionPtrs(void)
NTDLL_GET_PROC(NtUnmapViewOfSection);
NTDLL_GET_PROC(NtOpenThread);
NTDLL_GET_PROC(NtQueryObject);
NTDLL_GET_PROC(NtCreateDebugObject);
NTDLL_GET_PROC(NtSetInformationDebugObject);
/* not present before XP */
pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll, "NtGetCurrentProcessorNumber");
@ -2749,6 +2753,56 @@ static void test_wow64(void)
ok( !NtCurrentTeb()->WowTebOffset, "WowTebOffset set to %x\n", NtCurrentTeb()->WowTebOffset );
}
static void test_debug_object(void)
{
NTSTATUS status;
HANDLE handle;
OBJECT_ATTRIBUTES attr = { sizeof(attr) };
ULONG len, flag = 0;
status = pNtCreateDebugObject( &handle, DEBUG_ALL_ACCESS, &attr, 0 );
ok( !status, "NtCreateDebugObject failed %x\n", status );
status = pNtSetInformationDebugObject( handle, 0, &flag, sizeof(ULONG), &len );
ok( status == STATUS_INVALID_PARAMETER, "NtSetInformationDebugObject failed %x\n", status );
status = pNtSetInformationDebugObject( handle, 2, &flag, sizeof(ULONG), &len );
ok( status == STATUS_INVALID_PARAMETER, "NtSetInformationDebugObject failed %x\n", status );
status = pNtSetInformationDebugObject( (HANDLE)0xdead, DebugObjectKillProcessOnExitInformation,
&flag, sizeof(ULONG), &len );
ok( status == STATUS_INVALID_HANDLE, "NtSetInformationDebugObject failed %x\n", status );
len = 0xdead;
status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation,
&flag, sizeof(ULONG) + 1, &len );
ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtSetInformationDebugObject failed %x\n", status );
ok( len == sizeof(ULONG), "wrong len %u\n", len );
len = 0xdead;
status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation,
&flag, sizeof(ULONG) - 1, &len );
ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtSetInformationDebugObject failed %x\n", status );
ok( len == sizeof(ULONG), "wrong len %u\n", len );
len = 0xdead;
status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation,
&flag, sizeof(ULONG), &len );
ok( !status, "NtSetInformationDebugObject failed %x\n", status );
ok( !len, "wrong len %u\n", len );
flag = DEBUG_KILL_ON_CLOSE;
status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation,
&flag, sizeof(ULONG), &len );
ok( !status, "NtSetInformationDebugObject failed %x\n", status );
ok( !len, "wrong len %u\n", len );
for (flag = 2; flag; flag <<= 1)
{
status = pNtSetInformationDebugObject( handle, DebugObjectKillProcessOnExitInformation,
&flag, sizeof(ULONG), &len );
ok( status == STATUS_INVALID_PARAMETER, "NtSetInformationDebugObject failed %x\n", status );
}
pNtClose( handle );
}
START_TEST(info)
{
@ -2808,6 +2862,7 @@ START_TEST(info)
test_affinity();
test_wow64();
test_debug_object();
/* belongs to its own file */
test_readvirtualmemory();

View File

@ -934,6 +934,36 @@ NTSTATUS WINAPI NtCreateDebugObject( HANDLE *handle, ACCESS_MASK access,
}
/**********************************************************************
* NtSetInformationDebugObject (NTDLL.@)
*/
NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS class,
void *info, ULONG len, ULONG *ret_len )
{
NTSTATUS ret;
ULONG flags;
if (class != DebugObjectKillProcessOnExitInformation) return STATUS_INVALID_PARAMETER;
if (len != sizeof(ULONG))
{
if (ret_len) *ret_len = sizeof(ULONG);
return STATUS_INFO_LENGTH_MISMATCH;
}
flags = *(ULONG *)info;
if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER;
SERVER_START_REQ( set_debug_obj_info )
{
req->debug = wine_server_obj_handle( handle );
req->flags = flags;
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (!ret && ret_len) *ret_len = 0;
return ret;
}
/**************************************************************************
* NtCreateDirectoryObject (NTDLL.@)
*/

View File

@ -2105,12 +2105,14 @@ struct debug_process_reply
struct set_debugger_kill_on_exit_request
struct set_debug_obj_info_request
{
struct request_header __header;
int kill_on_exit;
obj_handle_t debug;
unsigned int flags;
char __pad_20[4];
};
struct set_debugger_kill_on_exit_reply
struct set_debug_obj_info_reply
{
struct reply_header __header;
};
@ -5447,7 +5449,7 @@ enum request
REQ_get_exception_status,
REQ_continue_debug_event,
REQ_debug_process,
REQ_set_debugger_kill_on_exit,
REQ_set_debug_obj_info,
REQ_read_process_memory,
REQ_write_process_memory,
REQ_create_key,
@ -5729,7 +5731,7 @@ union generic_request
struct get_exception_status_request get_exception_status_request;
struct continue_debug_event_request continue_debug_event_request;
struct debug_process_request debug_process_request;
struct set_debugger_kill_on_exit_request set_debugger_kill_on_exit_request;
struct set_debug_obj_info_request set_debug_obj_info_request;
struct read_process_memory_request read_process_memory_request;
struct write_process_memory_request write_process_memory_request;
struct create_key_request create_key_request;
@ -6009,7 +6011,7 @@ union generic_reply
struct get_exception_status_reply get_exception_status_reply;
struct continue_debug_event_reply continue_debug_event_reply;
struct debug_process_reply debug_process_reply;
struct set_debugger_kill_on_exit_reply set_debugger_kill_on_exit_reply;
struct set_debug_obj_info_reply set_debug_obj_info_reply;
struct read_process_memory_reply read_process_memory_reply;
struct write_process_memory_reply write_process_memory_reply;
struct create_key_reply create_key_reply;
@ -6211,7 +6213,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 659
#define SERVER_PROTOCOL_VERSION 660
/* ### protocol_version end ### */

View File

@ -3015,6 +3015,12 @@ typedef struct _PS_CREATE_INFO
#define DEBUG_KILL_ON_CLOSE 0x1
typedef enum _DEBUGOBJECTINFOCLASS
{
DebugObjectKillProcessOnExitInformation = 1,
MaxDebugObjectInfoClass
} DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS;
/***********************************************************************
* Function declarations
*/
@ -3256,6 +3262,7 @@ NTSYSAPI NTSTATUS WINAPI NtSetEvent(HANDLE,LONG*);
NTSYSAPI NTSTATUS WINAPI NtSetHighEventPair(HANDLE);
NTSYSAPI NTSTATUS WINAPI NtSetHighWaitLowEventPair(HANDLE);
NTSYSAPI NTSTATUS WINAPI NtSetHighWaitLowThread(VOID);
NTSYSAPI NTSTATUS WINAPI NtSetInformationDebugObject(HANDLE,DEBUGOBJECTINFOCLASS,PVOID,ULONG,ULONG*);
NTSYSAPI NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
NTSYSAPI NTSTATUS WINAPI NtSetInformationJobObject(HANDLE,JOBOBJECTINFOCLASS,PVOID,ULONG);
NTSYSAPI NTSTATUS WINAPI NtSetInformationKey(HANDLE,const int,PVOID,ULONG);

View File

@ -747,13 +747,12 @@ DECL_HANDLER(get_exception_status)
}
}
/* set debugger kill on exit flag */
DECL_HANDLER(set_debugger_kill_on_exit)
/* set debug object information */
DECL_HANDLER(set_debug_obj_info)
{
if (!current->debug_obj)
{
set_error( STATUS_ACCESS_DENIED );
return;
}
current->debug_obj->flags = req->kill_on_exit ? DEBUG_KILL_ON_CLOSE : 0;
struct debug_obj *debug_obj;
if (!(debug_obj = get_debug_obj( current->process, req->debug, DEBUG_SET_INFORMATION ))) return;
debug_obj->flags = req->flags;
release_object( debug_obj );
}

View File

@ -1645,9 +1645,10 @@ struct process_info
@END
/* Set debugger kill on exit flag */
@REQ(set_debugger_kill_on_exit)
int kill_on_exit; /* 0=detach/1=kill debuggee when debugger dies */
/* Set debug object information */
@REQ(set_debug_obj_info)
obj_handle_t debug; /* debug object */
unsigned int flags; /* object flags */
@END

View File

@ -196,7 +196,7 @@ DECL_HANDLER(queue_exception_event);
DECL_HANDLER(get_exception_status);
DECL_HANDLER(continue_debug_event);
DECL_HANDLER(debug_process);
DECL_HANDLER(set_debugger_kill_on_exit);
DECL_HANDLER(set_debug_obj_info);
DECL_HANDLER(read_process_memory);
DECL_HANDLER(write_process_memory);
DECL_HANDLER(create_key);
@ -477,7 +477,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_get_exception_status,
(req_handler)req_continue_debug_event,
(req_handler)req_debug_process,
(req_handler)req_set_debugger_kill_on_exit,
(req_handler)req_set_debug_obj_info,
(req_handler)req_read_process_memory,
(req_handler)req_write_process_memory,
(req_handler)req_create_key,
@ -1163,8 +1163,9 @@ 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 );
C_ASSERT( FIELD_OFFSET(struct set_debug_obj_info_request, debug) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_debug_obj_info_request, flags) == 16 );
C_ASSERT( sizeof(struct set_debug_obj_info_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, addr) == 16 );
C_ASSERT( sizeof(struct read_process_memory_request) == 24 );

View File

@ -2211,9 +2211,10 @@ static void dump_debug_process_request( const struct debug_process_request *req
fprintf( stderr, ", attach=%d", req->attach );
}
static void dump_set_debugger_kill_on_exit_request( const struct set_debugger_kill_on_exit_request *req )
static void dump_set_debug_obj_info_request( const struct set_debug_obj_info_request *req )
{
fprintf( stderr, " kill_on_exit=%d", req->kill_on_exit );
fprintf( stderr, " debug=%04x", req->debug );
fprintf( stderr, ", flags=%08x", req->flags );
}
static void dump_read_process_memory_request( const struct read_process_memory_request *req )
@ -4475,7 +4476,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_exception_status_request,
(dump_func)dump_continue_debug_event_request,
(dump_func)dump_debug_process_request,
(dump_func)dump_set_debugger_kill_on_exit_request,
(dump_func)dump_set_debug_obj_info_request,
(dump_func)dump_read_process_memory_request,
(dump_func)dump_write_process_memory_request,
(dump_func)dump_create_key_request,
@ -5031,7 +5032,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"get_exception_status",
"continue_debug_event",
"debug_process",
"set_debugger_kill_on_exit",
"set_debug_obj_info",
"read_process_memory",
"write_process_memory",
"create_key",