ntdll: Support the NtCreateDebugObject() flags.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a24e330b20
commit
964772bc8e
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ### */
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue