Пример #1
0
        private void RequestBackendVariables(DAPRequest request, DAPVariablesRequest msg, int dapIndex)
        {
            if (!VariableRefs.TryGetValue(dapIndex, out BackendVariableReference varRef))
            {
                throw new RequestFailedException($"Unknown backend variable reference: {dapIndex}");
            }

            var state = DAP.GetThread(varRef.Context);

            if (!state.Stopped)
            {
                throw new RequestFailedException("Cannot fetch variables when thread is not stopped");
            }

            uint seq = DAP.DbgCli.SendGetVariables(varRef);

            PendingGetVariablesRequests.Add(seq, (uint replySeq, StatusCode status, BkGetVariablesResponse response) =>
            {
                if (status == StatusCode.Success)
                {
                    OnVariablesReceived(request, msg, state, response);
                }
                else if (status == StatusCode.EvalFailed && response != null)
                {
                    DAP.Stream.SendReply(request, response.ErrorMessage);
                }
                else
                {
                    DAP.Stream.SendReply(request, $"Backend returned error: {status}");
                }
            });
        }
Пример #2
0
        private void HandleContinueRequest(DAPRequest request, DAPContinueRequest msg, DbgContinue.Types.Action action)
        {
            var state = GetThread(msg.threadId, true);

            if (action == DbgContinue.Types.Action.Pause)
            {
                if (state.Stopped)
                {
                    throw new RequestFailedException("Already stopped");
                }
            }
            else
            {
                if (!state.Stopped)
                {
                    throw new RequestFailedException("Already running");
                }

                state.Stopped = false;
            }

            SendContinue(state.Context, action);

            var reply = new DAPContinueResponse
            {
                allThreadsContinued = false
            };

            Stream.SendReply(request, reply);
        }
Пример #3
0
        private void ReceivedEvaluateResponse(DAPRequest request, DAPEvaulateRequest req, ThreadState state, BkEvaluateResponse response)
        {
            DAPEvaluateResponse evalResponse = new DAPEvaluateResponse
            {
                result             = "",
                namedVariables     = 0,
                indexedVariables   = 0,
                variablesReference = 0,
            };

            if (response.Result == null)
            {
                evalResponse.result = "(None)";
            }
            else
            {
                evalResponse.result = DbgValueToString(response.Result);

                if (response.Result.Variables != null)
                {
                    var varsRef = BackendVariableReference.FromDbg(state.Context, response.Result.Variables);
                    var varsIdx = NextVariableReference++;
                    VariableRefs.Add(varsIdx, varsRef);
                    evalResponse.variablesReference = MakeVariableRef(varsIdx);
                }
            }

            DAP.Stream.SendReply(request, evalResponse);
        }
Пример #4
0
        private void HandleModulesRequest(DAPRequest request, DAPModulesRequest req)
        {
            int startIdx = req.startModule;
            int lastIdx;

            if (req.moduleCount == 0)
            {
                lastIdx = Modules.Count;
            }
            else
            {
                lastIdx = Math.Min(startIdx + req.moduleCount, Modules.Count);
            }

            var reply = new DAPModulesResponse
            {
                modules      = new List <DAPModule>(),
                totalModules = Modules.Count
            };

            for (int i = startIdx; i < lastIdx; i++)
            {
                var mod = Modules[i];
                reply.modules.Add(new DAPModule
                {
                    id   = mod.UUID,
                    name = mod.Name,
                    path = mod.Path
                });
            }

            Stream.SendReply(request, reply);
        }
Пример #5
0
        private void HandleDisconnectRequest(DAPRequest request, DAPDisconnectRequest msg)
        {
            var reply = new DAPEmptyPayload();

            Stream.SendReply(request, reply);
            // TODO - close session
        }
