Пример #1
0
        /// <summary>
        /// Finds a module of given MVID in one of the processes being debugged and returns its baseline metadata.
        /// Shall only be called while in debug mode.
        /// </summary>
        public ModuleMetadata TryGetBaselineMetadata(Guid mvid)
        {
            return(_baselineMetadata.GetOrAdd(mvid, m =>
            {
                using (DebuggerComponent.ManagedEditAndContinueService())
                {
                    var clrModuleInstance = FindClrModuleInstance(m);
                    if (clrModuleInstance == null)
                    {
                        return default;
                    }

                    var metadata = GetBaselineModuleMetadata(clrModuleInstance);
                    if (metadata == null)
                    {
                        return default;
                    }

                    // hook up a callback on module unload (the call blocks until the message is processed):
                    DkmCustomMessage.Create(
                        Connection: clrModuleInstance.Process.Connection,
                        Process: clrModuleInstance.Process,
                        SourceId: DebuggerService.MessageSourceId,
                        MessageCode: 0,
                        Parameter1: this,
                        Parameter2: clrModuleInstance).SendLower();

                    return metadata;
                }
            }));
        }
Пример #2
0
        private static bool ShouldEnable(DkmProcess process)
        {
            var message = DkmCustomMessage.Create(
                process.Connection,
                process,
                s_messageSourceId,
                MessageCode: 1, // Is legacy EE enabled?
                Parameter1: null,
                Parameter2: null);

            try
            {
                var reply  = message.SendLower();
                var result = (int)reply.Parameter1;
                // Possible values are 0 = false, 1 = true, 2 = not ready.
                // At this point, we should only get 0 or 1, but to be
                // safe, treat values other than 0 or 1 as false.
                Debug.Assert(result == 0 || result == 1);
                return(result == 0);
            }
            catch (NotImplementedException)
            {
                return(false);
            }
        }
 DkmCustomMessage?IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
 {
     // Initialize the listener before OnModuleInstanceLoad/OnModuleInstanceUnload can be triggered.
     // These events are only called when managed debugging is being used due to RuntimeId=DkmRuntimeId.Clr filter in vsdconfigxml.
     _encService = (IEditAndContinueWorkspaceService)customMessage.Parameter1;
     return(null);
 }
        public void StartDebugging(DebugSessionOptions options)
        {
            _debuggingService.OnBeforeDebuggingStateChanged(DebuggingState.Design, DebuggingState.Run);

            if ((options & DebugSessionOptions.EditAndContinueDisabled) == 0)
            {
                _encService = _workspace.Services.GetRequiredService <IEditAndContinueWorkspaceService>();

                // hook up a callbacks (the call blocks until the message is processed):
                using (DebuggerComponent.ManagedEditAndContinueService())
                {
                    DkmCustomMessage.Create(
                        Connection: null,
                        Process: null,
                        SourceId: DebuggerService.MessageSourceId,
                        MessageCode: 0,
                        Parameter1: _encService,
                        Parameter2: null).SendLower();
                }

                _encService.StartDebuggingSession();
            }
            else
            {
                _encService = null;
            }
        }
 DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
 {
     // Initialize the listener before OnModuleInstanceLoad/OnModuleInstanceUnload can be triggered.
     // These events are only called when managed debugging is being used due to RuntimeId=DkmRuntimeId.Clr filter in vsdconfigxml.
     _listener = (VisualStudioDebugStateChangeListener)customMessage.Parameter1;
     return(null);
 }
        /// <summary>
        /// Finds a module of given MVID in one of the processes being debugged and returns its baseline metadata.
        /// Shall only be called while in debug mode.
        /// Shall only be called on MTA thread.
        /// </summary>
        public DebuggeeModuleInfo TryGetBaselineModuleInfo(Guid mvid)
        {
            Contract.ThrowIfFalse(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA);

            return(_baselineMetadata.GetOrAdd(mvid, m =>
            {
                using (DebuggerComponent.ManagedEditAndContinueService())
                {
                    var clrModuleInstance = FindClrModuleInstance(m);
                    if (clrModuleInstance == null)
                    {
                        return default;
                    }

                    if (!TryGetBaselineModuleInfo(clrModuleInstance, out var metadata, out var symReader))
                    {
                        return default;
                    }

                    // hook up a callback on module unload (the call blocks until the message is processed):
                    DkmCustomMessage.Create(
                        Connection: clrModuleInstance.Process.Connection,
                        Process: clrModuleInstance.Process,
                        SourceId: DebuggerService.MessageSourceId,
                        MessageCode: 0,
                        Parameter1: this,
                        Parameter2: clrModuleInstance).SendLower();

                    return new DebuggeeModuleInfo(metadata, symReader);
                }
Пример #7
0
        DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
        {
            var process = customMessage.Process;

            if (customMessage.MessageCode == MessageToLocalWorker.fetchLuaSymbols)
            {
                var moduleUniqueId = new Guid(customMessage.Parameter1 as byte[]);

                var nativeModuleInstance = process.GetNativeRuntimeInstance().GetNativeModuleInstances().FirstOrDefault(el => el.UniqueId == moduleUniqueId);

                if (nativeModuleInstance == null)
                {
                    return(null);
                }

                // Check if Lua library is loaded
                ulong luaNewState    = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_newstate", out _).GetValueOrDefault(0);
                ulong luaLibNewState = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0);

                if (luaNewState != 0 || luaLibNewState != 0)
                {
                    var locations = new LuaLocationsMessage();

                    locations.luaExecuteAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaV_execute", out _).GetValueOrDefault(0);
                    locations.luaExecuteAtEnd   = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "luaV_execute", out _).GetValueOrDefault(0);

                    if (luaNewState != 0)
                    {
                        locations.luaNewStateAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lua_newstate", out _).GetValueOrDefault(0);
                        locations.luaNewStateAtEnd   = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "lua_newstate", out _).GetValueOrDefault(0);
                    }
                    else
                    {
                        locations.luaNewStateAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0);
                        locations.luaNewStateAtEnd   = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0);
                    }

                    locations.luaClose   = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lua_close", out _).GetValueOrDefault(0);
                    locations.closeState = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "close_state", out _).GetValueOrDefault(0);

                    locations.luaLoadFileEx       = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadfilex", out _).GetValueOrDefault(0);
                    locations.luaLoadFile         = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadfile", out _).GetValueOrDefault(0);
                    locations.solCompatLoadFileEx = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "kp_compat53L_loadfilex", out _).GetValueOrDefault(0);

                    locations.luaLoadBufferEx = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadbufferx", out _).GetValueOrDefault(0);
                    locations.luaLoadBuffer   = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadbuffer", out _).GetValueOrDefault(0);

                    locations.luaLoad = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lua_load", out _).GetValueOrDefault(0);

                    locations.luaError    = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaB_error", out _).GetValueOrDefault(0);
                    locations.luaRunError = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaG_runerror", out _).GetValueOrDefault(0);
                    locations.luaThrow    = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaD_throw", out _).GetValueOrDefault(0);

                    return(DkmCustomMessage.Create(process.Connection, process, MessageToLocal.guid, MessageToLocal.luaSymbols, locations.Encode(), null));
                }
            }

            return(null);
        }
Пример #8
0
        private DkmCustomMessage Handle(DkmCustomMessage customMessage)
        {
            var requestSerializer = _messageSerializers[customMessage.MessageCode];
            var requestData       = (byte[])customMessage.Parameter1;
            var request           = (IMessage)requestSerializer.ReadObject(new MemoryStream(requestData, false));

            return(request.Handle(customMessage.Process));
        }
            DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
            {
                var provider          = (VisualStudioDebuggeeModuleMetadataProvider)customMessage.Parameter1;
                var clrModuleInstance = (DkmClrModuleInstance)customMessage.Parameter2;

                // Note that this call has to be made in a Concord component.
                // The debugger tracks what the current Concord component is and associates the data item with it.
                clrModuleInstance.SetDataItem(DkmDataCreationDisposition.CreateAlways, new DataItem(provider, clrModuleInstance.Mvid));
                return(null);
            }
        /// <summary>
        /// Called by the debugger when a debugging session starts and managed debugging is being used.
        /// </summary>
        public void StartDebugging()
        {
            // Hook up a callbacks (the call blocks until the message is processed).
            using (DebuggerComponent.ManagedEditAndContinueService())
            {
                DkmCustomMessage.Create(
                    Connection: null,
                    Process: null,
                    SourceId: DebuggerService.MessageSourceId,
                    MessageCode: 0,
                    Parameter1: this,
                    Parameter2: null).SendLower();
            }

            _debuggingService.OnBeforeDebuggingStateChanged(DebuggingState.Design, DebuggingState.Run);

            _encService.StartDebuggingSession();
        }
