forked from OSchip/llvm-project
Retry of D84974
- Fix a small issue caused by a conflicting name (GetObject) on Windows. The fix was to rename the internal GetObject function to GetNextFunction.
This commit is contained in:
parent
4ff4708d39
commit
132e57bc59
|
@ -282,7 +282,7 @@ class VSCodeTestCaseBase(TestBase):
|
|||
trace=False, initCommands=None, preRunCommands=None,
|
||||
stopCommands=None, exitCommands=None, terminateCommands=None,
|
||||
sourcePath=None, debuggerRoot=None, launchCommands=None,
|
||||
sourceMap=None, disconnectAutomatically=True):
|
||||
sourceMap=None, disconnectAutomatically=True, runInTerminal=False):
|
||||
'''Sending launch request to vscode
|
||||
'''
|
||||
|
||||
|
@ -316,10 +316,16 @@ class VSCodeTestCaseBase(TestBase):
|
|||
sourcePath=sourcePath,
|
||||
debuggerRoot=debuggerRoot,
|
||||
launchCommands=launchCommands,
|
||||
sourceMap=sourceMap)
|
||||
sourceMap=sourceMap,
|
||||
runInTerminal=runInTerminal)
|
||||
if not (response and response['success']):
|
||||
self.assertTrue(response['success'],
|
||||
'launch failed (%s)' % (response['message']))
|
||||
# We need to trigger a request_configurationDone after we've successfully
|
||||
# attached a runInTerminal process to finish initialization.
|
||||
if runInTerminal:
|
||||
self.vscode.request_configurationDone()
|
||||
|
||||
|
||||
def build_and_launch(self, program, args=None, cwd=None, env=None,
|
||||
stopOnEntry=False, disableASLR=True,
|
||||
|
@ -327,7 +333,7 @@ class VSCodeTestCaseBase(TestBase):
|
|||
trace=False, initCommands=None, preRunCommands=None,
|
||||
stopCommands=None, exitCommands=None,
|
||||
terminateCommands=None, sourcePath=None,
|
||||
debuggerRoot=None):
|
||||
debuggerRoot=None, runInTerminal=False):
|
||||
'''Build the default Makefile target, create the VSCode debug adaptor,
|
||||
and launch the process.
|
||||
'''
|
||||
|
@ -337,4 +343,4 @@ class VSCodeTestCaseBase(TestBase):
|
|||
self.launch(program, args, cwd, env, stopOnEntry, disableASLR,
|
||||
disableSTDIO, shellExpandArguments, trace,
|
||||
initCommands, preRunCommands, stopCommands, exitCommands,
|
||||
terminateCommands, sourcePath, debuggerRoot)
|
||||
terminateCommands, sourcePath, debuggerRoot, runInTerminal=runInTerminal)
|
||||
|
|
|
@ -300,12 +300,29 @@ class DebugCommunication(object):
|
|||
self.send_packet(command)
|
||||
done = False
|
||||
while not done:
|
||||
response = self.recv_packet(filter_type='response')
|
||||
if response is None:
|
||||
response_or_request = self.recv_packet(filter_type=['response', 'request'])
|
||||
if response_or_request is None:
|
||||
desc = 'no response for "%s"' % (command['command'])
|
||||
raise ValueError(desc)
|
||||
self.validate_response(command, response)
|
||||
return response
|
||||
if response_or_request['type'] == 'response':
|
||||
self.validate_response(command, response_or_request)
|
||||
return response_or_request
|
||||
else:
|
||||
if response_or_request['command'] == 'runInTerminal':
|
||||
subprocess.Popen(response_or_request['arguments']['args'],
|
||||
env=response_or_request['arguments']['env'])
|
||||
self.send_packet({
|
||||
"type": "response",
|
||||
"seq": -1,
|
||||
"request_seq": response_or_request['seq'],
|
||||
"success": True,
|
||||
"command": "runInTerminal",
|
||||
"body": {}
|
||||
}, set_sequence=False)
|
||||
else:
|
||||
desc = 'unkonwn reverse request "%s"' % (response_or_request['command'])
|
||||
raise ValueError(desc)
|
||||
|
||||
return None
|
||||
|
||||
def wait_for_event(self, filter=None, timeout=None):
|
||||
|
@ -599,7 +616,8 @@ class DebugCommunication(object):
|
|||
trace=False, initCommands=None, preRunCommands=None,
|
||||
stopCommands=None, exitCommands=None,
|
||||
terminateCommands=None ,sourcePath=None,
|
||||
debuggerRoot=None, launchCommands=None, sourceMap=None):
|
||||
debuggerRoot=None, launchCommands=None, sourceMap=None,
|
||||
runInTerminal=False):
|
||||
args_dict = {
|
||||
'program': program
|
||||
}
|
||||
|
@ -638,6 +656,8 @@ class DebugCommunication(object):
|
|||
args_dict['launchCommands'] = launchCommands
|
||||
if sourceMap:
|
||||
args_dict['sourceMap'] = sourceMap
|
||||
if runInTerminal:
|
||||
args_dict['runInTerminal'] = runInTerminal
|
||||
command_dict = {
|
||||
'command': 'launch',
|
||||
'type': 'request',
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
C_SOURCES := main.c
|
||||
|
||||
include Makefile.rules
|
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
Test lldb-vscode runInTerminal reverse request
|
||||
"""
|
||||
|
||||
|
||||
import unittest2
|
||||
import vscode
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
import lldbvscode_testcase
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
class TestVSCode_runInTerminal(lldbvscode_testcase.VSCodeTestCaseBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@skipUnlessDarwin
|
||||
@skipIfRemote
|
||||
def test_runInTerminal(self):
|
||||
'''
|
||||
Tests the "runInTerminal" reverse request. It makes sure that the IDE can
|
||||
launch the inferior with the correct environment variables and arguments.
|
||||
'''
|
||||
program = self.getBuildArtifact("a.out")
|
||||
source = 'main.c'
|
||||
self.build_and_launch(program, stopOnEntry=True, runInTerminal=True, args=["foobar"], env=["FOO=bar"])
|
||||
breakpoint_line = line_number(source, '// breakpoint')
|
||||
|
||||
self.set_source_breakpoints(source, [breakpoint_line])
|
||||
self.continue_to_next_stop()
|
||||
|
||||
# We verify we actually stopped inside the loop
|
||||
counter = int(self.vscode.get_local_variable_value('counter'))
|
||||
self.assertTrue(counter > 0)
|
||||
|
||||
# We verify we were able to set the launch arguments
|
||||
argc = int(self.vscode.get_local_variable_value('argc'))
|
||||
self.assertEqual(argc, 2)
|
||||
|
||||
argv1 = self.vscode.request_evaluate('argv[1]')['body']['result']
|
||||
self.assertIn('foobar', argv1)
|
||||
|
||||
# We verify we were able to set the environment
|
||||
env = self.vscode.request_evaluate('foo')['body']['result']
|
||||
self.assertIn('bar', env)
|
|
@ -0,0 +1,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *foo = getenv("FOO");
|
||||
for (int counter = 1;; counter++) {
|
||||
sleep(1); // breakpoint
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -998,4 +998,44 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit) {
|
|||
return llvm::json::Value(std::move(object));
|
||||
}
|
||||
|
||||
/// See
|
||||
/// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
|
||||
llvm::json::Object
|
||||
CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request) {
|
||||
llvm::json::Object reverse_request;
|
||||
reverse_request.try_emplace("type", "request");
|
||||
reverse_request.try_emplace("command", "runInTerminal");
|
||||
|
||||
llvm::json::Object run_in_terminal_args;
|
||||
// This indicates the IDE to open an embedded terminal, instead of opening the
|
||||
// terminal in a new window.
|
||||
run_in_terminal_args.try_emplace("kind", "integrated");
|
||||
|
||||
auto launch_request_arguments = launch_request.getObject("arguments");
|
||||
std::vector<std::string> args = GetStrings(launch_request_arguments, "args");
|
||||
// The program path must be the first entry in the "args" field
|
||||
args.insert(args.begin(),
|
||||
GetString(launch_request_arguments, "program").str());
|
||||
run_in_terminal_args.try_emplace("args", args);
|
||||
|
||||
const auto cwd = GetString(launch_request_arguments, "cwd");
|
||||
if (!cwd.empty())
|
||||
run_in_terminal_args.try_emplace("cwd", cwd);
|
||||
|
||||
// We need to convert the input list of environments variables into a
|
||||
// dictionary
|
||||
std::vector<std::string> envs = GetStrings(launch_request_arguments, "env");
|
||||
llvm::json::Object environment;
|
||||
for (const std::string &env : envs) {
|
||||
size_t index = env.find("=");
|
||||
environment.try_emplace(env.substr(0, index), env.substr(index + 1));
|
||||
}
|
||||
run_in_terminal_args.try_emplace("env",
|
||||
llvm::json::Value(std::move(environment)));
|
||||
|
||||
reverse_request.try_emplace(
|
||||
"arguments", llvm::json::Value(std::move(run_in_terminal_args)));
|
||||
return reverse_request;
|
||||
}
|
||||
|
||||
} // namespace lldb_vscode
|
||||
|
|
|
@ -443,6 +443,18 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
|
|||
|
||||
llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit);
|
||||
|
||||
/// Create a runInTerminal reverse request object
|
||||
///
|
||||
/// \param[in] launch_request
|
||||
/// The original launch_request object whose fields are used to construct
|
||||
/// the reverse request object.
|
||||
///
|
||||
/// \return
|
||||
/// A "runInTerminal" JSON object that follows the specification outlined by
|
||||
/// Microsoft.
|
||||
llvm::json::Object
|
||||
CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request);
|
||||
|
||||
} // namespace lldb_vscode
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,8 @@ VSCode::VSCode()
|
|||
{"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift},
|
||||
{"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}),
|
||||
focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false),
|
||||
stop_at_entry(false), is_attach(false) {
|
||||
stop_at_entry(false), is_attach(false),
|
||||
reverse_request_seq(0), waiting_for_run_in_terminal(false) {
|
||||
const char *log_file_path = getenv("LLDBVSCODE_LOG");
|
||||
#if defined(_WIN32)
|
||||
// Windows opens stdout and stdin in text mode which converts \n to 13,10
|
||||
|
@ -362,4 +363,71 @@ void VSCode::SetTarget(const lldb::SBTarget target) {
|
|||
}
|
||||
}
|
||||
|
||||
PacketStatus VSCode::GetNextObject(llvm::json::Object &object) {
|
||||
std::string json = ReadJSON();
|
||||
if (json.empty())
|
||||
return PacketStatus::EndOfFile;
|
||||
|
||||
llvm::StringRef json_sref(json);
|
||||
llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
|
||||
if (!json_value) {
|
||||
auto error = json_value.takeError();
|
||||
if (log) {
|
||||
std::string error_str;
|
||||
llvm::raw_string_ostream strm(error_str);
|
||||
strm << error;
|
||||
strm.flush();
|
||||
*log << "error: failed to parse JSON: " << error_str << std::endl
|
||||
<< json << std::endl;
|
||||
}
|
||||
return PacketStatus::JSONMalformed;
|
||||
}
|
||||
object = *json_value->getAsObject();
|
||||
if (!json_value->getAsObject()) {
|
||||
if (log)
|
||||
*log << "error: json packet isn't a object" << std::endl;
|
||||
return PacketStatus::JSONNotObject;
|
||||
}
|
||||
return PacketStatus::Success;
|
||||
}
|
||||
|
||||
bool VSCode::HandleObject(const llvm::json::Object &object) {
|
||||
const auto packet_type = GetString(object, "type");
|
||||
if (packet_type == "request") {
|
||||
const auto command = GetString(object, "command");
|
||||
auto handler_pos = request_handlers.find(std::string(command));
|
||||
if (handler_pos != request_handlers.end()) {
|
||||
handler_pos->second(object);
|
||||
return true; // Success
|
||||
} else {
|
||||
if (log)
|
||||
*log << "error: unhandled command \"" << command.data() << std::endl;
|
||||
return false; // Fail
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketStatus VSCode::SendReverseRequest(llvm::json::Object request,
|
||||
llvm::json::Object &response) {
|
||||
request.try_emplace("seq", ++reverse_request_seq);
|
||||
SendJSON(llvm::json::Value(std::move(request)));
|
||||
while (true) {
|
||||
PacketStatus status = GetNextObject(response);
|
||||
const auto packet_type = GetString(response, "type");
|
||||
if (packet_type == "response")
|
||||
return status;
|
||||
else {
|
||||
// Not our response, we got another packet
|
||||
HandleObject(response);
|
||||
}
|
||||
}
|
||||
return PacketStatus::EndOfFile;
|
||||
}
|
||||
|
||||
void VSCode::RegisterRequestCallback(std::string request,
|
||||
RequestCallback callback) {
|
||||
request_handlers[request] = callback;
|
||||
}
|
||||
|
||||
} // namespace lldb_vscode
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef LLDB_TOOLS_LLDB_VSCODE_VSCODE_H
|
||||
#define LLDB_TOOLS_LLDB_VSCODE_VSCODE_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "lldb/API/SBAttachInfo.h"
|
||||
|
@ -65,6 +67,15 @@ enum class OutputType { Console, Stdout, Stderr, Telemetry };
|
|||
|
||||
enum VSCodeBroadcasterBits { eBroadcastBitStopEventThread = 1u << 0 };
|
||||
|
||||
typedef void (*RequestCallback)(const llvm::json::Object &command);
|
||||
|
||||
enum class PacketStatus {
|
||||
Success = 0,
|
||||
EndOfFile,
|
||||
JSONMalformed,
|
||||
JSONNotObject
|
||||
};
|
||||
|
||||
struct VSCode {
|
||||
InputStream input;
|
||||
OutputStream output;
|
||||
|
@ -91,6 +102,10 @@ struct VSCode {
|
|||
bool sent_terminated_event;
|
||||
bool stop_at_entry;
|
||||
bool is_attach;
|
||||
uint32_t reverse_request_seq;
|
||||
std::map<std::string, RequestCallback> request_handlers;
|
||||
std::condition_variable request_in_terminal_cv;
|
||||
bool waiting_for_run_in_terminal;
|
||||
// Keep track of the last stop thread index IDs as threads won't go away
|
||||
// unless we send a "thread" event to indicate the thread exited.
|
||||
llvm::DenseSet<lldb::tid_t> thread_ids;
|
||||
|
@ -152,6 +167,36 @@ struct VSCode {
|
|||
/// Set given target object as a current target for lldb-vscode and start
|
||||
/// listeing for its breakpoint events.
|
||||
void SetTarget(const lldb::SBTarget target);
|
||||
|
||||
const std::map<std::string, RequestCallback> &GetRequestHandlers();
|
||||
|
||||
PacketStatus GetNextObject(llvm::json::Object &object);
|
||||
bool HandleObject(const llvm::json::Object &object);
|
||||
|
||||
/// Send a Debug Adapter Protocol reverse request to the IDE
|
||||
///
|
||||
/// \param[in] request
|
||||
/// The payload of the request to send.
|
||||
///
|
||||
/// \param[out] response
|
||||
/// The response of the IDE. It might be undefined if there was an error.
|
||||
///
|
||||
/// \return
|
||||
/// A \a PacketStatus object indicating the sucess or failure of the
|
||||
/// request.
|
||||
PacketStatus SendReverseRequest(llvm::json::Object request,
|
||||
llvm::json::Object &response);
|
||||
|
||||
/// Registers a callback handler for a Debug Adapter Protocol request
|
||||
///
|
||||
/// \param[in] request
|
||||
/// The name of the request following the Debug Adapter Protocol
|
||||
/// specification.
|
||||
///
|
||||
/// \param[in] callback
|
||||
/// The callback to execute when the given request is triggered by the
|
||||
/// IDE.
|
||||
void RegisterRequestCallback(std::string request, RequestCallback callback);
|
||||
};
|
||||
|
||||
extern VSCode g_vsc;
|
||||
|
|
|
@ -384,7 +384,12 @@ void EventThreadFunction() {
|
|||
break;
|
||||
case lldb::eStateSuspended:
|
||||
break;
|
||||
case lldb::eStateStopped:
|
||||
case lldb::eStateStopped: {
|
||||
if (g_vsc.waiting_for_run_in_terminal) {
|
||||
g_vsc.waiting_for_run_in_terminal = false;
|
||||
g_vsc.request_in_terminal_cv.notify_one();
|
||||
}
|
||||
}
|
||||
// Only report a stopped event if the process was not restarted.
|
||||
if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
|
||||
SendStdOutStdErr(process);
|
||||
|
@ -1374,6 +1379,9 @@ void request_initialize(const llvm::json::Object &request) {
|
|||
filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
|
||||
}
|
||||
body.try_emplace("exceptionBreakpointFilters", std::move(filters));
|
||||
// The debug adapter supports launching a debugee in intergrated VSCode
|
||||
// terminal.
|
||||
body.try_emplace("supportsRunInTerminalRequest", true);
|
||||
// The debug adapter supports stepping back via the stepBack and
|
||||
// reverseContinue requests.
|
||||
body.try_emplace("supportsStepBack", false);
|
||||
|
@ -1433,6 +1441,49 @@ void request_initialize(const llvm::json::Object &request) {
|
|||
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
|
||||
}
|
||||
|
||||
void request_runInTerminal(const llvm::json::Object &launch_request,
|
||||
llvm::json::Object &launch_response) {
|
||||
// We have already created a target that has a valid "program" path to the
|
||||
// executable. We will attach to the next process whose name matches that
|
||||
// of the target's.
|
||||
g_vsc.is_attach = true;
|
||||
lldb::SBAttachInfo attach_info;
|
||||
lldb::SBError error;
|
||||
attach_info.SetWaitForLaunch(true, /*async*/ true);
|
||||
g_vsc.target.Attach(attach_info, error);
|
||||
|
||||
llvm::json::Object reverse_request =
|
||||
CreateRunInTerminalReverseRequest(launch_request);
|
||||
llvm::json::Object reverse_response;
|
||||
lldb_vscode::PacketStatus status =
|
||||
g_vsc.SendReverseRequest(reverse_request, reverse_response);
|
||||
if (status != lldb_vscode::PacketStatus::Success)
|
||||
error.SetErrorString("Process cannot be launched by IDE.");
|
||||
|
||||
if (error.Success()) {
|
||||
// Wait for the attach stop event to happen or for a timeout.
|
||||
g_vsc.waiting_for_run_in_terminal = true;
|
||||
static std::mutex mutex;
|
||||
std::unique_lock<std::mutex> locker(mutex);
|
||||
g_vsc.request_in_terminal_cv.wait_for(locker, std::chrono::seconds(10));
|
||||
|
||||
auto attached_pid = g_vsc.target.GetProcess().GetProcessID();
|
||||
if (attached_pid == LLDB_INVALID_PROCESS_ID)
|
||||
error.SetErrorString("Failed to attach to a process");
|
||||
else
|
||||
SendProcessEvent(Attach);
|
||||
}
|
||||
|
||||
if (error.Fail()) {
|
||||
launch_response["success"] = llvm::json::Value(false);
|
||||
EmplaceSafeString(launch_response, "message",
|
||||
std::string(error.GetCString()));
|
||||
} else {
|
||||
launch_response["success"] = llvm::json::Value(true);
|
||||
g_vsc.SendJSON(CreateEventObject("initialized"));
|
||||
}
|
||||
}
|
||||
|
||||
// "LaunchRequest": {
|
||||
// "allOf": [ { "$ref": "#/definitions/Request" }, {
|
||||
// "type": "object",
|
||||
|
@ -1505,6 +1556,12 @@ void request_launch(const llvm::json::Object &request) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (GetBoolean(arguments, "runInTerminal", false)) {
|
||||
request_runInTerminal(request, response);
|
||||
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiate a launch info instance for the target.
|
||||
auto launch_info = g_vsc.target.GetLaunchInfo();
|
||||
|
||||
|
@ -2831,39 +2888,35 @@ void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
|
|||
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
|
||||
}
|
||||
|
||||
const std::map<std::string, RequestCallback> &GetRequestHandlers() {
|
||||
#define REQUEST_CALLBACK(name) \
|
||||
{ #name, request_##name }
|
||||
static std::map<std::string, RequestCallback> g_request_handlers = {
|
||||
// VSCode Debug Adaptor requests
|
||||
REQUEST_CALLBACK(attach),
|
||||
REQUEST_CALLBACK(completions),
|
||||
REQUEST_CALLBACK(continue),
|
||||
REQUEST_CALLBACK(configurationDone),
|
||||
REQUEST_CALLBACK(disconnect),
|
||||
REQUEST_CALLBACK(evaluate),
|
||||
REQUEST_CALLBACK(exceptionInfo),
|
||||
REQUEST_CALLBACK(getCompileUnits),
|
||||
REQUEST_CALLBACK(initialize),
|
||||
REQUEST_CALLBACK(launch),
|
||||
REQUEST_CALLBACK(next),
|
||||
REQUEST_CALLBACK(pause),
|
||||
REQUEST_CALLBACK(scopes),
|
||||
REQUEST_CALLBACK(setBreakpoints),
|
||||
REQUEST_CALLBACK(setExceptionBreakpoints),
|
||||
REQUEST_CALLBACK(setFunctionBreakpoints),
|
||||
REQUEST_CALLBACK(setVariable),
|
||||
REQUEST_CALLBACK(source),
|
||||
REQUEST_CALLBACK(stackTrace),
|
||||
REQUEST_CALLBACK(stepIn),
|
||||
REQUEST_CALLBACK(stepOut),
|
||||
REQUEST_CALLBACK(threads),
|
||||
REQUEST_CALLBACK(variables),
|
||||
// Testing requests
|
||||
REQUEST_CALLBACK(_testGetTargetBreakpoints),
|
||||
};
|
||||
#undef REQUEST_CALLBACK
|
||||
return g_request_handlers;
|
||||
void RegisterRequestCallbacks() {
|
||||
g_vsc.RegisterRequestCallback("attach", request_attach);
|
||||
g_vsc.RegisterRequestCallback("completions", request_completions);
|
||||
g_vsc.RegisterRequestCallback("continue", request_continue);
|
||||
g_vsc.RegisterRequestCallback("configurationDone", request_configurationDone);
|
||||
g_vsc.RegisterRequestCallback("disconnect", request_disconnect);
|
||||
g_vsc.RegisterRequestCallback("evaluate", request_evaluate);
|
||||
g_vsc.RegisterRequestCallback("exceptionInfo", request_exceptionInfo);
|
||||
g_vsc.RegisterRequestCallback("getCompileUnits", request_getCompileUnits);
|
||||
g_vsc.RegisterRequestCallback("initialize", request_initialize);
|
||||
g_vsc.RegisterRequestCallback("launch", request_launch);
|
||||
g_vsc.RegisterRequestCallback("next", request_next);
|
||||
g_vsc.RegisterRequestCallback("pause", request_pause);
|
||||
g_vsc.RegisterRequestCallback("scopes", request_scopes);
|
||||
g_vsc.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
|
||||
g_vsc.RegisterRequestCallback("setExceptionBreakpoints",
|
||||
request_setExceptionBreakpoints);
|
||||
g_vsc.RegisterRequestCallback("setFunctionBreakpoints",
|
||||
request_setFunctionBreakpoints);
|
||||
g_vsc.RegisterRequestCallback("setVariable", request_setVariable);
|
||||
g_vsc.RegisterRequestCallback("source", request_source);
|
||||
g_vsc.RegisterRequestCallback("stackTrace", request_stackTrace);
|
||||
g_vsc.RegisterRequestCallback("stepIn", request_stepIn);
|
||||
g_vsc.RegisterRequestCallback("stepOut", request_stepOut);
|
||||
g_vsc.RegisterRequestCallback("threads", request_threads);
|
||||
g_vsc.RegisterRequestCallback("variables", request_variables);
|
||||
// Testing requests
|
||||
g_vsc.RegisterRequestCallback("_testGetTargetBreakpoints",
|
||||
request__testGetTargetBreakpoints);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -2895,6 +2948,8 @@ int main(int argc, char *argv[]) {
|
|||
// Initialize LLDB first before we do anything.
|
||||
lldb::SBDebugger::Initialize();
|
||||
|
||||
RegisterRequestCallbacks();
|
||||
|
||||
int portno = -1;
|
||||
|
||||
LLDBVSCodeOptTable T;
|
||||
|
@ -2937,49 +2992,17 @@ int main(int argc, char *argv[]) {
|
|||
g_vsc.output.descriptor =
|
||||
StreamDescriptor::from_file(fileno(stdout), false);
|
||||
}
|
||||
auto request_handlers = GetRequestHandlers();
|
||||
uint32_t packet_idx = 0;
|
||||
while (!g_vsc.sent_terminated_event) {
|
||||
std::string json = g_vsc.ReadJSON();
|
||||
if (json.empty())
|
||||
llvm::json::Object object;
|
||||
lldb_vscode::PacketStatus status = g_vsc.GetObject(object);
|
||||
if (status == lldb_vscode::PacketStatus::EndOfFile)
|
||||
break;
|
||||
if (status != lldb_vscode::PacketStatus::Success)
|
||||
return 1; // Fatal error
|
||||
|
||||
llvm::StringRef json_sref(json);
|
||||
llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
|
||||
if (!json_value) {
|
||||
auto error = json_value.takeError();
|
||||
if (g_vsc.log) {
|
||||
std::string error_str;
|
||||
llvm::raw_string_ostream strm(error_str);
|
||||
strm << error;
|
||||
strm.flush();
|
||||
|
||||
*g_vsc.log << "error: failed to parse JSON: " << error_str << std::endl
|
||||
<< json << std::endl;
|
||||
}
|
||||
if (!g_vsc.HandleObject(object))
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto object = json_value->getAsObject();
|
||||
if (!object) {
|
||||
if (g_vsc.log)
|
||||
*g_vsc.log << "error: json packet isn't a object" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto packet_type = GetString(object, "type");
|
||||
if (packet_type == "request") {
|
||||
const auto command = GetString(object, "command");
|
||||
auto handler_pos = request_handlers.find(std::string(command));
|
||||
if (handler_pos != request_handlers.end()) {
|
||||
handler_pos->second(*object);
|
||||
} else {
|
||||
if (g_vsc.log)
|
||||
*g_vsc.log << "error: unhandled command \"" << command.data()
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
++packet_idx;
|
||||
}
|
||||
|
||||
|
|
|
@ -175,6 +175,11 @@
|
|||
"type": "array",
|
||||
"description": "Commands executed at the end of debugging session.",
|
||||
"default": []
|
||||
},
|
||||
"runInTerminal": {
|
||||
"type": "boolean",
|
||||
"description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue