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}"); } }); }
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); }
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); }
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); }
private void HandleDisconnectRequest(DAPRequest request, DAPDisconnectRequest msg) { var reply = new DAPEmptyPayload(); Stream.SendReply(request, reply); // TODO - close session }
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); }
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); }
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); }
private void HandleLoadedSourcesRequest(DAPRequest request, DAPLoadedSourcesRequest req) { var reply = new DAPLoadedSourcesResponse { sources = SourceFiles.Select(source => new DAPSource { path = source }).ToList() }; Stream.SendReply(request, reply); }
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); }
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); }
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); }
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); }
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}"); } }); }
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); }
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})"); } }
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); }
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}"); } }); }
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}"); } }
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); }
private void HandleConfigurationDoneRequest(DAPRequest request, DAPEmptyPayload msg) { Stream.SendReply(request, new DAPEmptyPayload()); }