Esempio n. 1
0
        public unsafe static DnDebugger CreateDnDebugger(DebugProcessOptions options, CoreCLRTypeDebugInfo info, Func <bool> keepWaiting, Func <ICorDebug, string, uint, string, DnDebugger> createDnDebugger)
        {
            var dbgShimState = GetOrCreateDbgShimState(info.HostFilename, info.DbgShimFilename);

            if (dbgShimState == null)
            {
                throw new Exception(string.Format("Could not load dbgshim.dll: '{0}' . Make sure you use the {1}-bit version", info.DbgShimFilename, IntPtr.Size * 8));
            }

            var    startupEvent = IntPtr.Zero;
            var    hThread = IntPtr.Zero;
            IntPtr pHandleArray = IntPtr.Zero, pStringArray = IntPtr.Zero;
            uint   dwArrayLength = 0;

            var  pi = new PROCESS_INFORMATION();
            bool error = true, calledSetEvent = false;

            try {
                var dwCreationFlags = options.ProcessCreationFlags ?? DebugProcessOptions.DefaultProcessCreationFlags;
                dwCreationFlags |= ProcessCreationFlags.CREATE_SUSPENDED;
                var si = new STARTUPINFO();
                si.cb = (uint)(4 * 1 + IntPtr.Size * 3 + 4 * 8 + 2 * 2 + IntPtr.Size * 4);
                var cmdline = "\"" + info.HostFilename + "\" " + info.HostCommandLine + " \"" + options.Filename + "\"" + (string.IsNullOrEmpty(options.CommandLine) ? string.Empty : " " + options.CommandLine);
                var env     = Win32EnvironmentStringBuilder.CreateEnvironmentUnicodeString(options.Environment);
                dwCreationFlags |= ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT;
                bool b = NativeMethods.CreateProcess(info.HostFilename ?? string.Empty, cmdline, IntPtr.Zero, IntPtr.Zero,
                                                     options.InheritHandles, dwCreationFlags, env, options.CurrentDirectory,
                                                     ref si, out pi);
                hThread = pi.hThread;
                if (!b)
                {
                    throw new Exception(string.Format("Could not execute '{0}'", options.Filename));
                }

                int hr = dbgShimState.GetStartupNotificationEvent(pi.dwProcessId, out startupEvent);
                if (hr < 0)
                {
                    throw new Exception(string.Format("GetStartupNotificationEvent failed: 0x{0:X8}", hr));
                }

                NativeMethods.ResumeThread(hThread);

                const uint WAIT_MS = 5000;
                for (;;)
                {
                    uint res = NativeMethods.WaitForSingleObject(startupEvent, WAIT_MS);
                    if (res == 0)
                    {
                        break;
                    }

                    if (res == NativeMethods.WAIT_FAILED)
                    {
                        throw new Exception(string.Format("Error waiting for startup event: 0x{0:X8}", Marshal.GetLastWin32Error()));
                    }
                    if (res == NativeMethods.WAIT_TIMEOUT)
                    {
                        if (keepWaiting())
                        {
                            continue;
                        }
                        throw new TimeoutException("Waiting for CoreCLR timed out. Debug 32-bit .NET Core apps with 32-bit dnSpy (dnSpy-x86.exe), and 64-bit .NET Core apps with 64-bit dnSpy (dnSpy.exe).");
                    }
                    Debug.Fail(string.Format("Unknown result from WaitForMultipleObjects: 0x{0:X8}", res));
                    throw new Exception("Error waiting for startup event");
                }

                hr = dbgShimState.EnumerateCLRs(pi.dwProcessId, out pHandleArray, out pStringArray, out dwArrayLength);
                if (hr < 0 || dwArrayLength == 0)
                {
                    throw new Exception("Process started but no CoreCLR found");
                }
                var       psa     = (IntPtr *)pStringArray;
                var       pha     = (IntPtr *)pHandleArray;
                const int index   = 0;
                var       version = GetVersionStringFromModule(dbgShimState, pi.dwProcessId, psa[index], out string coreclrFilename);
                hr = dbgShimState.CreateDebuggingInterfaceFromVersionEx(CorDebugInterfaceVersion.CorDebugVersion_4_0, version, out object obj);
                var corDebug = obj as ICorDebug;
                if (corDebug == null)
                {
                    throw new Exception(string.Format("Could not create a ICorDebug: hr=0x{0:X8}", hr));
                }
                var dbg = createDnDebugger(corDebug, coreclrFilename, pi.dwProcessId, version);
                for (uint i = 0; i < dwArrayLength; i++)
                {
                    NativeMethods.SetEvent(pha[i]);
                }
                calledSetEvent = true;
                error          = false;
                return(dbg);
            }
            finally {
                if (!calledSetEvent && pHandleArray != IntPtr.Zero && dwArrayLength != 0)
                {
                    var pha = (IntPtr *)pHandleArray;
                    for (uint i = 0; i < dwArrayLength; i++)
                    {
                        NativeMethods.SetEvent(pha[i]);
                    }
                }
                if (startupEvent != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(startupEvent);
                }
                if (hThread != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(hThread);
                }
                if (pHandleArray != IntPtr.Zero)
                {
                    dbgShimState.CloseCLREnumeration(pHandleArray, pStringArray, dwArrayLength);
                }
                if (error)
                {
                    NativeMethods.TerminateProcess(pi.hProcess, uint.MaxValue);
                }
                if (pi.hProcess != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(pi.hProcess);
                }
            }
        }