Пример #6
0
        private void HandleSetBreakpointsRequest(DAPRequest request, DAPSetBreakpointsRequest breakpoints)
        {
            var path = breakpoints.source.path.Length > 0 ? breakpoints.source.path : breakpoints.source.name;

            var reply = new DAPSetBreakpointsResponse
            {
                breakpoints = new List <DAPBreakpoint>()
            };

            var fileBps = new Dictionary <int, BreakpointInfo>();

            foreach (var breakpoint in breakpoints.breakpoints)
            {
                var bp = new BreakpointInfo();
                bp.Id   = NextBreakpointId++;
                bp.Path = path;
                bp.Line = breakpoint.line;
                fileBps.Add(bp.Line, bp);

                var dapBp = new DAPBreakpoint();
                dapBp.id       = bp.Id;
                dapBp.verified = true; // TODO - verify with backend?
                dapBp.source   = breakpoints.source;
                dapBp.line     = bp.Line;
                reply.breakpoints.Add(dapBp);
            }

            Breakpoints[path] = fileBps;
            SendBreakpointUpdate();

            Stream.SendReply(request, reply);
        }
Пример #7
0
        private void HandleLaunchRequest(DAPRequest request, DAPLaunchRequest launch)
        {
            Config = launch.dbgOptions;

            if (launch.backendHost == null || launch.backendPort == 0)
            {
                throw new RequestFailedException("'backendHost' and 'backendPort' launch configuration variables must be set!");
            }

            if (Config == null)
            {
                Config = new DAPCustomConfiguration();
            }

            if (launch.noDebug)
            {
                throw new RequestFailedException("Cannot attach to game with debugging disabled");
            }

            try
            {
                DbgClient = new AsyncProtobufClient(launch.backendHost, launch.backendPort);
            }
            catch (SocketException e)
            {
                throw new RequestFailedException("Could not connect to Lua debugger backend: " + e.Message);
            }

            DbgCli = new DebuggerClient(DbgClient)
            {
                OnBackendConnected     = this.OnBackendConnected,
                OnBreakpointTriggered  = this.OnBreakpointTriggered,
                OnEvaluateFinished     = Evaluator.OnEvaluateFinished,
                OnContextUpdated       = this.OnContextUpdated,
                OnModInfo              = this.OnModInfo,
                OnDebugOutput          = this.OnDebugOutput,
                OnResults              = this.OnResults,
                OnDebuggerReady        = this.OnDebuggerReady,
                OnSourceResponse       = this.OnSourceResponse,
                OnGetVariablesFinished = Evaluator.OnGetVariablesFinished
            };
            if (LogStream != null)
            {
                DbgCli.EnableLogging(LogStream);
            }

            DbgCli.SendConnectRequest(DBGProtocolVersion);

            DbgThread = new Thread(new ThreadStart(DebugThreadMain));
            DbgThread.Start();

            var reply = new DAPLaunchResponse();

            Stream.SendReply(request, reply);
        }
Пример #8
0
        private void HandleSourceRequest(DAPRequest request, DAPSourceRequest req)
        {
            if (req.source == null || req.source.path == null)
            {
                throw new RequestFailedException("Cannot handle source requests without a path");
            }

            var path  = req.source.path.Length > 0 ? req.source.path : req.source.name;
            var seqId = DbgCli.SendSourceRequest(path);

            PendingSourceRequests.Add(seqId, request);
        }
Пример #9
0
        private void HandleLoadedSourcesRequest(DAPRequest request, DAPLoadedSourcesRequest req)
        {
            var reply = new DAPLoadedSourcesResponse
            {
                sources = SourceFiles.Select(source => new DAPSource
                {
                    path = source
                }).ToList()
            };

            Stream.SendReply(request, reply);
        }
Пример #10
0
        public void SendReply(DAPRequest request, string errorText)
        {
            var reply = new DAPResponse
            {
                type        = "response",
                request_seq = request.seq,
                success     = false,
                command     = request.command,
                message     = errorText
            };

            Send(reply);
        }
Пример #11
0
        public void SendReply(DAPRequest request, IDAPMessagePayload response)
        {
            var reply = new DAPResponse
            {
                type        = "response",
                request_seq = request.seq,
                success     = true,
                command     = request.command,
                body        = response
            };

            Send(reply);
        }
