public DkmCustomMessage SendLower(DkmCustomMessage customMessage) { try { Debug.Assert(customMessage.SourceId == PackageServices.VsDebuggerMessageGuid); VsDebuggerMessage code = (VsDebuggerMessage)customMessage.MessageCode; switch (code) { case VsDebuggerMessage.EnableChildProcessDebugging: Guid processGuid = (Guid)customMessage.Parameter1; DkmProcess process = DkmProcess.FindProcess(processGuid); if (process != null) { process.SetDataItem( DkmDataCreationDisposition.CreateNew, new RuntimeBreakpointHandler()); process.SetDataItem( DkmDataCreationDisposition.CreateNew, new AutoAttachToChildHandler()); Logger.LogInfo( "Successfully delay-enabled child debugging for process {0}.", processGuid); } else { Logger.LogError( "Unable to find process {0} while trying to enable child process debugging.", processGuid); } break; default: Logger.LogError("Debug component received unknown message code {0}.", code); break; } } catch (DkmException exception) { Logger.LogError( exception, "An error occurred while handling a debugger message. HR = 0x{0:X}", exception.HResult); } return(null); }
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); }
public static void VscxOnRuntimeInstanceLoad(this DkmRuntimeInstance runtime) { if (runtime.TagValue != DkmRuntimeInstance.Tag.NativeRuntimeInstance) { return; } DkmNativeRuntimeInstance nativeRuntime = (DkmNativeRuntimeInstance)runtime; bool isChrome = false; bool isTestProcess = false; // Check if the process is a chrome executable, and if so, attach a CallstackFilter to the DkmProcess. if (ChromeUtility.IsChromeProcess(nativeRuntime.Process.Path)) { isChrome = true; } #if DEBUG string fileName = Path.GetFileName(nativeRuntime.Process.Path); if (fileName.Equals("vistest.exe", StringComparison.CurrentCultureIgnoreCase)) { isTestProcess = true; } #endif if (isTestProcess || isChrome) { DkmProcess process = nativeRuntime.Process; DebugProcessOptions options = DebugProcessOptions.Create(process.DebugLaunchSettings.OptionsString); ProcessDebugOptionsDataItem optionsDataItem = new ProcessDebugOptionsDataItem(options); process.SetDataItem(DkmDataCreationDisposition.CreateAlways, optionsDataItem); if (isTestProcess || ShouldEnableChildDebugging(nativeRuntime.Process, options)) { process.SetDataItem(DkmDataCreationDisposition.CreateAlways, new RuntimeBreakpointHandler()); process.SetDataItem(DkmDataCreationDisposition.CreateAlways, new AutoAttachToChildHandler()); } } }
public static StructMetadata GetStructMetadata <TStruct>(DkmProcess process) where TStruct : StructProxy { var metadata = process.GetDataItem <StructMetadata <TStruct> >(); if (metadata != null) { return(metadata); } metadata = new StructMetadata <TStruct>(process); process.SetDataItem(DkmDataCreationDisposition.CreateNew, metadata); return(metadata); }
public override void Handle(DkmProcess process) { var pyrtInfo = process.GetPythonRuntimeInfo(); var nativeModules = process.GetNativeRuntimeInstance().GetNativeModuleInstances(); pyrtInfo.DLLs.Python = nativeModules.Single(mi => mi.UniqueId == PythonDllModuleInstanceId); pyrtInfo.DLLs.Python.FlagAsTransitionModule(); if (DebuggerHelperDllModuleInstanceId != Guid.Empty) { pyrtInfo.DLLs.DebuggerHelper = nativeModules.Single(mi => mi.UniqueId == DebuggerHelperDllModuleInstanceId); pyrtInfo.DLLs.DebuggerHelper.FlagAsTransitionModule(); process.SetDataItem(DkmDataCreationDisposition.CreateNew, new TraceManager(process)); } var runtimeId = new DkmRuntimeInstanceId(Guids.PythonRuntimeTypeGuid, 0); var runtimeInstance = DkmCustomRuntimeInstance.Create(process, runtimeId, null); new CreateModuleRequest { ModuleId = Guids.UnknownPythonModuleGuid }.Handle(process); }