diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index b9b81ca3e76..eff3f589d9c 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -141,7 +141,6 @@ NTSTATUS WINAPI NtQueryInformationProcess( UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation); UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled); UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination); - UNIMPLEMENTED_INFO_CLASS(ProcessDebugFlags); UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing); case ProcessBasicInformation: @@ -314,6 +313,30 @@ NTSTATUS WINAPI NtQueryInformationProcess( else ret = STATUS_INFO_LENGTH_MISMATCH; break; + case ProcessDebugFlags: + len = sizeof(DWORD); + if (ProcessInformationLength == len) + { + if (!ProcessInformation) + ret = STATUS_ACCESS_VIOLATION; + else if (!ProcessHandle) + ret = STATUS_INVALID_HANDLE; + else + { + SERVER_START_REQ(get_process_info) + { + req->handle = wine_server_obj_handle( ProcessHandle ); + if ((ret = wine_server_call( req )) == STATUS_SUCCESS) + { + *(DWORD *)ProcessInformation = !reply->debugger_present; + } + } + SERVER_END_REQ; + } + } + else + ret = STATUS_INFO_LENGTH_MISMATCH; + break; case ProcessDefaultHardErrorMode: len = sizeof(process_error_mode); if (ProcessInformationLength == len) diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 774e8a18a17..2d5c94f3c63 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -1028,6 +1028,78 @@ static void test_query_process_debug_object_handle(int argc, char **argv) ok(ret, "CloseHandle failed with last error %u\n", GetLastError()); } +static void test_query_process_debug_flags(int argc, char **argv) +{ + DWORD debug_flags = 0xdeadbeef; + char cmdline[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFO si = { 0 }; + NTSTATUS status; + BOOL ret; + + sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee"); + + si.cb = sizeof(si); + ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); + if (!ret) return; + + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, + NULL, 0, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status); + + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, + NULL, sizeof(debug_flags), NULL); + ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION || broken(status == STATUS_INVALID_INFO_CLASS) /* W7PROX64 (32-bit) */, + "Expected STATUS_INVALID_HANDLE, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + NULL, sizeof(debug_flags), NULL); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + &debug_flags, sizeof(debug_flags) - 1, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + &debug_flags, sizeof(debug_flags) + 1, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == TRUE|| broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected flag TRUE, got %x.\n", debug_flags); + + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == FALSE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected flag FALSE, got %x.\n", debug_flags); + + for (;;) + { + DEBUG_EVENT ev; + + ret = WaitForDebugEvent(&ev, INFINITE); + ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); + if (!ret) break; + + if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + + ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); + if (!ret) break; + } + + ret = CloseHandle(pi.hThread); + ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); + ret = CloseHandle(pi.hProcess); + ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); +} + static void test_readvirtualmemory(void) { HANDLE process; @@ -1411,6 +1483,10 @@ START_TEST(info) trace("Starting test_query_process_debug_object_handle()\n"); test_query_process_debug_object_handle(argc, argv); + /* 0x1F ProcessDebugFlags */ + trace("Starting test_process_debug_flags()\n"); + test_query_process_debug_flags(argc, argv); + /* belongs into it's own file */ trace("Starting test_readvirtualmemory()\n"); test_readvirtualmemory();