예제 #1
0
        public DbgEngDataReader(int pid, bool invasive, uint msecTimeout)
        {
            IntPtr client = CreateIDebugClient();
            CreateClient(client);

            DebugAttach attach = invasive ? DebugAttach.Default : DebugAttach.NonInvasive;
            _control.AddEngineOptions(DebugControl.INITIAL_BREAK);

            int hr = _client.AttachProcess((uint)pid, attach);

            if (hr == 0)
                hr = _control.WaitForEvent(msecTimeout) ? 0 : -1;

            if (hr == 1)
            {
                throw new TimeoutException("Break in did not occur within the allotted timeout.");
            }

            if (hr != 0)
            {
                if ((uint)hr == 0xd00000bb)
                    throw new InvalidOperationException("Mismatched architecture between this process and the target process.");

                throw new ClrDiagnosticsException($"Could not attach to process {pid:X}, HRESULT: 0x{hr:x8}", ClrDiagnosticsExceptionKind.DebuggerError, hr);
            }
        }
예제 #2
0
        public HResult AttachProcess(uint pid, DebugAttach flags)
        {
            InitDelegate(ref _attachProcess, VTable.AttachProcess);
            HResult hr = _attachProcess(Self, 0, pid, flags);

            _sys.Init();
            return(hr);
        }
예제 #3
0
파일: LocalComponent.cs 프로젝트: krus/PTVS
        private static void InjectHelperDll(DkmProcess process)
        {
            var injectionData = process.GetDataItem <HelperDllInjectionDataHolder>();

            if (injectionData != null)
            {
                // Injection is already in progress.
                return;
            }

            injectionData = new HelperDllInjectionDataHolder();
            process.SetDataItem(DkmDataCreationDisposition.CreateNew, injectionData);

            var pyrtInfo = process.GetPythonRuntimeInfo();

            // Loading the helper is done via CreateRemoteThread(LoadLibrary), which is inherently asynchronous.
            // On the other hand, we will not handle breakpoints until it is loaded - they won't even be bound.
            // If any Python code is running in the meantime, this may cause us to skip breakpoints, which is
            // very surprising in the run (F5) scenario, as the user expects all preset breakpoints to be hit.
            // To fix that, we need block the Python interpreter loop until the helper is fully loaded.
            //
            // Pausing all threads is not a good way to do this, because one of the threads may be holding the
            // loader lock, which will prevent the helper from loading and result in a deadlock. So instead,
            // block at a known location at the beginning of PyInitialize_Ex, and only freeze the thread that
            // calls it - this is sufficient to prevent execution of Python code in run scenario before helper
            // is loaded.
            //
            // For attach-to-running-process scenario, we do nothing because the attach itself is inherently
            // asynchronous, and so there's no user expectation that breakpoints light up instantly.

            // If Python is already initialized, this is attach-to-running-process - don't block.
            var initialized = pyrtInfo.DLLs.Python.GetStaticVariable <Int32Proxy>(
                "initialized",
                GetPyInitializeObjectFile(pyrtInfo.LanguageVersion)
                );

            if (initialized.Read() == 0)
            {
                // When Py_InitializeEx is hit, suspend the thread.
                DkmRuntimeBreakpoint makePendingCallsBP = null;
                makePendingCallsBP = CreateRuntimeDllExportedFunctionBreakpoint(pyrtInfo.DLLs.Python, "Py_InitializeEx", (thread, frameBase, vFrame) => {
                    makePendingCallsBP.Close();
                    if (process.GetPythonRuntimeInstance() == null)
                    {
                        thread.Suspend(true);
                        injectionData.SuspendedThread = thread;
                    }
                });
                makePendingCallsBP.Enable();
            }

            // Inject the helper DLL; OnHelperDllInitialized will resume the thread once the DLL is loaded and initialized.
            DebugAttach.AttachDkm(process.LivePart.Id);
        }
예제 #4
0
        /// <summary>
        /// Attaches debugger to the already running specified process.
        /// </summary>
        /// <param name="processId">The process identifier.</param>
        /// <param name="attachFlags">The attaching flags.</param>
        /// <param name="symbolPaths">Array of paths where debugger will look for symbols.</param>
        public static void AttachToProcess(uint processId, DebugAttach attachFlags = DebugAttach.Noninvasive, params string[] symbolPaths)
        {
            IDebugClient   debugClient = DebugClient.DebugCreate();
            IDebugSymbols5 symbols     = (IDebugSymbols5)debugClient;
            IDebugControl7 control     = (IDebugControl7)debugClient;

            symbols.SetSymbolPathWide(string.Join(";", symbolPaths));
            debugClient.AttachProcess(0, processId, attachFlags);
            control.WaitForEvent(0, uint.MaxValue);
            InitializeDbgEng(debugClient);
        }
예제 #5
0
        public DbgEngDataReader(int processId, bool invasive, uint msecTimeout)
        {
            DisplayName = $"{processId:x}";

            IntPtr client = CreateIDebugClient();

            CreateClient(client);

            DebugAttach attach = invasive ? DebugAttach.Default : DebugAttach.NonInvasive;

            _control.AddEngineOptions(DebugControl.INITIAL_BREAK);

            HResult hr = _client.AttachProcess((uint)processId, attach);

            if (hr)
            {
                hr = _control.WaitForEvent(msecTimeout);
            }

            if (hr == HResult.S_FALSE)
            {
                throw new TimeoutException("Break in did not occur within the allotted timeout.");
            }

            if (hr != 0)
            {
                if ((uint)hr.Value == 0xd00000bb)
                {
                    throw new InvalidOperationException("Mismatched architecture between this process and the target process.");
                }

                if (!WindowsFunctions.IsProcessRunning(processId))
                {
                    throw new ArgumentException($"Process {processId} is not running.");
                }

                throw new ArgumentException($"Could not attach to process {processId}, HRESULT: 0x{hr:x}");
            }
        }
예제 #6
0
 public static int Main(string[] args)
 {
     return(DebugAttach.Main(args));
 }
예제 #7
0
        // Obtains information about programs running, filtered in a variety of ways.
        int IDebugProgramProvider2.GetProviderProcessData(enum_PROVIDER_FLAGS Flags, IDebugDefaultPort2 port, AD_PROCESS_ID ProcessId, CONST_GUID_ARRAY EngineFilter, PROVIDER_PROCESS_DATA[] processArray)
        {
            processArray[0] = new PROVIDER_PROCESS_DATA();

            // we handle creation of the remote program provider ourselves.  This is because we always load our program provider locally which keeps
            // attach working when developing Python Tools and running/debugging from within VS and in the experimental hive.  When we are installed
            // we install into the GAC so these types are available to create and then remote debugging works as well.  When we're running in the
            // experimental hive we are not in the GAC so if we're created outside of VS (e.g. in msvsmon on the local machine) then we can't get
            // at our program provider and debug->attach doesn't work.
            if (port != null && port.QueryIsLocal() == VSConstants.S_FALSE)
            {
                IDebugCoreServer3 server;
                if (ErrorHandler.Succeeded(port.GetServer(out server)))
                {
                    IDebugCoreServer90 dbgServer = server as IDebugCoreServer90;
                    if (dbgServer != null)
                    {
                        Guid   g = typeof(IDebugProgramProvider2).GUID;
                        IntPtr remoteProviderPunk;

                        int hr = dbgServer.CreateManagedInstanceInServer(typeof(AD7ProgramProvider).FullName, typeof(AD7ProgramProvider).Assembly.FullName, 0, ref g, out remoteProviderPunk);
                        try {
                            if (ErrorHandler.Succeeded(hr))
                            {
                                var remoteProvider = (IDebugProgramProvider2)Marshal.GetObjectForIUnknown(remoteProviderPunk);
                                return(remoteProvider.GetProviderProcessData(Flags, null, ProcessId, EngineFilter, processArray));
                            }
                        } finally {
                            if (remoteProviderPunk != IntPtr.Zero)
                            {
                                Marshal.Release(remoteProviderPunk);
                            }
                        }
                    }
                }
            }
            else if ((Flags & enum_PROVIDER_FLAGS.PFLAG_GET_PROGRAM_NODES) != 0)
            {
                // The debugger is asking the engine to return the program nodes it can debug. We check
                // each process if it has a python##.dll or python##_d.dll loaded and if it does
                // then we report the program as being a Python process.

                if (DebugAttach.IsPythonProcess((int)ProcessId.dwProcessId))
                {
                    IDebugProgramNode2 node = new AD7ProgramNode((int)ProcessId.dwProcessId);

                    IntPtr[] programNodes = { Marshal.GetComInterfaceForObject(node, typeof(IDebugProgramNode2)) };

                    IntPtr destinationArray = Marshal.AllocCoTaskMem(IntPtr.Size * programNodes.Length);
                    Marshal.Copy(programNodes, 0, destinationArray, programNodes.Length);

                    processArray[0].Fields = enum_PROVIDER_FIELDS.PFIELD_PROGRAM_NODES;
                    processArray[0].ProgramNodes.Members = destinationArray;
                    processArray[0].ProgramNodes.dwCount = (uint)programNodes.Length;

                    return(VSConstants.S_OK);
                }
            }

            return(VSConstants.S_FALSE);
        }