Пример #12
0
        private void HandleScopesRequest(DAPRequest request, DAPScopesRequest msg)
        {
            var threadId   = msg.frameId >> 16;
            var frameIndex = msg.frameId & 0xffff;

            var state = GetThread(threadId);

            if (!state.Stopped)
            {
                throw new RequestFailedException("Cannot get scopes when thread is not stopped");
            }

            if (frameIndex < 0 || frameIndex >= state.Stack.Count)
            {
                throw new RequestFailedException("Requested scopes for unknown frame");
            }

            var frame      = state.Stack[frameIndex];
            var stackScope = new DAPScope
            {
                name = "Locals",
                variablesReference = Evaluator.MakeStackRef(threadId, frameIndex, 0),
                namedVariables     = 0, // TODO - get hinted named/indexed variable count,
                indexedVariables   = 0,
                expensive          = false
            };

            SetScopeRange(stackScope, frame);

            var upvalueScope = new DAPScope
            {
                name = "Upvalues",
                variablesReference = Evaluator.MakeStackRef(threadId, frameIndex, 1),
                namedVariables     = 0,
                indexedVariables   = 0,
                expensive          = false
            };

            SetScopeRange(upvalueScope, frame);

            var scopes = new List <DAPScope> {
                stackScope, upvalueScope
            };

            var reply = new DAPScopesResponse
            {
                scopes = scopes
            };

            Stream.SendReply(request, reply);
        }
Пример #13
0
        private void OnVariablesReceived(DAPRequest request, DAPVariablesRequest msg, ThreadState state, BkGetVariablesResponse response)
        {
            int startIndex = msg.start == null ? 0 : (int)msg.start;
            int numVars    = (msg.count == null || msg.count == 0) ? response.Result.Count : (int)msg.count;
            int lastIndex  = Math.Min(startIndex + numVars, response.Result.Count);
            // TODO req.filter, format

            var variables = new List <DAPVariable>();

            for (var i = startIndex; i < startIndex + numVars; i++)
            {
                var variable = response.Result[i];
                var dapVar   = new DAPVariable
                {
                    value = DbgValueToString(variable.Value),
                    type  = variable.Value.TypeId.ToString()
                };

                if (variable.Type == MsgChildValue.Types.Type.Numeric)
                {
                    dapVar.name = variable.Index.ToString();
                }
                else
                {
                    dapVar.name = variable.Name;
                }


                if (variable.Value.Variables != null)
                {
                    var varsRef = BackendVariableReference.FromDbg(state.Context, variable.Value.Variables);
                    var varsIdx = NextVariableReference++;
                    VariableRefs.Add(varsIdx, varsRef);
                    dapVar.variablesReference = MakeVariableRef(varsIdx);
                }

                variables.Add(dapVar);
            }

            var reply = new DAPVariablesResponse
            {
                variables = variables
            };

            DAP.Stream.SendReply(request, reply);
        }
Пример #14
0
        private void RequestStackVariables(DAPRequest request, DAPVariablesRequest msg, int threadId, int frameIndex, int scopeIndex)
        {
            var state = DAP.GetThread(threadId);

            if (!state.Stopped)
            {
                throw new RequestFailedException("Cannot get scopes when thread is not stopped");
            }

            if (frameIndex < 0 || frameIndex >= state.Stack.Count)
            {
                throw new RequestFailedException($"Requested variables for unknown frame {frameIndex}");
            }

            var varRef = new BackendVariableReference();

            varRef.Context     = state.Context;
            varRef.VariableRef = -1;
            varRef.Frame       = frameIndex;
            varRef.Local       = -1;
            uint seq = DAP.DbgCli.SendGetVariables(varRef);

            PendingGetVariablesRequests.Add(seq, (uint replySeq, StatusCode status, BkGetVariablesResponse response) =>
            {
                if (status == StatusCode.Success)
                {
                    // Filter locals/upvalues based on requested scope type
                    var results = response.Result.Where(result => ((result.Index >= 0) == (scopeIndex == 0))).ToList();
                    response.Result.Clear();
                    response.Result.AddRange(results);

                    OnVariablesReceived(request, msg, state, response);
                }
                else if (status == StatusCode.EvalFailed && response != null)
                {
                    DAP.Stream.SendReply(request, response.ErrorMessage);
                }
                else
                {
                    DAP.Stream.SendReply(request, $"Backend returned error: {status}");
                }
            });
        }