Пример #11
0
        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);
        }
Пример #12
0
        public DkmCustomMessage SendLower(DkmCustomMessage message)
        {
            object result;

            byte[]       bytes;
            MessageCodes messageCode = (MessageCodes)message.MessageCode;

            try
            {
                bytes  = (byte[])message.Parameter1;
                result = ProcessMessage(messageCode, bytes);
            }
            catch (Exception e)
            {
                result      = e.ToString();
                messageCode = MessageCodes.Exception;
            }

            bytes = MessageSerializer.Serialize(result);
            return(DkmCustomMessage.Create(message.Connection, message.Process, Guid.Empty, (int)messageCode, bytes, null));
        }
Пример #13
0
        void createProcessTracer_OnFunctionExited(
            DkmStackWalkFrame frame,
            StackFrameAnalyzer frameAnalyzer)
        {
            try {
                ulong processInfoAddr = Convert.ToUInt64(
                    frameAnalyzer.GetArgumentValue(frame, "lpProcessInformation"));

                // Check the return address first, it should be in EAX.  CreateProcessAsUser and
                // CreateProcess both return 0 on failure.  If the function failed, there is no child to
                // attach to.
                if (0 == frame.VscxGetRegisterValue32(CpuRegister.Eax))
                {
                    return;
                }

                // The process was successfully created.  Extract the PID from the PROCESS_INFORMATION
                // output param.  An attachment request must happend through the EnvDTE, which can only
                // be accessed from the VsPackage, so a request must be sent via a component message.
                DkmProcess process = frame.Process;
                int        size    = Marshal.SizeOf(typeof(PROCESS_INFORMATION));
                byte[]     buffer  = new byte[size];
                process.ReadMemory(processInfoAddr, DkmReadMemoryFlags.None, buffer);
                PROCESS_INFORMATION info          = MarshalUtility.ByteArrayToStructure <PROCESS_INFORMATION>(buffer);
                DkmCustomMessage    attachRequest = DkmCustomMessage.Create(
                    process.Connection,
                    process,
                    PackageServices.VsPackageMessageGuid,
                    (int)VsPackageMessage.AttachToChild,
                    process.LivePart.Id,
                    info.dwProcessId);
                attachRequest.SendToVsService(PackageServices.DkmComponentEventHandler, false);
            } catch (Exception exception) {
                Logger.LogError(
                    exception,
                    "An error occured handling the exit breakpoint.  HR = 0x{0:X}",
                    exception.HResult);
            }
        }
        /// <summary>
        /// Finds a module of given MVID in one of the processes being debugged and returns its baseline metadata.
        /// Shall only be called while in debug mode.
        /// Shall only be called on MTA thread.
        /// </summary>
        /// <returns>Null, if the module with the specified MVID is not found.</returns>
        public DebuggeeModuleInfo TryGetBaselineModuleInfo(Guid mvid)
        {
            Contract.ThrowIfFalse(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA);

            return(_baselineMetadata.GetOrAdd(mvid, m =>
            {
                using (DebuggerComponent.ManagedEditAndContinueService())
                {
                    var clrModuleInstance = EnumerateClrModuleInstances(m).FirstOrDefault();
                    if (clrModuleInstance == null)
                    {
                        return null;
                    }

                    // The DebuggeeModuleInfo holds on a pointer to module metadata and on a SymReader instance.
                    //
                    // The module metadata lifetime is that of the module instance, so we need to stop using the module
                    // as soon as the module instance is unloaded. We do so by associating a DataItem with the module
                    // instance and removing the metadata from our cache when the DataItem is disposed.
                    //
                    // The SymReader instance is shared across all instancese of the module.
                    if (!clrModuleInstance.TryGetModuleInfo(out var info))
                    {
                        return null;
                    }

                    // hook up a callback on module unload (the call blocks until the message is processed):
                    DkmCustomMessage.Create(
                        Connection: clrModuleInstance.Process.Connection,
                        Process: clrModuleInstance.Process,
                        SourceId: DebuggerService.MessageSourceId,
                        MessageCode: 0,
                        Parameter1: this,
                        Parameter2: clrModuleInstance).SendLower();

                    return info;
                }
Пример #15
0
 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.Log(
         "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.LogException(
     exception,
     "An error occurred while handling a debugger message.  HR = 0x{0:X}",
     exception.HResult);
       }
       return null;
 }
Пример #16
0
            void IDkmProcessExecutionNotification.OnProcessPause(DkmProcess process, DkmProcessExecutionCounters processCounters)
            {
                try
                {
                    ulong?moduleBaseOpt = DebugHelpers.ReadPointerVariable(process, "nullcModuleStartAddress");

                    // Check if nullc is available
                    if (moduleBaseOpt == null)
                    {
                        return;
                    }

                    var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(process);

                    if (processData.language == null)
                    {
                        processData.compilerId = new DkmCompilerId(DebugHelpers.NullcCompilerGuid, DebugHelpers.NullcLanguageGuid);

                        processData.language = DkmLanguage.Create("nullc", processData.compilerId);
                    }

                    // Create VM runtime and module
                    if (processData.vmRuntimeInstance == null)
                    {
                        DkmRuntimeInstanceId runtimeId = new DkmRuntimeInstanceId(DebugHelpers.NullcVmRuntimeGuid, 0);

                        processData.vmRuntimeInstance = DkmCustomRuntimeInstance.Create(process, runtimeId, null);
                    }

                    if (processData.vmModule == null)
                    {
                        DkmModuleId moduleId = new DkmModuleId(Guid.NewGuid(), DebugHelpers.NullcSymbolProviderGuid);

                        processData.vmModule = DkmModule.Create(moduleId, "nullc.vm.code", processData.compilerId, process.Connection, null);
                    }

                    if (processData.vmModuleInstance == null)
                    {
                        DkmDynamicSymbolFileId symbolFileId = DkmDynamicSymbolFileId.Create(DebugHelpers.NullcSymbolProviderGuid);

                        processData.vmModuleInstance = DkmCustomModuleInstance.Create("nullc_vm", "nullc.vm.code", 0, processData.vmRuntimeInstance, null, symbolFileId, DkmModuleFlags.None, DkmModuleMemoryLayout.Unknown, 0, 1, 0, "nullc vm code", false, null, null, null);

                        processData.vmModuleInstance.SetModule(processData.vmModule, true); // Can use reload?
                    }

                    ulong moduleBase = moduleBaseOpt.GetValueOrDefault(0);

                    uint moduleSize = (uint)(DebugHelpers.ReadPointerVariable(process, "nullcModuleEndAddress").GetValueOrDefault(0) - moduleBase);

                    // Create JiT runtime and module
                    if (moduleBase != 0 && moduleSize != 0)
                    {
                        if (processData.runtimeInstance == null && processData.nativeRuntimeInstance == null)
                        {
                            DkmRuntimeInstanceId runtimeId = new DkmRuntimeInstanceId(DebugHelpers.NullcRuntimeGuid, 0);

                            if (DebugHelpers.useNativeInterfaces)
                            {
                                processData.nativeRuntimeInstance = DebugHelpers.useDefaultRuntimeInstance ? process.GetNativeRuntimeInstance() : DkmNativeRuntimeInstance.Create(process, runtimeId, DkmRuntimeCapabilities.None, process.GetNativeRuntimeInstance(), null);
                            }
                            else
                            {
                                processData.runtimeInstance = DkmCustomRuntimeInstance.Create(process, runtimeId, null);
                            }
                        }

                        if (processData.module == null)
                        {
                            DkmModuleId moduleId = new DkmModuleId(Guid.NewGuid(), DebugHelpers.NullcSymbolProviderGuid);

                            processData.module = DkmModule.Create(moduleId, "nullc.embedded.code", processData.compilerId, process.Connection, null);
                        }

                        if (processData.moduleInstance == null && processData.nativeModuleInstance == null)
                        {
                            DkmDynamicSymbolFileId symbolFileId = DkmDynamicSymbolFileId.Create(DebugHelpers.NullcSymbolProviderGuid);

                            if (DebugHelpers.useNativeInterfaces)
                            {
                                processData.nativeModuleInstance = DkmNativeModuleInstance.Create("nullc", "nullc.embedded.code", 0, null, symbolFileId, DkmModuleFlags.None, DkmModuleMemoryLayout.Unknown, 1, "nullc embedded code", processData.nativeRuntimeInstance, moduleBase, moduleSize, Microsoft.VisualStudio.Debugger.Clr.DkmClrHeaderStatus.NativeBinary, false, null, null, null);

                                processData.nativeModuleInstance.SetModule(processData.module, true); // Can use reload?
                            }
                            else
                            {
                                processData.moduleInstance = DkmCustomModuleInstance.Create("nullc", "nullc.embedded.code", 0, processData.runtimeInstance, null, symbolFileId, DkmModuleFlags.None, DkmModuleMemoryLayout.Unknown, moduleBase, 1, moduleSize, "nullc embedded code", false, null, null, null);

                                processData.moduleInstance.SetModule(processData.module, true); // Can use reload?
                            }
                        }
                    }

                    // Update bytecode
                    var moduleBytecodeVersion = DebugHelpers.ReadPointerVariable(process, "nullcModuleBytecodeVersion").GetValueOrDefault(0);

                    if (processData.moduleBytecodeLocation != 0 && moduleBytecodeVersion != processData.moduleBytecodeVersion)
                    {
                        processData.moduleBytecodeLocation = 0;
                        processData.moduleBytecodeSize     = 0;
                        processData.moduleBytecodeRaw      = null;
                        processData.bytecode = null;
                    }

                    if (processData.moduleBytecodeLocation == 0)
                    {
                        processData.moduleBytecodeLocation = DebugHelpers.ReadPointerVariable(process, "nullcModuleBytecodeLocation").GetValueOrDefault(0);
                        processData.moduleBytecodeSize     = DebugHelpers.ReadPointerVariable(process, "nullcModuleBytecodeSize").GetValueOrDefault(0);
                        processData.moduleBytecodeVersion  = moduleBytecodeVersion;

                        if (processData.moduleBytecodeLocation != 0)
                        {
                            processData.moduleBytecodeRaw = new byte[processData.moduleBytecodeSize];
                            process.ReadMemory(processData.moduleBytecodeLocation, DkmReadMemoryFlags.None, processData.moduleBytecodeRaw);

                            processData.bytecode = new NullcBytecode();
                            processData.bytecode.ReadFrom(processData.moduleBytecodeRaw, DebugHelpers.Is64Bit(process));

                            // Notify local component about bytecode update
                            var message = DkmCustomMessage.Create(process.Connection, process, DebugHelpers.NullcReloadSymbolsMessageGuid, 1, null, null);

                            message.SendHigher();
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("OnProcessPause failed with: " + ex.ToString());
                }
            }
Пример #17
0
 DkmCustomMessage IDkmCustomMessageCallbackReceiver.SendHigher(DkmCustomMessage customMessage)
 {
     return((customMessage.SourceId == _sourceId) ? Handle(customMessage) : null);
 }
Пример #18
0
 DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
 {
     return((customMessage.SourceId == _sourceId) ? Handle(customMessage) : null);
 }
        DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
        {
            var process     = customMessage.Process;
            var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process);

            if (customMessage.MessageCode == MessageToRemote.createRuntime)
            {
                if (processData.language == null)
                {
                    processData.compilerId = new DkmCompilerId(Guids.luaCompilerGuid, Guids.luaLanguageGuid);

                    processData.language = DkmLanguage.Create("Lua", processData.compilerId);
                }

                if (processData.runtimeInstance == null)
                {
                    DkmRuntimeInstanceId runtimeId = new DkmRuntimeInstanceId(Guids.luaRuntimeGuid, 0);

                    processData.runtimeInstance = DkmCustomRuntimeInstance.Create(process, runtimeId, null);
                }

                if (processData.module == null)
                {
                    DkmModuleId moduleId = new DkmModuleId(Guid.NewGuid(), Guids.luaSymbolProviderGuid);

                    processData.module = DkmModule.Create(moduleId, "lua.vm.code", processData.compilerId, process.Connection, null);
                }

                if (processData.moduleInstance == null)
                {
                    DkmDynamicSymbolFileId symbolFileId = DkmDynamicSymbolFileId.Create(Guids.luaSymbolProviderGuid);

                    processData.moduleInstance = DkmCustomModuleInstance.Create("lua_vm", "lua.vm.code", 0, processData.runtimeInstance, null, symbolFileId, DkmModuleFlags.None, DkmModuleMemoryLayout.Unknown, 0, 1, 0, "Lua vm code", false, null, null, null);

                    processData.moduleInstance.SetModule(processData.module, true); // Can use reload?
                }
            }
            else if (customMessage.MessageCode == MessageToRemote.luaHelperDataLocations)
            {
                var data = new HelperLocationsMessage();

                data.ReadFrom(customMessage.Parameter1 as byte[]);

                processData.locations = data;
            }
            else if (customMessage.MessageCode == MessageToRemote.pauseBreakpoints)
            {
                processData.pauseBreakpoints = true;
            }
            else if (customMessage.MessageCode == MessageToRemote.resumeBreakpoints)
            {
                processData.pauseBreakpoints = false;
            }
            else if (customMessage.MessageCode == MessageToRemote.luaVersionInfo)
            {
                processData.luaVersion = (customMessage.Parameter1 as int?).GetValueOrDefault(0);

                LuaHelpers.luaVersion = processData.luaVersion;
            }
            else if (customMessage.MessageCode == MessageToRemote.registerLuaState)
            {
                var data = new RegisterStateMessage();

                data.ReadFrom(customMessage.Parameter1 as byte[]);

                Debug.Assert(processData.knownStates.ContainsKey(data.stateAddress) == false);

                if (processData.knownStates.ContainsKey(data.stateAddress))
                {
                    Debug.WriteLine("IDkmCustomMessageForwardReceiver.SendLower() Duplicate Lua state registration, destruction was probably missed!");
                }
                else
                {
                    processData.knownStates.Add(data.stateAddress, data);

                    if (processData.hooksEnabled)
                    {
                        SetupHooks(process, processData);
                    }
                }
            }
            else if (customMessage.MessageCode == MessageToRemote.unregisterLuaState)
            {
                var data = new UnregisterStateMessage();

                data.ReadFrom(customMessage.Parameter1 as byte[]);

                // Registration is called only for states that can be hooked, unregistration is always called
                if (processData.knownStates.ContainsKey(data.stateAddress))
                {
                    processData.knownStates.Remove(data.stateAddress);
                }
            }

            return(null);
        }
        void IDkmRuntimeBreakpointReceived.OnRuntimeBreakpointReceived(DkmRuntimeBreakpoint runtimeBreakpoint, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor)
        {
            var process = thread.Process;

            var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process);

            if (runtimeBreakpoint.SourceId == Guids.luaSupportBreakpointGuid)
            {
                if (processData.locations != null)
                {
                    if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperBreakpointHit)
                    {
                        // Breakpoint can get hit again after expression evaluation 'slips' the thread
                        if (processData.pauseBreakpoints)
                        {
                            return;
                        }

                        eventDescriptor.Suppress();

                        var breakpointPos = DebugHelpers.ReadUintVariable(process, processData.locations.helperBreakHitIdAddress);

                        if (!breakpointPos.HasValue)
                        {
                            return;
                        }

                        if (breakpointPos.Value < processData.activeBreakpoints.Count)
                        {
                            try
                            {
                                var breakpoint = processData.activeBreakpoints[(int)breakpointPos.Value];

                                if (breakpoint.runtimeBreakpoint != null)
                                {
                                    breakpoint.runtimeBreakpoint.OnHit(thread, false);
                                }
                            }
                            catch (System.ObjectDisposedException)
                            {
                                // Breakpoint was implicitly closed
                                processData.activeBreakpoints.RemoveAt((int)breakpointPos.Value);
                            }
                            catch (DkmException)
                            {
                                // In case another component evaluates a function
                            }
                        }

                        return;
                    }
                    else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepComplete)
                    {
                        if (processData.activeStepper != null)
                        {
                            var activeStepper = processData.activeStepper;

                            ClearStepperData(process, processData);

                            activeStepper.OnStepComplete(thread, false);
                        }

                        return;
                    }
                    else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepInto)
                    {
                        if (processData.activeStepper != null)
                        {
                            var activeStepper = processData.activeStepper;

                            ClearStepperData(process, processData);

                            activeStepper.OnStepComplete(thread, false);
                        }

                        return;
                    }
                    else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepOut)
                    {
                        if (processData.activeStepper != null)
                        {
                            var activeStepper = processData.activeStepper;

                            ClearStepperData(process, processData);

                            activeStepper.OnStepComplete(thread, false);
                        }

                        return;
                    }
                }

                thread.GetCurrentFrameInfo(out ulong retAddr, out ulong frameBase, out ulong vframe);

                var data = new SupportBreakpointHitMessage
                {
                    breakpointId = runtimeBreakpoint.UniqueId,
                    threadId     = thread.UniqueId,
                    retAddr      = retAddr,
                    frameBase    = frameBase,
                    vframe       = vframe
                };

                var message = DkmCustomMessage.Create(process.Connection, process, MessageToLocal.guid, MessageToLocal.luaSupportBreakpointHit, data.Encode(), null);

                var response = message.SendHigher();

                if (response?.MessageCode == MessageToRemote.throwException)
                {
                    if (runtimeBreakpoint is DkmRuntimeInstructionBreakpoint runtimeInstructionBreakpoint)
                    {
                        var exceptionInformation = DkmCustomExceptionInformation.Create(processData.runtimeInstance, Guids.luaExceptionGuid, thread, runtimeInstructionBreakpoint.InstructionAddress, "LuaError", 0, DkmExceptionProcessingStage.Thrown | DkmExceptionProcessingStage.UserVisible | DkmExceptionProcessingStage.Unhandled, null, new ReadOnlyCollection <byte>(response.Parameter1 as byte[]));

                        exceptionInformation.OnDebugMonitorException();
                    }
                }
            }
        }
 DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage)
 {
     _listener = (VisualStudioDebugStateChangeListener)customMessage.Parameter1;
     return(null);
 }