aelitashen created this revision.
aelitashen added reviewers: wallace, clayborg.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
aelitashen requested review of this revision.
Herald added a subscriber: JDevlieghere.
When turn on "Launch In Terminal" in IDE, the debugee will be launched inside
the integrated terminal so that user can input values for debugging. The
current version adds a response handler for the runInTerminal response from IDE
to lldb. lldb will attach the program after the response is received.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D84974
Files:
lldb/tools/lldb-vscode/lldb-vscode.cpp
Index: lldb/tools/lldb-vscode/lldb-vscode.cpp
===================================================================
--- lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -98,6 +98,7 @@
};
typedef void (*RequestCallback)(const llvm::json::Object &command);
+typedef void (*ResponseCallback)(const llvm::json::Object &command);
enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };
@@ -1357,6 +1358,8 @@
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);
@@ -1488,66 +1491,113 @@
return;
}
- // Instantiate a launch info instance for the target.
- auto launch_info = g_vsc.target.GetLaunchInfo();
-
- // Grab the current working directory if there is one and set it in the
- // launch info.
- const auto cwd = GetString(arguments, "cwd");
- if (!cwd.empty())
- launch_info.SetWorkingDirectory(cwd.data());
-
- // Extract any extra arguments and append them to our program arguments for
- // when we launch
- auto args = GetStrings(arguments, "args");
- if (!args.empty())
- launch_info.SetArguments(MakeArgv(args).data(), true);
-
- // Pass any environment variables along that the user specified.
- auto envs = GetStrings(arguments, "env");
- if (!envs.empty())
- launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
-
- auto flags = launch_info.GetLaunchFlags();
-
- if (GetBoolean(arguments, "disableASLR", true))
- flags |= lldb::eLaunchFlagDisableASLR;
- if (GetBoolean(arguments, "disableSTDIO", false))
- flags |= lldb::eLaunchFlagDisableSTDIO;
- if (GetBoolean(arguments, "shellExpandArguments", false))
- flags |= lldb::eLaunchFlagShellExpandArguments;
- const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
- launch_info.SetDetachOnError(detatchOnError);
- launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
- lldb::eLaunchFlagStopAtEntry);
-
- // Run any pre run LLDB commands the user specified in the launch.json
- g_vsc.RunPreRunCommands();
- if (launchCommands.empty()) {
- // Disable async events so the launch will be successful when we return from
- // the launch call and the launch will happen synchronously
- g_vsc.debugger.SetAsync(false);
- g_vsc.target.Launch(launch_info, error);
- g_vsc.debugger.SetAsync(true);
+ if (GetBoolean(arguments, "launchInTerminal", false)) {
+ llvm::json::Object reverseRequest;
+ reverseRequest.try_emplace("type", "request");
+ reverseRequest.try_emplace("command", "runInTerminal");
+ reverseRequest.try_emplace("seq", 100);
+ llvm::json::Object runInTerminalArgs;
+ runInTerminalArgs.try_emplace("kind", "integrated");
+ runInTerminalArgs.try_emplace("cwd", GetString(arguments, "cwd"));
+ std::vector<std::string> commands = GetStrings(arguments, "args");
+ commands.insert(commands.begin(), std::string(GetString(arguments, "program").data()));
+ runInTerminalArgs.try_emplace("args", commands);
+ std::vector<std::string> envVars = GetStrings(arguments, "env");
+ llvm::json::Object environment;
+ for(std::string envVar : envVars) {
+ size_t ind = envVar.find("=");
+ environment.try_emplace(envVar.substr(0, ind), envVar.substr(ind+1));
+ }
+ runInTerminalArgs.try_emplace("env", llvm::json::Value(std::move(environment)));
+ reverseRequest.try_emplace("arguments", llvm::json::Value(std::move(runInTerminalArgs)));
+ g_vsc.SendJSON(llvm::json::Value(std::move(reverseRequest)));
+ // g_vsc.SendJSON(llvm::json::Value(std::move(response)));
} else {
- g_vsc.RunLLDBCommands("Running launchCommands:", launchCommands);
- // The custom commands might have created a new target so we should use the
- // selected target after these commands are run.
- g_vsc.target = g_vsc.debugger.GetSelectedTarget();
+ // Instantiate a launch info instance for the target.
+ auto launch_info = g_vsc.target.GetLaunchInfo();
+
+ // Grab the current working directory if there is one and set it in the
+ // launch info.
+ const auto cwd = GetString(arguments, "cwd");
+ if (!cwd.empty())
+ launch_info.SetWorkingDirectory(cwd.data());
+
+ // Extract any extra arguments and append them to our program arguments for
+ // when we launch
+ auto args = GetStrings(arguments, "args");
+ if (!args.empty())
+ launch_info.SetArguments(MakeArgv(args).data(), true);
+
+ // Pass any environment variables along that the user specified.
+ auto envs = GetStrings(arguments, "env");
+ if (!envs.empty())
+ launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
+
+ auto flags = launch_info.GetLaunchFlags();
+
+ if (GetBoolean(arguments, "disableASLR", true))
+ flags |= lldb::eLaunchFlagDisableASLR;
+ if (GetBoolean(arguments, "disableSTDIO", false))
+ flags |= lldb::eLaunchFlagDisableSTDIO;
+ if (GetBoolean(arguments, "shellExpandArguments", false))
+ flags |= lldb::eLaunchFlagShellExpandArguments;
+ const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
+ launch_info.SetDetachOnError(detatchOnError);
+ launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
+ lldb::eLaunchFlagStopAtEntry);
+
+ // Run any pre run LLDB commands the user specified in the launch.json
+ g_vsc.RunPreRunCommands();
+ if (launchCommands.empty()) {
+ // Disable async events so the launch will be successful when we return from
+ // the launch call and the launch will happen synchronously
+ g_vsc.debugger.SetAsync(false);
+ g_vsc.target.Launch(launch_info, error);
+ g_vsc.debugger.SetAsync(true);
+ } else {
+ g_vsc.RunLLDBCommands("Running launchCommands:", launchCommands);
+ // The custom commands might have created a new target so we should use the
+ // selected target after these commands are run.
+ g_vsc.target = g_vsc.debugger.GetSelectedTarget();
+ }
+
+ if (error.Fail()) {
+ response["success"] = llvm::json::Value(false);
+ EmplaceSafeString(response, "message", std::string(error.GetCString()));
+ }
+
+ g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+ SendProcessEvent(Launch);
+ g_vsc.SendJSON(llvm::json::Value(CreateEventObject("initialized")));
}
+ // Reenable async events and start the event thread to catch async events.
+ // g_vsc.debugger.SetAsync(true);
+}
+void response_runInTerminal(const llvm::json::Object &reverseRequest) {
+ g_vsc.is_attach = true;
+ llvm::json::Object response;
+ lldb::SBError error;
+ FillResponse(reverseRequest, response);
+ lldb::SBAttachInfo attach_info;
+ g_vsc.target.Attach(attach_info, error);
+ if (error.Success()) {
+ auto attached_pid = g_vsc.target.GetProcess().GetProcessID();
+ if (attached_pid == LLDB_INVALID_PROCESS_ID) {
+ error.SetErrorString("Failed to attach to a process");
+ }
+ }
if (error.Fail()) {
response["success"] = llvm::json::Value(false);
EmplaceSafeString(response, "message", std::string(error.GetCString()));
}
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
-
- SendProcessEvent(Launch);
- g_vsc.SendJSON(llvm::json::Value(CreateEventObject("initialized")));
- // Reenable async events and start the event thread to catch async events.
- // g_vsc.debugger.SetAsync(true);
+ if (error.Success()) {
+ SendProcessEvent(Attach);
+ g_vsc.SendJSON(CreateEventObject("initialized"));
+ // SendThreadStoppedEvent();
+ }
}
-
// "NextRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
@@ -2849,6 +2899,17 @@
return g_request_handlers;
}
+const std::map<std::string, ResponseCallback> &GetResponseHandlers() {
+#define RESPONSE_CALLBACK(name) \
+ { #name, response_##name }
+ static std::map<std::string, ResponseCallback> g_response_handlers = {
+ // VSCode Debug Adaptor response to reverse request
+ RESPONSE_CALLBACK(runInTerminal),
+ };
+#undef RESPONSE_CALLBACK
+ return g_response_handlers;
+}
+
} // anonymous namespace
static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) {
@@ -2961,6 +3022,17 @@
*g_vsc.log << "error: unhandled command \"" << command.data() << std::endl;
return 1;
}
+ } else if (packet_type == "response") {
+ auto response_handlers = GetResponseHandlers();
+ const auto command = GetString(object, "command");
+ auto handler_pos = response_handlers.find("runInTerminal");
+ if (handler_pos != response_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;
}
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits