[Lldb-commits] [PATCH] D141626: [lldb-vscode] Include the return value in 'local' variables
ivanhernandez13 created this revision. Herald added a project: All. ivanhernandez13 requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits. This provides a convenient way for the user to easily inspect a functions return value after stepping out of a function. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D141626 Files: lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py lldb/tools/lldb-vscode/JSONUtils.cpp lldb/tools/lldb-vscode/JSONUtils.h 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 @@ -2960,6 +2960,19 @@ reg.SetFormat(lldb::eFormatAddressInfo); } } +} else if (variablesReference == VARREF_LOCALS) { + auto return_value = + g_vsc.target.GetProcess().GetSelectedThread().GetStopReturnValue(); + if (return_value.IsValid()) { +int64_t var_ref = 0; +if (return_value.MightHaveChildren()) { + var_ref = g_vsc.variables.InsertExpandableVariable( + return_value, /*is_permanent=*/false); +} +variables.emplace_back(CreateVariable( +return_value, var_ref, var_ref != 0 ? var_ref : UINT64_MAX, hex, +/*is_name_duplicated=*/false, "Return value")); + } } num_children = top_scope->GetSize(); Index: lldb/tools/lldb-vscode/JSONUtils.h === --- lldb/tools/lldb-vscode/JSONUtils.h +++ lldb/tools/lldb-vscode/JSONUtils.h @@ -457,12 +457,17 @@ /// As VSCode doesn't render two of more variables with the same name, we /// apply a suffix to distinguish duplicated variables. /// +/// \param[in] name_override +/// A name to give the variable when a predetermined name is known. +/// Otherwise, the name is derived from the variable. +/// /// \return /// A "Variable" JSON object with that follows the formal JSON /// definition outlined by Microsoft. llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, int64_t varID, bool format_hex, - bool is_name_duplicated = false); + bool is_name_duplicated = false, + const char *name_override = nullptr); llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit); Index: lldb/tools/lldb-vscode/JSONUtils.cpp === --- lldb/tools/lldb-vscode/JSONUtils.cpp +++ lldb/tools/lldb-vscode/JSONUtils.cpp @@ -1034,10 +1034,13 @@ // } llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, int64_t varID, bool format_hex, - bool is_name_duplicated) { + bool is_name_duplicated, + const char *name_override) { llvm::json::Object object; - EmplaceSafeString(object, "name", -CreateUniqueVariableNameForDisplay(v, is_name_duplicated)); + auto name = name_override + ? name_override + : CreateUniqueVariableNameForDisplay(v, is_name_duplicated); + EmplaceSafeString(object, "name", name); if (format_hex) v.SetFormat(lldb::eFormatHex); Index: lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py === --- lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py +++ lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py @@ -576,3 +576,39 @@ ''' initCommands = ['settings set symbols.load-on-demand true'] self.darwin_dwarf_missing_obj(initCommands) + + +@skipIfWindows +@skipIfRemote +def test_return_value(self): +''' +Test that local variables include a an entry for the return value +when stepping out of a function with a return value. +''' +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.cpp" +breakpoint4_line = line_number(source, "// breakpoint 4") +lines = [breakpoint4_line] +breakpoint_ids = self.set_source_breakpoints(source, lines) +self.assertEqual( +len(breakpoint_ids), len(lines), "expect correct number of breakpoints" +) +self.continue_to_breakpoints(breakpoint_ids) +tid = self.vscode.get_thread_id() + +# We haven't stepped out of a function with a return value so there +# should be no variable named 'Return value'. +locals = self.vscode.get_local_variables() +names = [var['name'] for var in locals] +self.assertNotIn('
[Lldb-commits] [PATCH] D141633: [lldb-vscode] Use SBFrame.GetDisplayFunctionName() instead of SBFrame.GetFunctionName()
ivanhernandez13 created this revision. Herald added a project: All. ivanhernandez13 requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits. This change replaces calls to SBFrame.GetFunctionName() with SBFrame.GetDisplayFunctionName() which can return much more user friendly names in some cases, particularly for Swift code. A trivial example: main.swift class Doer { static func doTheThing() { print("Hello World!") } } Doer.doTheThing() lldb (lldb) script lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().GetDisplayFunctionName() 'static Doer.doTheThing()' (lldb) script lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().GetFunctionName() 'static main.Doer.doTheThing() -> ()' Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D141633 Files: lldb/tools/lldb-vscode/JSONUtils.cpp Index: lldb/tools/lldb-vscode/JSONUtils.cpp === --- lldb/tools/lldb-vscode/JSONUtils.cpp +++ lldb/tools/lldb-vscode/JSONUtils.cpp @@ -650,7 +650,7 @@ } const auto num_insts = insts.GetSize(); if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) { -EmplaceSafeString(object, "name", frame.GetFunctionName()); +EmplaceSafeString(object, "name", frame.GetDisplayFunctionName()); SourceReference source; llvm::raw_string_ostream src_strm(source.content); std::string line; @@ -759,7 +759,7 @@ object.try_emplace("id", frame_id); std::string frame_name; - const char *func_name = frame.GetFunctionName(); + const char *func_name = frame.GetDisplayFunctionName(); if (func_name) frame_name = func_name; else Index: lldb/tools/lldb-vscode/JSONUtils.cpp === --- lldb/tools/lldb-vscode/JSONUtils.cpp +++ lldb/tools/lldb-vscode/JSONUtils.cpp @@ -650,7 +650,7 @@ } const auto num_insts = insts.GetSize(); if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) { -EmplaceSafeString(object, "name", frame.GetFunctionName()); +EmplaceSafeString(object, "name", frame.GetDisplayFunctionName()); SourceReference source; llvm::raw_string_ostream src_strm(source.content); std::string line; @@ -759,7 +759,7 @@ object.try_emplace("id", frame_id); std::string frame_name; - const char *func_name = frame.GetFunctionName(); + const char *func_name = frame.GetDisplayFunctionName(); if (func_name) frame_name = func_name; else ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D141637: [lldb-vscode] Fix an issue where lldb-vscode tries to display a source file for generated code
ivanhernandez13 created this revision. Herald added a project: All. ivanhernandez13 requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits. According to https://github.com/llvm/llvm-project/blob/fbcefff9d0a3f5e97270ef8e7b8e0f2afc33dc1c/lldb/source/Symbol/LineEntry.cpp#L215, a line entry of 0 indicates compiler generated code. Despite it being generated code, the SBLineEntry.GetFileSpec().IsValid() check can be true in which case lldb-vscode responds with a non-existent file named "". This patch will instead have lldb-vscode return the disassembly of the generated code. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D141637 Files: lldb/tools/lldb-vscode/JSONUtils.cpp Index: lldb/tools/lldb-vscode/JSONUtils.cpp === --- lldb/tools/lldb-vscode/JSONUtils.cpp +++ lldb/tools/lldb-vscode/JSONUtils.cpp @@ -613,7 +613,7 @@ llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) { disasm_line = 0; auto line_entry = frame.GetLineEntry(); - if (line_entry.GetFileSpec().IsValid()) + if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) return CreateSource(line_entry); llvm::json::Object object; Index: lldb/tools/lldb-vscode/JSONUtils.cpp === --- lldb/tools/lldb-vscode/JSONUtils.cpp +++ lldb/tools/lldb-vscode/JSONUtils.cpp @@ -613,7 +613,7 @@ llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) { disasm_line = 0; auto line_entry = frame.GetLineEntry(); - if (line_entry.GetFileSpec().IsValid()) + if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) return CreateSource(line_entry); llvm::json::Object object; ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D153447: Creating a startDebugging reverse DAP request handler in lldb-vscode.
ivanhernandez13 accepted this revision. ivanhernandez13 added inline comments. This revision is now accepted and ready to land. Comment at: lldb/tools/lldb-vscode/VSCode.cpp:569 + +// llvm::Error VSCode::Loop() { +// std::condition_variable cv; Dead code? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D153447/new/ https://reviews.llvm.org/D153447 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D153447: Creating a startDebugging reverse DAP request handler in lldb-vscode.
ivanhernandez13 added inline comments. Comment at: lldb/tools/lldb-vscode/VSCode.h:251-252 /// \return - /// A \a PacketStatus object indicating the sucess or failure of the - /// request. - PacketStatus SendReverseRequest(llvm::json::Object request, - llvm::json::Object &response); + /// A future that resolves to the response object indicating the sucess or + /// failure of the request. + void SendReverseRequest(llvm::StringRef command, llvm::json::Value arguments, nit: Could you update this comment that is no longer accurate Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D153447/new/ https://reviews.llvm.org/D153447 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 created this revision. Herald added subscribers: lldb-commits, mgorny. Herald added a project: LLDB. This change will bring lldb-vscode in line with how several other llvm tools process command line arguments. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D74798 Files: lldb/tools/lldb-vscode/CMakeLists.txt lldb/tools/lldb-vscode/Opts.td 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 @@ -41,8 +41,12 @@ #include #include "llvm/ADT/ArrayRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "JSONUtils.h" @@ -64,6 +68,34 @@ using namespace lldb_vscode; namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Opts.inc" +#undef PREFIX + +static const llvm::opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ +{ \ + PREFIX, NAME, HELPTEXT,\ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Opts.inc" +#undef OPTION +}; +class LLDBVSCodeOptTable : public llvm::opt::OptTable { +public: + LLDBVSCodeOptTable() : OptTable(InfoTable, true) {} +}; typedef void (*RequestCallback)(const llvm::json::Object &command); @@ -2719,31 +2751,70 @@ } // anonymous namespace +static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) { + std::string usage_str = tool_name.str() + "options"; + table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false); + + std::string examples = R"___( +EXAMPLES: + The debug adapter can be started in two modes. + + Running lldb-vscode without any arguments will start communicating with the + parent over stdio. Passing a port number causes lldb-vscode to start listening + for connections on that port. + +lldb-vscode -p + + Passing --wait-for-debugger will pause the process at startup and wait for a + debugger to attach to the process. + +lldb-vscode -g + )___"; + llvm::outs() << examples; +} + int main(int argc, char *argv[]) { // Initialize LLDB first before we do anything. lldb::SBDebugger::Initialize(); - if (argc == 2) { -const char *arg = argv[1]; + int portno = -1; + + LLDBVSCodeOptTable T; + unsigned MAI, MAC; + llvm::ArrayRef ArgsArr = llvm::makeArrayRef(argv + 1, argc); + llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC); + + if (input_args.hasArg(OPT_help)) { +printHelp(T, llvm::sys::path::filename(argv[0])); +return 0; + } + + if (auto *arg = input_args.getLastArg(OPT_port)) { +auto optarg = arg->getValue(); +char *remainder; +portno = strtol(optarg, &remainder, 0); +if (remainder == optarg || *remainder != '\0') { + fprintf(stderr, "'%s' is not a valid port number.\n", optarg); + exit(1); +} + } + #if !defined(_WIN32) -if (strcmp(arg, "-g") == 0) { - printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); - pause(); -} else { -#else -{ + if (input_args.hasArg(OPT_wait_for_debugger)) { +printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); +pause(); + } #endif - int portno = atoi(arg); - printf("Listening on port %i...\n", portno); - SOCKET socket_fd = AcceptConnection(portno); - if (socket_fd >= 0) { -g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); -g_vsc.output.descriptor = -StreamDescriptor::from_socket(socket_fd, false); - } else { -exit(1); - } + if (portno != -1) { +printf("Listening on port %i...\n", portno); +SOCKET socket_fd = AcceptConnection(portno); +if (socket_fd >= 0) { + g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); + g_vsc.output.descriptor = + StreamDescriptor::from_socket(socket_fd, false); +} else { + exit(1); } } else { g_vsc.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false); Index: lldb/tools/lldb-v
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 added a comment. Assuming this looks good, can I get some pointers on how and where I should add a test for this? I based this change on the one for the LLDB driver (https://reviews.llvm.org/D54692) which added lldb/trunk/lit/Driver/TestCommands.test. Should I look into adding something similar or should I be using lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py and adding something in lldb/test/API/tools/lldb-vscode? This is what the output for help looks like: ~/llvm-project ❯❯❯ build/Debug/bin/lldb-vscode --help [INSERT] OVERVIEW: LLDB VSCode USAGE: lldb-vscodeoptions OPTIONS: -g Alias for --wait-for-debugger --help Prints out the usage information for the LLDB debug adapter tool. -h Alias for --help --portWhat port to listen on. -p Alias for --port --wait-for-debugger Pause the program at startup. EXAMPLES: The debug adapter can be started in two modes. Running lldb-vscode without any arguments will start communicating with the parent over stdio. Passing a port number causes lldb-vscode to start listening for connections on that port. lldb-vscode -p Passing --wait-for-debugger will pause the process at startup and wait for a debugger to attach to the process. lldb-vscode -w % Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74798/new/ https://reviews.llvm.org/D74798 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 updated this revision to Diff 245442. ivanhernandez13 marked 2 inline comments as done. ivanhernandez13 added a comment. - Rename opts to options to be consistent with the lldb driver and add a test case around setting an invalid port. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74798/new/ https://reviews.llvm.org/D74798 Files: lldb/test/Shell/VSCode/TestOptions.test lldb/test/Shell/helper/toolchain.py lldb/tools/lldb-vscode/CMakeLists.txt lldb/tools/lldb-vscode/Options.td 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 @@ -41,8 +41,12 @@ #include #include "llvm/ADT/ArrayRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "JSONUtils.h" @@ -64,6 +68,34 @@ using namespace lldb_vscode; namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Opts.inc" +#undef PREFIX + +static const llvm::opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ +{ \ + PREFIX, NAME, HELPTEXT,\ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Opts.inc" +#undef OPTION +}; +class LLDBVSCodeOptTable : public llvm::opt::OptTable { +public: + LLDBVSCodeOptTable() : OptTable(InfoTable, true) {} +}; typedef void (*RequestCallback)(const llvm::json::Object &command); @@ -2719,31 +2751,70 @@ } // anonymous namespace +static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) { + std::string usage_str = tool_name.str() + "options"; + table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false); + + std::string examples = R"___( +EXAMPLES: + The debug adapter can be started in two modes. + + Running lldb-vscode without any arguments will start communicating with the + parent over stdio. Passing a port number causes lldb-vscode to start listening + for connections on that port. + +lldb-vscode -p + + Passing --wait-for-debugger will pause the process at startup and wait for a + debugger to attach to the process. + +lldb-vscode -g + )___"; + llvm::outs() << examples; +} + int main(int argc, char *argv[]) { // Initialize LLDB first before we do anything. lldb::SBDebugger::Initialize(); - if (argc == 2) { -const char *arg = argv[1]; + int portno = -1; + + LLDBVSCodeOptTable T; + unsigned MAI, MAC; + llvm::ArrayRef ArgsArr = llvm::makeArrayRef(argv + 1, argc); + llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC); + + if (input_args.hasArg(OPT_help)) { +printHelp(T, llvm::sys::path::filename(argv[0])); +return 0; + } + + if (auto *arg = input_args.getLastArg(OPT_port)) { +auto optarg = arg->getValue(); +char *remainder; +portno = strtol(optarg, &remainder, 0); +if (remainder == optarg || *remainder != '\0') { + fprintf(stderr, "'%s' is not a valid port number.\n", optarg); + exit(1); +} + } + #if !defined(_WIN32) -if (strcmp(arg, "-g") == 0) { - printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); - pause(); -} else { -#else -{ + if (input_args.hasArg(OPT_wait_for_debugger)) { +printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); +pause(); + } #endif - int portno = atoi(arg); - printf("Listening on port %i...\n", portno); - SOCKET socket_fd = AcceptConnection(portno); - if (socket_fd >= 0) { -g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); -g_vsc.output.descriptor = -StreamDescriptor::from_socket(socket_fd, false); - } else { -exit(1); - } + if (portno != -1) { +printf("Listening on port %i...\n", portno); +SOCKET socket_fd = AcceptConnection(portno); +if (socket_fd >= 0) { + g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); + g_vsc.output.descriptor = + StreamDescriptor::from_socke
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 added a comment. I added the test file but atm the two existing arguments (--wait-for-debugger and --port) will cause lldb-vscode to hang and await some sort of action from an external process causing the test runner to hang. I added a single test case for handling an invalid port since that will cause the process to exit immediately but not certain on how to handle the other cases. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74798/new/ https://reviews.llvm.org/D74798 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 updated this revision to Diff 245517. ivanhernandez13 added a comment. - Update ldb-vscode options test to simply look for the expected flags when passing the --help option. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74798/new/ https://reviews.llvm.org/D74798 Files: lldb/test/Shell/VSCode/TestOptions.test lldb/test/Shell/helper/toolchain.py lldb/tools/lldb-vscode/CMakeLists.txt lldb/tools/lldb-vscode/Options.td 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 @@ -41,8 +41,12 @@ #include #include "llvm/ADT/ArrayRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "JSONUtils.h" @@ -64,6 +68,34 @@ using namespace lldb_vscode; namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +static const llvm::opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ +{ \ + PREFIX, NAME, HELPTEXT,\ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Options.inc" +#undef OPTION +}; +class LLDBVSCodeOptTable : public llvm::opt::OptTable { +public: + LLDBVSCodeOptTable() : OptTable(InfoTable, true) {} +}; typedef void (*RequestCallback)(const llvm::json::Object &command); @@ -2719,31 +2751,70 @@ } // anonymous namespace +static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) { + std::string usage_str = tool_name.str() + "options"; + table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false); + + std::string examples = R"___( +EXAMPLES: + The debug adapter can be started in two modes. + + Running lldb-vscode without any arguments will start communicating with the + parent over stdio. Passing a port number causes lldb-vscode to start listening + for connections on that port. + +lldb-vscode -p + + Passing --wait-for-debugger will pause the process at startup and wait for a + debugger to attach to the process. + +lldb-vscode -g + )___"; + llvm::outs() << examples; +} + int main(int argc, char *argv[]) { // Initialize LLDB first before we do anything. lldb::SBDebugger::Initialize(); - if (argc == 2) { -const char *arg = argv[1]; + int portno = -1; + + LLDBVSCodeOptTable T; + unsigned MAI, MAC; + llvm::ArrayRef ArgsArr = llvm::makeArrayRef(argv + 1, argc); + llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC); + + if (input_args.hasArg(OPT_help)) { +printHelp(T, llvm::sys::path::filename(argv[0])); +return 0; + } + + if (auto *arg = input_args.getLastArg(OPT_port)) { +auto optarg = arg->getValue(); +char *remainder; +portno = strtol(optarg, &remainder, 0); +if (remainder == optarg || *remainder != '\0') { + fprintf(stderr, "'%s' is not a valid port number.\n", optarg); + exit(1); +} + } + #if !defined(_WIN32) -if (strcmp(arg, "-g") == 0) { - printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); - pause(); -} else { -#else -{ + if (input_args.hasArg(OPT_wait_for_debugger)) { +printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); +pause(); + } #endif - int portno = atoi(arg); - printf("Listening on port %i...\n", portno); - SOCKET socket_fd = AcceptConnection(portno); - if (socket_fd >= 0) { -g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); -g_vsc.output.descriptor = -StreamDescriptor::from_socket(socket_fd, false); - } else { -exit(1); - } + if (portno != -1) { +printf("Listening on port %i...\n", portno); +SOCKET socket_fd = AcceptConnection(portno); +if (socket_fd >= 0) { + g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); + g_vsc.output.descriptor = + StreamDescriptor::from_socket(socket_fd, false); +} else { + exit(1);
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 updated this revision to Diff 245523. ivanhernandez13 added a comment. - Add missing newline. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74798/new/ https://reviews.llvm.org/D74798 Files: lldb/test/Shell/VSCode/TestOptions.test lldb/test/Shell/helper/toolchain.py lldb/tools/lldb-vscode/CMakeLists.txt lldb/tools/lldb-vscode/Options.td 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 @@ -41,8 +41,12 @@ #include #include "llvm/ADT/ArrayRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "JSONUtils.h" @@ -64,6 +68,34 @@ using namespace lldb_vscode; namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +static const llvm::opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ +{ \ + PREFIX, NAME, HELPTEXT,\ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Options.inc" +#undef OPTION +}; +class LLDBVSCodeOptTable : public llvm::opt::OptTable { +public: + LLDBVSCodeOptTable() : OptTable(InfoTable, true) {} +}; typedef void (*RequestCallback)(const llvm::json::Object &command); @@ -2719,31 +2751,70 @@ } // anonymous namespace +static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) { + std::string usage_str = tool_name.str() + "options"; + table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false); + + std::string examples = R"___( +EXAMPLES: + The debug adapter can be started in two modes. + + Running lldb-vscode without any arguments will start communicating with the + parent over stdio. Passing a port number causes lldb-vscode to start listening + for connections on that port. + +lldb-vscode -p + + Passing --wait-for-debugger will pause the process at startup and wait for a + debugger to attach to the process. + +lldb-vscode -g + )___"; + llvm::outs() << examples; +} + int main(int argc, char *argv[]) { // Initialize LLDB first before we do anything. lldb::SBDebugger::Initialize(); - if (argc == 2) { -const char *arg = argv[1]; + int portno = -1; + + LLDBVSCodeOptTable T; + unsigned MAI, MAC; + llvm::ArrayRef ArgsArr = llvm::makeArrayRef(argv + 1, argc); + llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC); + + if (input_args.hasArg(OPT_help)) { +printHelp(T, llvm::sys::path::filename(argv[0])); +return 0; + } + + if (auto *arg = input_args.getLastArg(OPT_port)) { +auto optarg = arg->getValue(); +char *remainder; +portno = strtol(optarg, &remainder, 0); +if (remainder == optarg || *remainder != '\0') { + fprintf(stderr, "'%s' is not a valid port number.\n", optarg); + exit(1); +} + } + #if !defined(_WIN32) -if (strcmp(arg, "-g") == 0) { - printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); - pause(); -} else { -#else -{ + if (input_args.hasArg(OPT_wait_for_debugger)) { +printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); +pause(); + } #endif - int portno = atoi(arg); - printf("Listening on port %i...\n", portno); - SOCKET socket_fd = AcceptConnection(portno); - if (socket_fd >= 0) { -g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); -g_vsc.output.descriptor = -StreamDescriptor::from_socket(socket_fd, false); - } else { -exit(1); - } + if (portno != -1) { +printf("Listening on port %i...\n", portno); +SOCKET socket_fd = AcceptConnection(portno); +if (socket_fd >= 0) { + g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); + g_vsc.output.descriptor = + StreamDescriptor::from_socket(socket_fd, false); +} else { + exit(1); } } else { g_vsc.input.descriptor = StreamDescriptor::from_file(fileno
[Lldb-commits] [PATCH] D74798: [lldb-vscode] Use libOption with tablegen to parse command line options.
ivanhernandez13 added a comment. Thanks for the guidance! When there are no additional concerns, would someone mind committing this change for me? I don't have commit access. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74798/new/ https://reviews.llvm.org/D74798 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D62547: (lldb-vscode) Evaluate expressions as LLDB commands when in REPL mode.
ivanhernandez13 created this revision. ivanhernandez13 added a reviewer: clayborg. ivanhernandez13 added a project: LLDB. Herald added a subscriber: lldb-commits. lldb-vscode can receive 'evaluate' requests in multiple modes, one of which is 'repl' which indicates the expression to evaluate was typed into the Debug Console i.e. user input. This change makes 'request_evaluate' in lldb-vscode evaluate any user requested expression as an LLDB command if it cannot first find it as a local variable or a variable in the current frame. Repository: rLLDB LLDB https://reviews.llvm.org/D62547 Files: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py 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 @@ -926,6 +926,7 @@ auto arguments = request.getObject("arguments"); lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments); const auto expression = GetString(arguments, "expression"); + const auto context = GetString(arguments, "context"); if (!expression.empty() && expression[0] == '`') { auto result = RunLLDBCommands(llvm::StringRef(), @@ -936,25 +937,38 @@ // Always try to get the answer from the local variables if possible. If // this fails, then actually evaluate an expression using the expression // parser. "frame variable" is more reliable than the expression parser in -// many cases and it is faster. +// many cases and it is faster. Run the expression as an LLDB command as a +// last resort when in REPL context. lldb::SBValue value = frame.GetValueForVariablePath( expression.data(), lldb::eDynamicDontRunTarget); if (value.GetError().Fail()) value = frame.EvaluateExpression(expression.data()); if (value.GetError().Fail()) { - response["success"] = llvm::json::Value(false); - // This error object must live until we're done with the pointer returned - // by GetCString(). - lldb::SBError error = value.GetError(); - const char *error_cstr = error.GetCString(); - if (error_cstr && error_cstr[0]) -EmplaceSafeString(response, "message", std::string(error_cstr)); - else -EmplaceSafeString(response, "message", "evaluate failed"); + // Evaluate the expression as an LLDB command when the expression was + // received from the REPL console. + if (context == "repl") { +if (value.GetError().Fail()) { + auto result = RunLLDBCommands(llvm::StringRef(), +{expression}); + EmplaceSafeString(body, "result", result); + body.try_emplace("variablesReference", (int64_t)0); +} + } else { +response["success"] = llvm::json::Value(false); +// This error object must live until we're done with the pointer +// returned by GetCString(). +lldb::SBError error = value.GetError(); +const char *error_cstr = error.GetCString(); +if (error_cstr && error_cstr[0]) + EmplaceSafeString(response, "message", std::string(error_cstr)); +else + EmplaceSafeString(response, "message", "evaluate failed"); + } } else { SetValueForKey(value, body, "result"); auto value_typename = value.GetType().GetDisplayTypeName(); - EmplaceSafeString(body, "type", value_typename ? value_typename : NO_TYPENAME); + EmplaceSafeString( +body, "type", value_typename ? value_typename : NO_TYPENAME); if (value.MightHaveChildren()) { auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize()); g_vsc.variables.Append(value); Index: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py === --- lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py @@ -519,7 +519,7 @@ } return self.send_recv(command_dict) -def request_evaluate(self, expression, frameIndex=0, threadId=None): +def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None): stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: @@ -528,6 +528,8 @@ 'expression': expression, 'frameId': stackFrame['id'], } +if context is not None: + args_dict["context"] = context command_dict = { 'command': 'evaluate', 'type': 'request', Index: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py ===
[Lldb-commits] [PATCH] D62547: (lldb-vscode) Evaluate expressions as LLDB commands when in REPL mode.
ivanhernandez13 added a comment. clayborg - I see the issue that this change would introduce and I’m not certain of a solution. Also, I’m not sure I understand what we get from keeping track of the selected thread. Isn’t the issue that the behavior is dependent on what thread is selected, and whether a variable exists in that thread? e.g. Thread #1 Foo: “Foo” Thread #2 Bar: “Bar” - Break at BP in Thread #1 * > Foo > “Foo” - Select Thread #2 * > Foo > (lldb) Foo > error: ‘Foo’ is not a valid command. lanza - One motivation behind this was to support completions (see: https://github.com/ivanhernandez13/swift-lldb/commit/3311eef0afcf11d3426ff1d9e153e1641fd312b3) although I suppose it would be easy to hack support for that as well by simply checking for the “`” character and using only the rest of the string for completions. I was not aware of that DAP feature request. I agree that a separate command and REPL console ultimately sounds like a better approach. labath - As an Xcode user I was used to simply typing an lldb command, I made this change locally to better replicate Xcode’s behavior. I do however, see the issue with inconsistent behavior that this would introduce and I’m not certain there is a good solution for that. Repository: rLLDB LLDB CHANGES SINCE LAST ACTION https://reviews.llvm.org/D62547/new/ https://reviews.llvm.org/D62547 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D62547: (lldb-vscode) Evaluate expressions as LLDB commands when in REPL mode.
ivanhernandez13 added a comment. Yep you're right, Xcode doesn't have that capability. Unfortunately there is no standard way of doing this. Lanza filed a feature request to add a standard way to the DAP. Also looks like he looked into how other extensions do this: > vscode-cpptools - Prefix the command with -exec e.g. -exec target list > vscode-lldb - The specs is actually ignored and evaluate actually evaluated > the lldb command. You must prefix your Debug Console command with ? in order > to get the spec's evaluation requirements. > lldb-vscode - Prefix the command with a backtick. 'target list. > code-debug - Same as vscode-lldb, ignores the spec and provides the debugger > command prompt instead. (copied from the DAP feature request thread) Repository: rLLDB LLDB CHANGES SINCE LAST ACTION https://reviews.llvm.org/D62547/new/ https://reviews.llvm.org/D62547 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D71824: Add the 'start' and 'length' to the completions response. This will fix an issue where applying a completion 'foo.bar' to 'po foo.b' inserts the entire completion result
ivanhernandez13 created this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D71824 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 @@ -947,6 +947,7 @@ 0, -1, matches, descriptions); size_t count = std::min((uint32_t)50, matches.GetSize()); targets.reserve(count); + auto command_prefix = llvm::StringRef(text).rsplit(" ").second; for (size_t i = 0; i < count; i++) { std::string match = matches.GetStringAtIndex(i); std::string description = descriptions.GetStringAtIndex(i); @@ -958,6 +959,15 @@ else EmplaceSafeString(item, "label", match + " -- " + description); +auto command_prefix_size = command_prefix.size(); +if (command_prefix_size && match.find(command_prefix, 0) == 0) { + EmplaceSafeString(item, "start", +llvm::StringRef(std::to_string(actual_column - + command_prefix_size))); + EmplaceSafeString(item, "length", +llvm::StringRef(std::to_string(command_prefix_size))); +} + targets.emplace_back(std::move(item)); } Index: lldb/tools/lldb-vscode/lldb-vscode.cpp === --- lldb/tools/lldb-vscode/lldb-vscode.cpp +++ lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -947,6 +947,7 @@ 0, -1, matches, descriptions); size_t count = std::min((uint32_t)50, matches.GetSize()); targets.reserve(count); + auto command_prefix = llvm::StringRef(text).rsplit(" ").second; for (size_t i = 0; i < count; i++) { std::string match = matches.GetStringAtIndex(i); std::string description = descriptions.GetStringAtIndex(i); @@ -958,6 +959,15 @@ else EmplaceSafeString(item, "label", match + " -- " + description); +auto command_prefix_size = command_prefix.size(); +if (command_prefix_size && match.find(command_prefix, 0) == 0) { + EmplaceSafeString(item, "start", +llvm::StringRef(std::to_string(actual_column - + command_prefix_size))); + EmplaceSafeString(item, "length", +llvm::StringRef(std::to_string(command_prefix_size))); +} + targets.emplace_back(std::move(item)); } ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits