diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py @@ -266,8 +266,8 @@ stopOnEntry=False, disableASLR=True, disableSTDIO=False, shellExpandArguments=False, trace=False, initCommands=None, preRunCommands=None, - stopCommands=None, exitCommands=None,sourcePath= None, - debuggerRoot=None, launchCommands=None): + stopCommands=None, exitCommands=None,sourcePath=None, + debuggerRoot=None, launchCommands=None, sourceMap=None): '''Sending launch request to vscode ''' @@ -298,7 +298,8 @@ exitCommands=exitCommands, sourcePath=sourcePath, debuggerRoot=debuggerRoot, - launchCommands=launchCommands) + launchCommands=launchCommands, + sourceMap=sourceMap) if not (response and response['success']): self.assertTrue(response['success'], 'launch failed (%s)' % (response['message'])) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py @@ -570,7 +570,7 @@ disableSTDIO=False, shellExpandArguments=False, trace=False, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, sourcePath=None, - debuggerRoot=None, launchCommands=None): + debuggerRoot=None, launchCommands=None, sourceMap=None): args_dict = { 'program': program } @@ -605,6 +605,8 @@ args_dict['debuggerRoot'] = debuggerRoot if launchCommands: args_dict['launchCommands'] = launchCommands + if sourceMap: + args_dict['sourceMap'] = sourceMap command_dict = { 'command': 'launch', 'type': 'request', diff --git a/lldb/test/API/tools/lldb-vscode/breakpoint/Makefile b/lldb/test/API/tools/lldb-vscode/breakpoint/Makefile --- a/lldb/test/API/tools/lldb-vscode/breakpoint/Makefile +++ b/lldb/test/API/tools/lldb-vscode/breakpoint/Makefile @@ -1,3 +1,7 @@ -CXX_SOURCES := main.cpp +CXX_SOURCES := main-copy.cpp include Makefile.rules + +# Copy file into the build folder to enable the test to modify it. +main-copy.cpp: main.cpp + cp -f $< $@ diff --git a/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py b/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py --- a/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py @@ -5,6 +5,7 @@ import unittest2 import vscode +import shutil from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil @@ -18,6 +19,46 @@ @skipIfWindows @skipIfRemote + def test_source_map(self): + self.build_and_create_debug_adaptor() + + source_basename = 'main-copy.cpp' + source_path = self.getBuildArtifact(source_basename) + source_folder = os.path.dirname(source_path) + + new_source_folder = os.path.join(os.path.dirname(source_folder), 'moved_location') + new_source_path = os.path.join(new_source_folder, source_basename) + + def cleanup(): + shutil.move(new_source_path, source_path) + os.rmdir(new_source_folder) + + self.addTearDownHook(cleanup) + + lines = [line_number('main.cpp', 'break 12')] + + os.mkdir(new_source_folder) + shutil.move(source_path, new_source_path) + + program = self.getBuildArtifact("a.out") + self.launch(program, sourceMap=[[source_folder, new_source_folder]]) + + response = self.vscode.request_setBreakpoints(new_source_path, lines) + if response: + breakpoints = response['body']['breakpoints'] + self.assertEquals(len(breakpoints), len(lines), + "expect %u source breakpoints" % (len(lines))) + for (breakpoint, index) in zip(breakpoints, range(len(lines))): + line = breakpoint['line'] + self.assertTrue(line, lines[index]) + self.assertTrue(line in lines, "line expected in lines array") + self.assertTrue(breakpoint['verified'], + "expect breakpoint verified") + self.assertEqual(source_basename, breakpoint['source']['name']) + self.assertEqual(new_source_path, breakpoint['source']['path']) + + @skipIfWindows + @skipIfRemote def test_set_and_clear(self): '''Tests setting and clearing source file and line breakpoints. This packet is a bit tricky on the debug adaptor side since there @@ -31,8 +72,8 @@ and makes sure things happen correctly. It doesn't test hitting breakpoints and the functionality of each breakpoint, like 'conditions' and 'hitCondition' settings.''' - source_basename = 'main.cpp' - source_path = os.path.join(os.getcwd(), source_basename) + source_basename = 'main-copy.cpp' + source_path = self.getBuildArtifact(source_basename) first_line = line_number('main.cpp', 'break 12') second_line = line_number('main.cpp', 'break 13') third_line = line_number('main.cpp', 'break 14') @@ -155,8 +196,8 @@ def test_functionality(self): '''Tests hitting breakpoints and the functionality of a single breakpoint, like 'conditions' and 'hitCondition' settings.''' - source_basename = 'main.cpp' - source_path = os.path.join(os.getcwd(), source_basename) + source_basename = 'main-copy.cpp' + source_path = self.getBuildArtifact(source_basename) loop_line = line_number('main.cpp', '// break loop') program = self.getBuildArtifact("a.out") diff --git a/lldb/tools/lldb-vscode/JSONUtils.h b/lldb/tools/lldb-vscode/JSONUtils.h --- a/lldb/tools/lldb-vscode/JSONUtils.h +++ b/lldb/tools/lldb-vscode/JSONUtils.h @@ -196,6 +196,25 @@ /// appended to it. void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints); +/// Converts \a bp to a JSON value using the provided source line information to +/// the \a breakpoints array. +/// +/// \param[in] bp +/// A LLDB breakpoint object which will provide basic information as ID and +/// resolved status. +/// +/// \param[in] sourcePath +/// The full path to the source to store in the JSON value. +/// +/// \param[in] line +/// The line to store in the JSON value. +/// +/// \param[in] breakpoints +/// A JSON array that will get a llvm::json::Value for \a bp +/// appended to it. +void AppendSourceBreakpoint(lldb::SBBreakpoint &bp, llvm::StringRef sourcePath, + int line, llvm::json::Array &breakpoints); + /// Converts breakpoint location to a Visual Studio Code "Breakpoint" /// JSON object and appends it to the \a breakpoints array. /// diff --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp --- a/lldb/tools/lldb-vscode/JSONUtils.cpp +++ b/lldb/tools/lldb-vscode/JSONUtils.cpp @@ -9,9 +9,11 @@ #include #include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/Path.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBFileSpec.h" #include "lldb/API/SBValue.h" #include "lldb/Host/PosixApi.h" @@ -319,10 +321,34 @@ return llvm::json::Value(std::move(object)); } +llvm::json::Value CreateSourceBreakpoint(lldb::SBBreakpoint &bp, + llvm::StringRef sourcePath, int line) { + llvm::json::Object object; + if (!bp.IsValid()) + return llvm::json::Value(std::move(object)); + + object.try_emplace("verified", bp.GetNumResolvedLocations() > 0); + object.try_emplace("id", bp.GetID()); + + object.try_emplace("line", line); + + llvm::json::Object source; + llvm::StringRef name = llvm::sys::path::filename(sourcePath); + EmplaceSafeString(source, "name", name); + EmplaceSafeString(source, "path", sourcePath); + object.try_emplace("source", llvm::json::Value(std::move(source))); + return llvm::json::Value(std::move(object)); +} + void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints) { breakpoints.emplace_back(CreateBreakpoint(bp)); } +void AppendSourceBreakpoint(lldb::SBBreakpoint &bp, llvm::StringRef sourcePath, + int line, llvm::json::Array &breakpoints) { + breakpoints.emplace_back(CreateSourceBreakpoint(bp, sourcePath, line)); +} + // "Event": { // "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, { // "type": "object", diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -1364,13 +1364,13 @@ llvm::sys::fs::set_current_path(debuggerRoot.data()); } - SetSourceMapFromArguments(*arguments); - // Run any initialize LLDB commands the user specified in the launch.json. // This is run before target is created, so commands can't do anything with // the targets - preRunCommands are run with the target. g_vsc.RunInitCommands(); + SetSourceMapFromArguments(*arguments); + lldb::SBError status; g_vsc.SetTarget(g_vsc.CreateTargetFromArguments(*arguments, status)); if (status.Fail()) { @@ -1748,13 +1748,15 @@ const auto &existing_bp = existing_source_bps->second.find(src_bp.line); if (existing_bp != existing_source_bps->second.end()) { existing_bp->second.UpdateBreakpoint(src_bp); - AppendBreakpoint(existing_bp->second.bp, response_breakpoints); + AppendSourceBreakpoint(existing_bp->second.bp, path, src_bp.line, + response_breakpoints); continue; } } // At this point the breakpoint is new src_bp.SetBreakpoint(path.data()); - AppendBreakpoint(src_bp.bp, response_breakpoints); + AppendSourceBreakpoint(src_bp.bp, path, src_bp.line, + response_breakpoints); g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp); } }