serhiy.redko updated this revision to Diff 390182. serhiy.redko edited the summary of this revision. serhiy.redko added a comment.
As requested DAP now reports an error in case debug configuration contains unused target related keys ("program", "coreFile" etc) along with "launchCommands" or "attachCommands" that must create target. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D94997/new/ https://reviews.llvm.org/D94997 Files: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py lldb/test/API/tools/lldb-vscode/attach/TestVSCode_attach.py lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py lldb/tools/lldb-vscode/lldb-vscode.cpp lldb/tools/lldb-vscode/package.json
Index: lldb/tools/lldb-vscode/package.json =================================================================== --- lldb/tools/lldb-vscode/package.json +++ lldb/tools/lldb-vscode/package.json @@ -215,7 +215,7 @@ }, "launchCommands": { "type": "array", - "description": "Custom commands that are executed instead of launching a process. A target will be created with the launch arguments prior to executing these commands. The commands may optionally create a new target and must perform a launch. A valid process must exist after these commands complete or the \"launch\" will fail.", + "description": "Custom commands that are executed instead of launching a process. The commands must create a target and must perform a launch. A valid process must exist after these commands complete or the \"launch\" will fail. The following settings will be ignored if provided: \"program\", \"cwd\", \"args\", \"env\", \"disableASLR\", \"disableSTDIO\", \"shellExpandArguments\", \"detachOnError\", \"runInTerminal\", \"targetTriple\", \"platformName\"", "default": [] }, "stopCommands": { @@ -276,7 +276,7 @@ }, "attachCommands": { "type": "array", - "description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands may optionally create a new target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail.", + "description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands must create a target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail. The following settings will be ignored if provided: \"program\", \"pid\", \"waitFor\", \"coreFile\", \"targetTriple\", \"platformName\"", "default": [] }, "initCommands": { Index: lldb/tools/lldb-vscode/lldb-vscode.cpp =================================================================== --- lldb/tools/lldb-vscode/lldb-vscode.cpp +++ lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -618,28 +618,67 @@ SetSourceMapFromArguments(*arguments); - lldb::SBError status; - g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status)); - if (status.Fail()) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", status.GetCString()); - g_vsc.SendJSON(llvm::json::Value(std::move(response))); - return; - } + if (!attachCommands.empty()) { + // We have "attachCommands" that are a set of commands that are expected + // to execute the commands after which a process should be created. If there + // is no valid process after running these commands, we have failed. - // Run any pre run LLDB commands the user specified in the launch.json - g_vsc.RunPreRunCommands(); + std::vector<llvm::StringRef> incompatible_fields; + for (llvm::StringRef arg : {"program", "pid", "waitFor", "coreFile", + "targetTriple", "platformName"}) { + if (arguments->get(arg) != nullptr) { + incompatible_fields.push_back(arg); + } + } - if (pid == LLDB_INVALID_PROCESS_ID && wait_for) { - char attach_msg[256]; - auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg), - "Waiting to attach to \"%s\"...", - g_vsc.target.GetExecutable().GetFilename()); - g_vsc.SendOutput(OutputType::Console, - llvm::StringRef(attach_msg, attach_msg_len)); + if (!incompatible_fields.empty()) { + std::string str; + llvm::raw_string_ostream strm(str); + strm << "Incorrect debug configuration: " << + "'attachCommands' is not compatible with "; + for (llvm::StringRef field : incompatible_fields) { + strm << " '" << field << "' "; + } + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", strm.str()); + g_vsc.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + // Run any pre run LLDB commands the user specified in the launch.json + g_vsc.RunPreRunCommands(); + g_vsc.RunLLDBCommands("Running attachCommands:", attachCommands); + // The custom commands are expected to create a new target + if (g_vsc.debugger.GetNumTargets() > 0) { + g_vsc.SetTarget(g_vsc.debugger.GetSelectedTarget()); + } + else { + error.SetErrorString("attachCommands failed to create target"); + } } - if (attachCommands.empty()) { + else { // No "attachCommands", just attach normally. + lldb::SBError status; + g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status)); + if (status.Fail()) { + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", status.GetCString()); + g_vsc.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + // Run any pre run LLDB commands the user specified in the launch.json + g_vsc.RunPreRunCommands(); + + if (pid == LLDB_INVALID_PROCESS_ID && wait_for) { + char attach_msg[256]; + auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg), + "Waiting to attach to \"%s\"...", + g_vsc.target.GetExecutable().GetFilename()); + g_vsc.SendOutput(OutputType::Console, + llvm::StringRef(attach_msg, attach_msg_len)); + } + // Disable async events so the attach will be successful when we return from // the launch call and the launch will happen synchronously g_vsc.debugger.SetAsync(false); @@ -649,14 +688,6 @@ g_vsc.target.LoadCore(core_file.data(), error); // Reenable async events g_vsc.debugger.SetAsync(true); - } else { - // We have "attachCommands" that are a set of commands that are expected - // to execute the commands after which a process should be created. If there - // is no valid process after running these commands, we have failed. - g_vsc.RunLLDBCommands("Running attachCommands:", attachCommands); - // 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.Success() && core_file.empty()) { @@ -1667,65 +1698,101 @@ SetSourceMapFromArguments(*arguments); - lldb::SBError status; - g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status)); - if (status.Fail()) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", status.GetCString()); - g_vsc.SendJSON(llvm::json::Value(std::move(response))); - return; - } + if (!launchCommands.empty()) { + // if "launchCommands" are provided, then they are expected to make the launch happen for launch requests + // and they replace the normal logic that would implement the launch. + // Run any pre run LLDB commands the user specified in the launch.json + + std::vector<llvm::StringRef> incompatible_fields; + for (llvm::StringRef arg : {"program", "cwd", "args", "env", "disableASLR", "disableSTDIO", + "shellExpandArguments", "detachOnError", "runInTerminal", "targetTriple", + "platformName"}) { + if (arguments->get(arg) != nullptr) { + incompatible_fields.push_back(arg); + } + } - // 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 (GetBoolean(arguments, "runInTerminal", false)) { - if (llvm::Error err = request_runInTerminal(request)) - error.SetErrorString(llvm::toString(std::move(err)).c_str()); - } else 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 { + if (!incompatible_fields.empty()) { + std::string str; + llvm::raw_string_ostream strm(str); + strm << "Incorrect debug configuration: " << + "'launchCommands' is not compatible with "; + for (llvm::StringRef field : incompatible_fields) { + strm << " '" << field << "' "; + } + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", strm.str()); + g_vsc.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + g_vsc.RunPreRunCommands(); 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(); + // The custom commands are expected to create a new target + if (g_vsc.debugger.GetNumTargets() > 0) { + g_vsc.SetTarget(g_vsc.debugger.GetSelectedTarget()); + } + else { + error.SetErrorString("launchCommands failed to create target"); + } + } + else { + // the normal logic that would implement the launch + lldb::SBError status; + g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status)); + if (status.Fail()) { + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", status.GetCString()); + 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(); + + // 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 (GetBoolean(arguments, "runInTerminal", false)) { + if (llvm::Error err = request_runInTerminal(request)) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + } else { + // 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 (error.Fail()) { Index: lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py =================================================================== --- lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py +++ lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py @@ -378,6 +378,7 @@ ''' self.build_and_create_debug_adaptor() program = self.getBuildArtifact("a.out") + execSearchPaths = '/unique/path/to/symbols/launch/test' source = 'main.c' first_line = line_number(source, '// breakpoint 1') @@ -387,6 +388,7 @@ # also we can verify that "stopCommands" get run as the # breakpoints get hit launchCommands = [ + 'settings set target.exec-search-paths "%s"' % (execSearchPaths), 'target create "%s"' % (program), 'breakpoint s -f main.c -l %d' % first_line, 'breakpoint s -f main.c -l %d' % second_line, @@ -396,13 +398,13 @@ initCommands = ['target list', 'platform list'] preRunCommands = ['image list a.out', 'image dump sections a.out'] stopCommands = ['frame variable', 'bt'] - exitCommands = ['expr 2+3', 'expr 3+4'] - self.launch(program, - initCommands=initCommands, + exitCommands = ['expr 2+3', 'expr 3+4', 'settings show target.exec-search-paths'] + self.launch(initCommands=initCommands, preRunCommands=preRunCommands, stopCommands=stopCommands, exitCommands=exitCommands, - launchCommands=launchCommands) + launchCommands=launchCommands, + disableASLR=None) # Get output from the console. This should contain both the # "initCommands" and the "preRunCommands". @@ -433,6 +435,8 @@ # "exitCommands" that were run after the second breakpoint was hit output = self.get_console(timeout=1.0) self.verify_commands('exitCommands', output, exitCommands) + # confirm that output contains correct target.exec-search-paths value + self.verify_contains_text('exitCommands', output, execSearchPaths) @skipIfWindows @skipIfNetBSD # Hangs on NetBSD as well Index: lldb/test/API/tools/lldb-vscode/attach/TestVSCode_attach.py =================================================================== --- lldb/test/API/tools/lldb-vscode/attach/TestVSCode_attach.py +++ lldb/test/API/tools/lldb-vscode/attach/TestVSCode_attach.py @@ -153,8 +153,7 @@ stopCommands = ['frame variable', 'bt'] exitCommands = ['expr 2+3', 'expr 3+4'] terminateCommands = ['expr 4+2'] - self.attach(program=program, - attachCommands=attachCommands, + self.attach(attachCommands=attachCommands, initCommands=initCommands, preRunCommands=preRunCommands, stopCommands=stopCommands, @@ -217,8 +216,7 @@ 'process launch' ] terminateCommands = ['expr 4+2'] - self.attach(program=program, - attachCommands=attachCommands, + self.attach(attachCommands=attachCommands, terminateCommands=terminateCommands, disconnectAutomatically=False) self.get_console() 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 @@ -631,7 +631,7 @@ self.initialize_body = response['body'] return response - def request_launch(self, program, args=None, cwd=None, env=None, + def request_launch(self, program=None, args=None, cwd=None, env=None, stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, trace=False, initCommands=None, preRunCommands=None, @@ -640,9 +640,9 @@ debuggerRoot=None, launchCommands=None, sourceMap=None, runInTerminal=False, expectFailure=False, postRunCommands=None): - args_dict = { - 'program': program - } + args_dict = {} + if program: + args_dict['program'] = program if args: args_dict['args'] = args if cwd: Index: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py =================================================================== --- lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py +++ lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py @@ -125,6 +125,13 @@ "verify '%s' found in console output for '%s'" % ( cmd, flavor)) + def verify_contains_text(self, flavor, output, text): + self.assertTrue(output and len(output) > 0, "expect console output") + found = text in output + self.assertTrue(found, + "verify '%s' found in console output for '%s'" % ( + text, flavor)) + def get_dict_value(self, d, key_path): '''Verify each key in the key_path array is in contained in each dictionary within "d". Assert if any key isn't in the
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits