ntdll: Support the NtCreateDebugObject() flags.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-01-29 12:26:17 +01:00
parent a24e330b20
commit 964772bc8e
9 changed files with 98 additions and 13 deletions

View File

@ -21,6 +21,8 @@
#include <stdio.h>
#include <assert.h>
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#include <winreg.h>
@ -43,6 +45,10 @@ 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 *pDbgUiConnectToDbg)(void);
static HANDLE (WINAPI *pDbgUiGetThreadDebugObject)(void);
static void (WINAPI *pDbgUiSetThreadDebugObject)(HANDLE);
static LONG child_failures;
@ -1699,6 +1705,69 @@ static void test_debugger(const char *argv0)
ok(ret, "CloseHandle failed, last error %d.\n", GetLastError());
}
static DWORD run_child_wait( char *cmd, HANDLE event )
{
PROCESS_INFORMATION pi;
STARTUPINFOA si = { sizeof(si) };
BOOL ret;
DWORD exit_code;
ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
Sleep(200);
CloseHandle( pDbgUiGetThreadDebugObject() );
pDbgUiSetThreadDebugObject( 0 );
SetEvent( event );
WaitForSingleObject( pi.hProcess, 1000 );
ret = GetExitCodeProcess( pi.hProcess, &exit_code );
ok( ret, "GetExitCodeProcess failed err=%d\n", GetLastError());
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return exit_code;
}
static void test_kill_on_exit(const char *argv0)
{
static const char arguments[] = " debugger wait ";
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE };
OBJECT_ATTRIBUTES attr = { sizeof(attr) };
NTSTATUS status;
HANDLE event, debug;
DWORD exit_code;
char *cmd;
event = CreateEventW(&sa, FALSE, FALSE, NULL);
ok(event != NULL, "CreateEvent failed: %u\n", GetLastError());
cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16);
sprintf(cmd, "%s%s%x\n", argv0, arguments, (DWORD)(DWORD_PTR)event);
status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 );
ok( !status, "NtCreateDebugObject failed %x\n", status );
pDbgUiSetThreadDebugObject( debug );
exit_code = run_child_wait( cmd, event );
todo_wine
ok( exit_code == 0, "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 );
exit_code = run_child_wait( cmd, event );
todo_wine
ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0xfffe );
ok( status == STATUS_INVALID_PARAMETER, "NtCreateDebugObject failed %x\n", status );
status = pDbgUiConnectToDbg();
ok( !status, "DbgUiConnectToDbg failed %x\n", status );
exit_code = run_child_wait( cmd, event );
todo_wine
ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08x\n", exit_code);
heap_free(cmd);
}
START_TEST(debugger)
{
HMODULE hdll;
@ -1710,6 +1779,10 @@ START_TEST(debugger)
pDbgBreakPoint = (void*)GetProcAddress(ntdll, "DbgBreakPoint");
pNtSuspendProcess = (void*)GetProcAddress(ntdll, "NtSuspendProcess");
pNtResumeProcess = (void*)GetProcAddress(ntdll, "NtResumeProcess");
pNtCreateDebugObject = (void*)GetProcAddress(ntdll, "NtCreateDebugObject");
pDbgUiConnectToDbg = (void*)GetProcAddress(ntdll, "DbgUiConnectToDbg");
pDbgUiGetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiGetThreadDebugObject");
pDbgUiSetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiSetThreadDebugObject");
myARGC=winetest_get_mainargs(&myARGV);
if (myARGC >= 3 && strcmp(myARGV[2], "crash") == 0)
@ -1746,5 +1819,6 @@ START_TEST(debugger)
test_debug_children(myARGV[0], 0, FALSE, TRUE);
test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, TRUE);
test_debugger(myARGV[0]);
test_kill_on_exit(myARGV[0]);
}
}

View File

@ -145,7 +145,7 @@ NTSTATUS WINAPI DbgUiConnectToDbg(void)
if (DbgUiGetThreadDebugObject()) return STATUS_SUCCESS; /* already connected */
status = NtCreateDebugObject( &handle, DEBUG_ALL_ACCESS, &attr, 0 );
status = NtCreateDebugObject( &handle, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE );
if (!status) DbgUiSetThreadDebugObject( handle );
return status;
}

View File

@ -916,11 +916,14 @@ NTSTATUS WINAPI NtCreateDebugObject( HANDLE *handle, ACCESS_MASK access,
data_size_t len;
struct object_attributes *objattr;
if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER;
if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
SERVER_START_REQ( create_debug_obj )
{
req->access = access;
req->flags = flags;
wine_server_add_data( req, objattr, len );
ret = wine_server_call( req );
*handle = wine_server_ptr_handle( reply->handle );

View File

@ -2012,7 +2012,9 @@ struct create_debug_obj_request
{
struct request_header __header;
unsigned int access;
unsigned int flags;
/* VARARG(objattr,object_attributes); */
char __pad_20[4];
};
struct create_debug_obj_reply
{
@ -6207,7 +6209,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 656
#define SERVER_PROTOCOL_VERSION 657
/* ### protocol_version end ### */

View File

@ -3013,6 +3013,8 @@ typedef struct _PS_CREATE_INFO
#define DEBUG_QUERY_INFORMATION 0x0008
#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x0f)
#define DEBUG_KILL_ON_CLOSE 0x1
/***********************************************************************
* Function declarations
*/

View File

@ -57,7 +57,7 @@ struct debug_obj
{
struct object obj; /* object header */
struct list event_queue; /* pending events queue */
int kill_on_exit;/* kill debuggees on debugger exit ? */
unsigned int flags; /* debug flags */
};
@ -347,7 +347,8 @@ static void debug_obj_destroy( struct object *obj )
struct debug_obj *debug_obj = (struct debug_obj *)obj;
assert( obj->ops == &debug_obj_ops );
detach_debugged_processes( debug_obj, debug_obj->kill_on_exit ? STATUS_DEBUGGER_INACTIVE : 0 );
detach_debugged_processes( debug_obj,
(debug_obj->flags & DEBUG_KILL_ON_CLOSE) ? STATUS_DEBUGGER_INACTIVE : 0 );
/* free all pending events */
while ((ptr = list_head( &debug_obj->event_queue )))
@ -355,7 +356,8 @@ static void debug_obj_destroy( struct object *obj )
}
static struct debug_obj *create_debug_obj( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd )
unsigned int attr, unsigned int flags,
const struct security_descriptor *sd )
{
struct debug_obj *debug_obj;
@ -363,7 +365,7 @@ static struct debug_obj *create_debug_obj( struct object *root, const struct uni
{
if (get_error() != STATUS_OBJECT_NAME_EXISTS)
{
debug_obj->kill_on_exit = 1;
debug_obj->flags = flags;
list_init( &debug_obj->event_queue );
}
}
@ -586,9 +588,7 @@ int set_process_debugger( struct process *process, struct thread *debugger )
if (!debugger->debug_obj) /* need to allocate a context */
{
if (!(debug_obj = alloc_object( &debug_obj_ops ))) return 0;
debug_obj->kill_on_exit = 1;
list_init( &debug_obj->event_queue );
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;
@ -602,7 +602,8 @@ void debug_exit_thread( struct thread *thread )
if (debug_obj) /* this thread is a debugger */
{
detach_debugged_processes( debug_obj, debug_obj->kill_on_exit ? STATUS_DEBUGGER_INACTIVE : 0 );
detach_debugged_processes( debug_obj,
(debug_obj->flags & DEBUG_KILL_ON_CLOSE) ? STATUS_DEBUGGER_INACTIVE : 0 );
release_object( thread->debug_obj );
thread->debug_obj = NULL;
}
@ -618,7 +619,7 @@ DECL_HANDLER(create_debug_obj)
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
if (!objattr) return;
if ((debug_obj = create_debug_obj( root, &name, objattr->attributes, sd )))
if ((debug_obj = create_debug_obj( root, &name, objattr->attributes, req->flags, sd )))
{
if (get_error() == STATUS_OBJECT_NAME_EXISTS)
reply->handle = alloc_handle( current->process, debug_obj, req->access, objattr->attributes );
@ -769,5 +770,5 @@ DECL_HANDLER(set_debugger_kill_on_exit)
set_error( STATUS_ACCESS_DENIED );
return;
}
current->debug_obj->kill_on_exit = req->kill_on_exit;
current->debug_obj->flags = req->kill_on_exit ? DEBUG_KILL_ON_CLOSE : 0;
}

View File

@ -1590,6 +1590,7 @@ struct process_info
/* Create a debug object */
@REQ(create_debug_obj)
unsigned int access; /* wanted access rights */
unsigned int flags; /* object flags */
VARARG(objattr,object_attributes); /* object attributes */
@REPLY
obj_handle_t handle; /* handle to the debug object */

View File

@ -1133,7 +1133,8 @@ C_ASSERT( FIELD_OFFSET(struct list_processes_reply, info_size) == 8 );
C_ASSERT( FIELD_OFFSET(struct list_processes_reply, process_count) == 12 );
C_ASSERT( sizeof(struct list_processes_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct create_debug_obj_request, access) == 12 );
C_ASSERT( sizeof(struct create_debug_obj_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct create_debug_obj_request, flags) == 16 );
C_ASSERT( sizeof(struct create_debug_obj_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct create_debug_obj_reply, handle) == 8 );
C_ASSERT( sizeof(struct create_debug_obj_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_request, get_handle) == 12 );

View File

@ -2153,6 +2153,7 @@ static void dump_list_processes_reply( const struct list_processes_reply *req )
static void dump_create_debug_obj_request( const struct create_debug_obj_request *req )
{
fprintf( stderr, " access=%08x", req->access );
fprintf( stderr, ", flags=%08x", req->flags );
dump_varargs_object_attributes( ", objattr=", cur_size );
}