Пример #15
0
        private void HandleInitializeRequest(DAPRequest request, DAPInitializeRequest init)
        {
            var reply = new DAPCapabilities
            {
                supportsConfigurationDoneRequest = true,
                supportsEvaluateForHovers        = true,
                supportsModulesRequest           = true,
                supportsLoadedSourcesRequest     = true
            };

            Stream.SendReply(request, reply);

            var versionInfo = new DAPCustomVersionInfoEvent
            {
                version = DAPProtocolVersion
            };

            Stream.SendEvent("luaProtocolVersion", versionInfo);
        }
Пример #16
0
        public void OnDAPVariablesRequested(DAPRequest request, DAPVariablesRequest msg)
        {
            var variableType = RefToVariableType(msg.variablesReference);

            if (variableType == 0)
            {
                var index = RefToVariableIndex(msg.variablesReference);
                RequestBackendVariables(request, msg, index);
            }
            else if (variableType == 1)
            {
                var threadId   = RefToThreadId(msg.variablesReference);
                var frameIndex = RefToFrameIndex(msg.variablesReference);
                var scopeIndex = RefToScopeIndex(msg.variablesReference);
                RequestStackVariables(request, msg, threadId, frameIndex, scopeIndex);
            }
            else
            {
                throw new InvalidOperationException($"Unknown variables reference type: {variableType} (ref: {msg.variablesReference})");
            }
        }
Пример #17
0
        private void HandleThreadsRequest(DAPRequest request, DAPEmptyPayload msg)
        {
            var reply = new DAPThreadsResponse
            {
                threads = new List <DAPThread>()
            };

            reply.threads.Add(new DAPThread
            {
                id   = ServerThreadId,
                name = "Lua Server"
            });

            reply.threads.Add(new DAPThread
            {
                id   = ClientThreadId,
                name = "Lua Client"
            });

            Stream.SendReply(request, reply);
        }
Пример #18
0
        public void OnDAPEvaluateRequested(DAPRequest request, DAPEvaulateRequest req)
        {
            if (req.frameId == null)
            {
                throw new RequestFailedException("Cannot evaluate expressions in global scope");
            }

            var threadId   = req.frameId.Value >> 16;
            var frameIndex = req.frameId.Value & 0xffff;

            var state = DAP.GetThread(threadId);

            if (!state.Stopped)
            {
                throw new RequestFailedException("Can only evaluate expressions when stopped");
            }

            // TODO - evaluate in frame in later versions
            uint seq = DAP.DbgCli.SendEvaluate(state.Context, frameIndex, req.expression);

            PendingEvalRequests.Add(seq, (uint replySeq, StatusCode status, BkEvaluateResponse response) =>
            {
                if (status == StatusCode.Success)
                {
                    ReceivedEvaluateResponse(request, req, state, response);
                }
                else if (status == StatusCode.EvalFailed && response != null)
                {
                    DAP.Stream.SendReply(request, response.ErrorMessage);
                }
                else
                {
                    DAP.Stream.SendReply(request, $"Backend returned error: {status}");
                }
            });
        }
Пример #19
0
        private void HandleRequest(DAPRequest request)
        {
            switch (request.command)
            {
            case "initialize":
                HandleInitializeRequest(request, request.arguments as DAPInitializeRequest);
                break;

            case "launch":
                HandleLaunchRequest(request, request.arguments as DAPLaunchRequest);
                break;

            case "setBreakpoints":
                HandleSetBreakpointsRequest(request, request.arguments as DAPSetBreakpointsRequest);
                break;

            case "configurationDone":
                HandleConfigurationDoneRequest(request, request.arguments as DAPEmptyPayload);
                break;

            case "threads":
                HandleThreadsRequest(request, request.arguments as DAPEmptyPayload);
                break;

            case "stackTrace":
                HandleStackTraceRequest(request, request.arguments as DAPStackFramesRequest);
                break;

            case "scopes":
                HandleScopesRequest(request, request.arguments as DAPScopesRequest);
                break;

            case "variables":
                Evaluator.OnDAPVariablesRequested(request, request.arguments as DAPVariablesRequest);
                break;

            case "continue":
                HandleContinueRequest(request, request.arguments as DAPContinueRequest,
                                      DbgContinue.Types.Action.Continue);
                break;

            case "next":
                HandleContinueRequest(request, request.arguments as DAPContinueRequest,
                                      DbgContinue.Types.Action.StepOver);
                break;

            case "stepIn":
                HandleContinueRequest(request, request.arguments as DAPContinueRequest,
                                      DbgContinue.Types.Action.StepInto);
                break;

            case "stepOut":
                HandleContinueRequest(request, request.arguments as DAPContinueRequest,
                                      DbgContinue.Types.Action.StepOut);
                break;

            case "pause":
                HandleContinueRequest(request, request.arguments as DAPContinueRequest,
                                      DbgContinue.Types.Action.Pause);
                break;

            case "evaluate":
                Evaluator.OnDAPEvaluateRequested(request, request.arguments as DAPEvaulateRequest);
                break;

            case "source":
                HandleSourceRequest(request, request.arguments as DAPSourceRequest);
                break;

            case "modules":
                HandleModulesRequest(request, request.arguments as DAPModulesRequest);
                break;

            case "loadedSources":
                HandleLoadedSourcesRequest(request, request.arguments as DAPLoadedSourcesRequest);
                break;

            case "disconnect":
                HandleDisconnectRequest(request, request.arguments as DAPDisconnectRequest);
                break;

            default:
                throw new InvalidOperationException($"Unsupported DAP request: {request.command}");
            }
        }
Пример #20
0
        private void HandleStackTraceRequest(DAPRequest request, DAPStackFramesRequest msg)
        {
            var state = GetThread(msg.threadId);

            if (!state.Stopped)
            {
                throw new RequestFailedException("Cannot get stack when thread is not stopped");
            }

            int startFrame = msg.startFrame == null ? 0 : (int)msg.startFrame;
            int levels     = (msg.levels == null || msg.levels == 0) ? state.Stack.Count : (int)msg.levels;
            int lastFrame  = Math.Min(startFrame + levels, state.Stack.Count);

            // Count total sendable frames
            int numFrames = 0;

            foreach (var frame in state.Stack)
            {
                if (!Config.omitCppFrames || frame.Path != null)
                {
                    numFrames++;
                }
            }

            var frames = new List <DAPStackFrame>();

            for (var i = startFrame; i < lastFrame; i++)
            {
                var frame = state.Stack[i];
                if (Config.omitCppFrames && frame.Path == null)
                {
                    continue;
                }

                var dapFrame = new DAPStackFrame();
                dapFrame.id = (msg.threadId << 16) | i;
                // TODO DAPStackFrameFormat for name formatting
                dapFrame.name = frame.Function;
                if (frame.Path != null || frame.Source != null)
                {
                    dapFrame.source = new DAPSource
                    {
                        name = frame.Source,
                        path = frame.Path != null?frame.Path.Replace("/", "\\") : null
                    };
                    dapFrame.line   = frame.Line;
                    dapFrame.column = (frame.Line > 0) ? 1 : 0;
                }

                // TODO presentationHint
                frames.Add(dapFrame);
            }

            var reply = new DAPStackFramesResponse
            {
                stackFrames = frames,
                totalFrames = numFrames
            };

            Stream.SendReply(request, reply);
        }
Пример #21
0
 private void HandleConfigurationDoneRequest(DAPRequest request, DAPEmptyPayload msg)
 {
     Stream.SendReply(request, new DAPEmptyPayload());
 }