ntdll: Implement NtSetInformationDebugObject().
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
46b84e7a83
commit
7bebf7db8c
|
@ -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 ));
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -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 ### */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue