void IDkmModuleSymbolsLoadedNotification.OnModuleSymbolsLoaded(DkmModuleInstance moduleInstance, DkmModule module, bool isReload, DkmWorkList workList, DkmEventDescriptor eventDescriptor) { var process = moduleInstance.Process; var engines = process.DebugLaunchSettings.EngineFilter; if (engines == null || !engines.Contains(AD7Engine.DebugEngineGuid)) { return; } var pyrtInfo = process.GetPythonRuntimeInfo(); var nativeModuleInstance = moduleInstance as DkmNativeModuleInstance; if (nativeModuleInstance != null) { if (PythonDLLs.CTypesNames.Contains(moduleInstance.Name)) { pyrtInfo.DLLs.CTypes = nativeModuleInstance; var traceHelper = process.GetDataItem <TraceManagerLocalHelper>(); if (traceHelper != null) { traceHelper.OnCTypesLoaded(nativeModuleInstance); } } else if (PythonDLLs.GetPythonLanguageVersion(nativeModuleInstance) != PythonLanguageVersion.None) { if (IsModuleCompiledWithPGO(moduleInstance)) { pyrtInfo.DLLs.Python = null; var pgoWarnMsg = DkmCustomMessage.Create(process.Connection, process, Guid.Empty, (int)VsPackageMessage.WarnAboutPGO, moduleInstance.Name, null); pgoWarnMsg.SendToVsService(Guids.CustomDebuggerEventHandlerGuid, IsBlocking: true); return; } } } if (process.GetPythonRuntimeInstance() != null) { return; } if (pyrtInfo.DLLs.Python != null && pyrtInfo.DLLs.Python.HasSymbols()) { if (process.LivePart == null || pyrtInfo.DLLs.DebuggerHelper != null) { CreatePythonRuntimeInstance(process); } else { InjectHelperDll(process); } } }
public PythonRuntimeInfo() { DLLs = new PythonDLLs(this); }
public override void Handle(DkmProcess process) { if (process.LivePart == null) { // When debugging dumps, there's no stepping or live expression evaluation. Hence, we don't // need the helper DLL nor _ctypes.pyd for anything, and even if they are loaded in the dump, // we don't care about them at all. return; } var pyrtInfo = process.GetPythonRuntimeInfo(); var moduleInstance = process.GetNativeRuntimeInstance().GetNativeModuleInstances().Single(mi => mi.UniqueId == ModuleInstanceId); if (pyrtInfo.DLLs.CTypes == null && PythonDLLs.CTypesNames.Contains(moduleInstance.Name)) { moduleInstance.TryLoadSymbols(); if (moduleInstance.HasSymbols()) { pyrtInfo.DLLs.CTypes = moduleInstance; var traceHelper = process.GetDataItem <TraceManagerLocalHelper>(); if (traceHelper != null) { traceHelper.OnCTypesLoaded(moduleInstance); } } } if (process.GetPythonRuntimeInstance() != null) { return; } if (PythonDLLs.GetPythonLanguageVersion(moduleInstance) != PythonLanguageVersion.None) { pyrtInfo.DLLs.Python = moduleInstance; for (int i = 0; i < 2; ++i) { if (moduleInstance.HasSymbols()) { if (IsModuleCompiledWithPGO(moduleInstance)) { pyrtInfo.DLLs.Python = null; var pgoWarnMsg = DkmCustomMessage.Create(process.Connection, process, Guid.Empty, (int)VsPackageMessage.WarnAboutPGO, moduleInstance.Name, null); pgoWarnMsg.SendToVsService(Guids.CustomDebuggerEventHandlerGuid, IsBlocking: true); return; } if (process.LivePart == null) { // If debugging crash dumps, runtime can be created as soon as Python symbols are resolved. CreatePythonRuntimeInstance(process); } else { // If not, we need to check for debugger helper DLL as well, and inject it if it isn't there yet. if (pyrtInfo.DLLs.DebuggerHelper != null) { CreatePythonRuntimeInstance(process); } else { InjectHelperDll(process); } } return; } moduleInstance.TryLoadSymbols(); } var symWarnMsg = DkmCustomMessage.Create(process.Connection, process, Guid.Empty, (int)VsPackageMessage.WarnAboutPythonSymbols, moduleInstance.Name, null); symWarnMsg.SendToVsService(Guids.CustomDebuggerEventHandlerGuid, IsBlocking: true); } else if (PythonDLLs.DebuggerHelperNames.Contains(moduleInstance.Name)) { moduleInstance.TryLoadSymbols(); // When the module is reported is loaded, it is not necessarily fully initialized yet - it is possible to get into a state // where its import table is not processed yet. If we register TraceFunc and it gets called by Python when in that state, // we'll get a crash as soon as any imported WinAPI function is called. So check whether DllMain has already run - if it // is, we're good to go, and if not, set a breakpoint on a hook that will be called once it is run, and defer runtime // creation until that breakpoint is hit. bool isInitialized = moduleInstance.GetExportedStaticVariable <ByteProxy>("isInitialized").Read() != 0; if (isInitialized) { OnHelperDllInitialized(moduleInstance); } else { DkmRuntimeBreakpoint initBP = null; initBP = CreateRuntimeDllExportedFunctionBreakpoint(moduleInstance, "OnInitialized", (thread, frameBase, vFrame) => { initBP.Close(); OnHelperDllInitialized(moduleInstance); }); initBP.Enable(); } } }