Esempio n. 2
0
        public unsafe static DnDebugger CreateDnDebugger(DebugProcessOptions options, CoreCLRTypeDebugInfo info, IntPtr outputHandle, IntPtr errorHandle, Func <bool> keepWaiting, Func <ICorDebug, string, uint, string, DnDebugger> createDnDebugger)
        {
            var dbgShimState = GetOrCreateDbgShimState(info.HostFilename, info.DbgShimFilename);

            if (dbgShimState == null)
            {
                throw new Exception($"Could not load {dbgshimFilename}: '{info.DbgShimFilename}' . Make sure you use the {IntPtr.Size * 8}-bit version");
            }

            var    startupEvent = IntPtr.Zero;
            var    hThread = IntPtr.Zero;
            IntPtr pHandleArray = IntPtr.Zero, pStringArray = IntPtr.Zero;
            uint   dwArrayLength = 0;

            bool useHost = info.HostFilename != null;
            var  pi = new PROCESS_INFORMATION();
            bool error = true, calledSetEvent = false;

            try {
                bool inheritHandles  = options.InheritHandles;
                var  dwCreationFlags = options.ProcessCreationFlags ?? DebugProcessOptions.DefaultProcessCreationFlags;
                dwCreationFlags |= ProcessCreationFlags.CREATE_SUSPENDED;
                var si = new STARTUPINFO();
                si.hStdOutput = outputHandle;
                si.hStdError  = errorHandle;
                if (si.hStdOutput != IntPtr.Zero || si.hStdError != IntPtr.Zero)
                {
                    si.dwFlags    |= STARTUPINFO.STARTF_USESTDHANDLES;
                    inheritHandles = true;
                }
                si.cb = (uint)(4 * 1 + IntPtr.Size * 3 + 4 * 8 + 2 * 2 + IntPtr.Size * 4);
                string cmdline;
                if (useHost)
                {
                    cmdline = "\"" + info.HostFilename + "\" " + info.HostCommandLine + " \"" + options.Filename + "\"" + (string.IsNullOrEmpty(options.CommandLine) ? string.Empty : " " + options.CommandLine);
                }
                else
                {
                    cmdline = "\"" + options.Filename + "\"" + (string.IsNullOrEmpty(options.CommandLine) ? string.Empty : " " + options.CommandLine);
                }
                var env = Win32EnvironmentStringBuilder.CreateEnvironmentUnicodeString(options.Environment);
                dwCreationFlags |= ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT;
                var  appName = useHost ? info.HostFilename : options.Filename;
                bool b       = NativeMethods.CreateProcess(appName ?? string.Empty, cmdline, IntPtr.Zero, IntPtr.Zero,
                                                           inheritHandles, dwCreationFlags, env, options.CurrentDirectory,
                                                           ref si, out pi);
                hThread = pi.hThread;
                if (!b)
                {
                    throw new Exception($"Could not execute '{options.Filename}'");
                }

                int hr = dbgShimState.GetStartupNotificationEvent(pi.dwProcessId, out startupEvent);
                if (hr < 0)
                {
                    throw new Exception($"GetStartupNotificationEvent failed: 0x{hr:X8}");
                }

                NativeMethods.ResumeThread(hThread);

                const uint WAIT_MS = 5000;
                for (;;)
                {
                    uint res = NativeMethods.WaitForSingleObject(startupEvent, WAIT_MS);
                    if (res == 0)
                    {
                        break;
                    }

                    if (res == NativeMethods.WAIT_FAILED)
                    {
                        throw new Exception($"Error waiting for startup event: 0x{Marshal.GetLastWin32Error():X8}");
                    }
                    if (res == NativeMethods.WAIT_TIMEOUT)
                    {
                        if (keepWaiting())
                        {
                            continue;
                        }
                        throw new TimeoutException("Waiting for CoreCLR timed out. Debug 32-bit .NET Core apps with 32-bit dnSpy (dnSpy-x86.exe), and 64-bit .NET Core apps with 64-bit dnSpy (dnSpy.exe).");
                    }
                    Debug.Fail($"Unknown result from WaitForMultipleObjects: 0x{res:X8}");
                    throw new Exception("Error waiting for startup event");
                }

                hr = dbgShimState.EnumerateCLRs(pi.dwProcessId, out pHandleArray, out pStringArray, out dwArrayLength);
                if (hr < 0 || dwArrayLength == 0)
                {
                    // CoreCLR doesn't give us a good error code if we try to debug a .NET Core app
                    // with an incompatible bitness:
                    //		x86 tries to debug x64: hr == 0x8007012B (ERROR_PARTIAL_COPY)
                    //		x64 tries to debug x86: hr == 0x00000000 && dwArrayLength == 0x00000000
                    if (IntPtr.Size == 4 && (uint)hr == 0x8007012B)
                    {
                        throw new StartDebuggerException(StartDebuggerError.UnsupportedBitness);
                    }
                    if (IntPtr.Size == 8 && hr == 0 && dwArrayLength == 0)
                    {
                        throw new StartDebuggerException(StartDebuggerError.UnsupportedBitness);
                    }
                    throw new Exception("Process started but no CoreCLR found");
                }
                var       psa     = (IntPtr *)pStringArray;
                var       pha     = (IntPtr *)pHandleArray;
                const int index   = 0;
                var       version = GetVersionStringFromModule(dbgShimState, pi.dwProcessId, psa[index], out string coreclrFilename);
                hr = dbgShimState.CreateDebuggingInterfaceFromVersionEx(CorDebugInterfaceVersion.CorDebugVersion_4_0, version, out object obj);
                var corDebug = obj as ICorDebug;
                if (corDebug == null)
                {
                    throw new Exception($"Could not create a ICorDebug: hr=0x{hr:X8}");
                }
                var dbg = createDnDebugger(corDebug, coreclrFilename, pi.dwProcessId, version);
                for (uint i = 0; i < dwArrayLength; i++)
                {
                    NativeMethods.SetEvent(pha[i]);
                }
                calledSetEvent = true;
                error          = false;
                return(dbg);
            }
            finally {
                if (!calledSetEvent && pHandleArray != IntPtr.Zero && dwArrayLength != 0)
                {
                    var pha = (IntPtr *)pHandleArray;
                    for (uint i = 0; i < dwArrayLength; i++)
                    {
                        NativeMethods.SetEvent(pha[i]);
                    }
                }
                if (startupEvent != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(startupEvent);
                }
                if (hThread != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(hThread);
                }
                if (pHandleArray != IntPtr.Zero)
                {
                    dbgShimState.CloseCLREnumeration(pHandleArray, pStringArray, dwArrayLength);
                }
                if (error)
                {
                    NativeMethods.TerminateProcess(pi.hProcess, uint.MaxValue);
                }
                if (pi.hProcess != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(pi.hProcess);
                }
            }
        }