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/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,49 @@ @skipIfWindows @skipIfRemote + def test_source_map(self): + self.build_and_create_debug_adaptor() + + source_basename = 'main.cpp' + source_path = os.path.join(os.getcwd(), source_basename) + + new_source_folder = os.path.join(os.path.dirname(os.getcwd()), '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=[[os.getcwd(), new_source_folder]]) + + response = self.vscode.request_setBreakpoints(new_source_path, lines) + line_to_id = {} + if response: + breakpoints = response['body']['breakpoints'] + print(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]) + # Store the "id" of the breakpoint that was set for later + line_to_id[line] = breakpoint['id'] + self.assertTrue(line in lines, "line expected in lines array") + self.assertTrue(breakpoint['verified'], + "expect breakpoint verified") + self.assertEqual('main.cpp', 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 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,26 @@ /// 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, + const 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 @@ -12,6 +12,7 @@ #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 +320,37 @@ return llvm::json::Value(std::move(object)); } +llvm::json::Value CreateSourceBreakpoint(lldb::SBBreakpoint &bp, + const 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; + lldb::SBFileSpec file(sourcePath.str().c_str()); + const char *name = file.GetFilename(); + 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, + const 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,15 +1364,17 @@ 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()) { response["success"] = llvm::json::Value(false); EmplaceSafeString(response, "message", status.GetCString()); @@ -1748,13 +1750,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); } }