diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/Makefile b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/Makefile new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/TestVSCode_environmentVariables.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/TestVSCode_environmentVariables.py new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/TestVSCode_environmentVariables.py @@ -0,0 +1,36 @@ +""" +Test lldb-vscode completions request +""" + + +import lldbvscode_testcase +import unittest2 +import vscode +from lldbsuite.test import lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +import os + + +class TestVSCode_variables(lldbvscode_testcase.VSCodeTestCaseBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIfWindows + #@skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots + def test_environment_variable(self): + """ + Tests the completion request at different breakpoints + """ + program = self.getBuildArtifact("a.out") + path_env_variable = 'PATH='+os.environ['PATH'] + self.build_and_launch(program, inheritEnvironment=False) + self.continue_to_exit() + output = self.get_stdout().encode('utf-8') + lines = output.splitlines() + found = False + for line in lines: + if line.startswith('PATH='): + found = True + self.assertTrue(path_env_variable == line, "PATH environment variable not the same") + self.assertTrue(found, 'PATH environment variable not found') \ No newline at end of file diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/main.cpp b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/environmentVariables/main.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +extern char **environ; + +int main(int argc, char const *argv[], char const *envp[]) { + char** env_var_pointer = environ; + // std::vector vscode_env_variables; + int count = 0; + for (char* env_variable = *env_var_pointer; env_variable; env_variable=*++env_var_pointer) { + printf("%s\n", env_variable); + count++; + } + return 0; // breakpoint 1 +} 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 @@ -267,7 +267,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, inheritEnvironment=False): '''Sending launch request to vscode ''' @@ -298,7 +298,9 @@ exitCommands=exitCommands, sourcePath=sourcePath, debuggerRoot=debuggerRoot, - launchCommands=launchCommands) + launchCommands=launchCommands, + inheritEnvironment=inheritEnvironment + ) if not (response and response['success']): self.assertTrue(response['success'], 'launch failed (%s)' % (response['message'])) @@ -308,14 +310,13 @@ disableSTDIO=False, shellExpandArguments=False, trace=False, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, - sourcePath=None, debuggerRoot=None): + sourcePath=None, debuggerRoot=None, inheritEnvironment=False): '''Build the default Makefile target, create the VSCode debug adaptor, and launch the process. ''' self.build_and_create_debug_adaptor() self.assertTrue(os.path.exists(program), 'executable must exist') - self.launch(program, args, cwd, env, stopOnEntry, disableASLR, disableSTDIO, shellExpandArguments, trace, initCommands, preRunCommands, stopCommands, exitCommands, - sourcePath, debuggerRoot) + sourcePath, debuggerRoot, inheritEnvironment=inheritEnvironment) 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, inheritEnvironment=False): args_dict = { 'program': program } @@ -605,6 +605,8 @@ args_dict['debuggerRoot'] = debuggerRoot if launchCommands: args_dict['launchCommands'] = launchCommands + if inheritEnvironment: + args_dict['inheritEnvironment'] = inheritEnvironment command_dict = { 'command': 'launch', 'type': 'request', @@ -912,7 +914,9 @@ initCommands=options.initCmds, preRunCommands=options.preRunCmds, stopCommands=options.stopCmds, - exitCommands=options.exitCmds) + exitCommands=options.exitCmds + inheritEnvironment=options.inheritEnvironment + ) if response['success']: if options.sourceBreakpoints: diff --git a/lldb/test/API/testcases/tools/lldb-vscode/environmentVariables/TestVSCode_environmentVariables.py b/lldb/test/API/testcases/tools/lldb-vscode/environmentVariables/TestVSCode_environmentVariables.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/testcases/tools/lldb-vscode/environmentVariables/TestVSCode_environmentVariables.py @@ -0,0 +1,36 @@ +""" +Test lldb-vscode completions request +""" + + +import lldbvscode_testcase +import unittest2 +import vscode +from lldbsuite.test import lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +import os + + +class TestVSCode_variables(lldbvscode_testcase.VSCodeTestCaseBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIfWindows + @skipIfDarwin # Skip this test for now until we can figure out why tings aren't working on build bots + def test_environment_variable(self): + """ + Tests the environment variables + """ + program = self.getBuildArtifact("a.out") + path_env_variable = 'PATH='+os.environ['PATH'] + self.build_and_launch(program, inheritEnvironment=False) + self.continue_to_exit() + output = self.get_stdout().encode('utf-8') + lines = output.splitlines() + found = False + for line in lines: + if line.startswith('PATH='): + found = True + self.assertTrue(path_env_variable == line, "PATH environment variable not the same") + self.assertTrue(found, 'PATH environment variable not found') \ No newline at end of file diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py b/lldb/test/API/testcases/tools/lldb-vscode/lldbvscode_testcase.py copy from lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py copy to lldb/test/API/testcases/tools/lldb-vscode/lldbvscode_testcase.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py +++ b/lldb/test/API/testcases/tools/lldb-vscode/lldbvscode_testcase.py @@ -12,10 +12,8 @@ '''Create the Visual Studio Code debug adaptor''' self.assertTrue(os.path.exists(self.lldbVSCodeExec), 'lldb-vscode must exist') - log_file_path = self.getBuildArtifact('vscode.txt') self.vscode = vscode.DebugAdaptor( - executable=self.lldbVSCodeExec, init_commands=self.setUpCommands(), - log_file=log_file_path) + executable=self.lldbVSCodeExec, init_commands=self.setUpCommands()) def build_and_create_debug_adaptor(self): self.build() @@ -24,7 +22,8 @@ def set_source_breakpoints(self, source_path, lines, condition=None, hitCondition=None): '''Sets source breakpoints and returns an array of strings containing - the breakpoint IDs ("1", "2") for each breakpoint that was set. + the breakpoint location IDs ("1.1", "1.2") for each breakpoint + that was set. ''' response = self.vscode.request_setBreakpoints( source_path, lines, condition=condition, hitCondition=hitCondition) @@ -33,14 +32,17 @@ breakpoints = response['body']['breakpoints'] breakpoint_ids = [] for breakpoint in breakpoints: - breakpoint_ids.append('%i' % (breakpoint['id'])) + response_id = breakpoint['id'] + bp_id = response_id >> 32 + bp_loc_id = response_id & 0xffffffff + breakpoint_ids.append('%i.%i' % (bp_id, bp_loc_id)) return breakpoint_ids def set_function_breakpoints(self, functions, condition=None, hitCondition=None): '''Sets breakpoints by function name given an array of function names - and returns an array of strings containing the breakpoint IDs - ("1", "2") for each breakpoint that was set. + and returns an array of strings containing the breakpoint location + IDs ("1.1", "1.2") for each breakpoint that was set. ''' response = self.vscode.request_setFunctionBreakpoints( functions, condition=condition, hitCondition=hitCondition) @@ -49,15 +51,18 @@ breakpoints = response['body']['breakpoints'] breakpoint_ids = [] for breakpoint in breakpoints: - breakpoint_ids.append('%i' % (breakpoint['id'])) + response_id = breakpoint['id'] + bp_id = response_id >> 32 + bp_loc_id = response_id & 0xffffffff + breakpoint_ids.append('%i.%i' % (bp_id, bp_loc_id)) return breakpoint_ids def verify_breakpoint_hit(self, breakpoint_ids): '''Wait for the process we are debugging to stop, and verify we hit any breakpoint location in the "breakpoint_ids" array. - "breakpoint_ids" should be a list of breakpoint ID strings - (["1", "2"]). The return value from self.set_source_breakpoints() - or self.set_function_breakpoints() can be passed to this function''' + "breakpoint_ids" should be a list of breakpoint location ID strings + (["1.1", "2.1"]). The return value from + self.set_source_breakpoints() can be passed to this function''' stopped_events = self.vscode.wait_for_stopped() for stopped_event in stopped_events: if 'body' in stopped_event: @@ -68,21 +73,14 @@ continue if 'description' not in body: continue - # Descriptions for breakpoints will be in the form - # "breakpoint 1.1", so look for any description that matches - # ("breakpoint 1.") in the description field as verification - # that one of the breakpoint locations was hit. VSCode doesn't - # allow breakpoints to have multiple locations, but LLDB does. - # So when looking at the description we just want to make sure - # the right breakpoint matches and not worry about the actual - # location. + # Description is "breakpoint 1.1", so look for any location id + # ("1.1") in the description field as verification that one of + # the breakpoint locations was hit description = body['description'] - print("description: %s" % (description)) for breakpoint_id in breakpoint_ids: - match_desc = 'breakpoint %s.' % (breakpoint_id) - if match_desc in description: - return - self.assertTrue(False, "breakpoint not hit") + if breakpoint_id in description: + return True + return False def verify_exception_breakpoint_hit(self, filter_label): '''Wait for the process we are debugging to stop, and verify the stop @@ -135,7 +133,7 @@ key, key_path, d)) return value - def get_stackFrames_and_totalFramesCount(self, threadId=None, startFrame=None, + def get_stackFrames_and_totalFramesCount(self, threadId=None, startFrame=None, levels=None, dump=False): response = self.vscode.request_stackTrace(threadId=threadId, startFrame=startFrame, @@ -267,7 +265,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, inheritEnvironment=False): '''Sending launch request to vscode ''' @@ -298,7 +296,9 @@ exitCommands=exitCommands, sourcePath=sourcePath, debuggerRoot=debuggerRoot, - launchCommands=launchCommands) + launchCommands=launchCommands, + inheritEnvironment=inheritEnvironment) + if not (response and response['success']): self.assertTrue(response['success'], 'launch failed (%s)' % (response['message'])) @@ -308,14 +308,14 @@ disableSTDIO=False, shellExpandArguments=False, trace=False, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, - sourcePath=None, debuggerRoot=None): + sourcePath=None, debuggerRoot=None, inheritEnvironment=False): '''Build the default Makefile target, create the VSCode debug adaptor, and launch the process. ''' self.build_and_create_debug_adaptor() self.assertTrue(os.path.exists(program), 'executable must exist') - + self.launch(program, args, cwd, env, stopOnEntry, disableASLR, disableSTDIO, shellExpandArguments, trace, initCommands, preRunCommands, stopCommands, exitCommands, - sourcePath, debuggerRoot) + sourcePath, debuggerRoot, inheritEnvironment=inheritEnvironment) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/test/API/testcases/tools/lldb-vscode/vscode.py copy from lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py copy to lldb/test/API/testcases/tools/lldb-vscode/vscode.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ b/lldb/test/API/testcases/tools/lldb-vscode/vscode.py @@ -111,7 +111,6 @@ self.exit_status = None self.initialize_body = None self.thread_stop_reasons = {} - self.breakpoint_events = [] self.sequence = 1 self.threads = None self.recv_thread.start() @@ -187,7 +186,7 @@ self.output[category] = output self.output_condition.notify() self.output_condition.release() - # no need to add 'output' event packets to our packets list + # no need to add 'output' packets to our packets list return keepGoing elif event == 'process': # When a new process is attached or launched, remember the @@ -201,13 +200,6 @@ self._process_stopped() tid = body['threadId'] self.thread_stop_reasons[tid] = body - elif event == 'breakpoint': - # Breakpoint events come in when a breakpoint has locations - # added or removed. Keep track of them so we can look for them - # in tests. - self.breakpoint_events.append(packet) - # no need to add 'breakpoint' event packets to our packets list - return keepGoing elif packet_type == 'response': if packet['command'] == 'disconnect': keepGoing = False @@ -570,7 +562,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, inheritEnvironment=False): args_dict = { 'program': program } @@ -605,6 +597,8 @@ args_dict['debuggerRoot'] = debuggerRoot if launchCommands: args_dict['launchCommands'] = launchCommands + if inheritEnvironment: + args_dict['inheritEnvironment'] = inheritEnvironment command_dict = { 'command': 'launch', 'type': 'request', @@ -847,17 +841,13 @@ class DebugAdaptor(DebugCommunication): - def __init__(self, executable=None, port=None, init_commands=[], log_file=None): + def __init__(self, executable=None, port=None, init_commands=[]): self.process = None if executable is not None: - adaptor_env = os.environ.copy() - if log_file: - adaptor_env['LLDBVSCODE_LOG'] = log_file self.process = subprocess.Popen([executable], stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=adaptor_env) + stderr=subprocess.PIPE) DebugCommunication.__init__(self, self.process.stdout, self.process.stdin, init_commands) elif port is not None: @@ -912,7 +902,8 @@ initCommands=options.initCmds, preRunCommands=options.preRunCmds, stopCommands=options.stopCmds, - exitCommands=options.exitCmds) + exitCommands=options.exitCmds, + inheritEnvironment=options.inheritEnvironment) if response['success']: if options.sourceBreakpoints: 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 @@ -49,6 +49,8 @@ #include "LLDBUtils.h" #include "VSCode.h" +extern char **environ; + #if defined(_WIN32) #ifndef PATH_MAX #define PATH_MAX MAX_PATH @@ -1327,6 +1329,7 @@ auto launchCommands = GetStrings(arguments, "launchCommands"); g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false); const auto debuggerRoot = GetString(arguments, "debuggerRoot"); + bool launchWithDebuggerEnvironment = GetBoolean(arguments, "inheritEnvironment", false); // This is a hack for loading DWARF in .o files on Mac where the .o files // in the debug map of the main executable have relative paths which require @@ -1364,13 +1367,24 @@ // Extract any extra arguments and append them to our program arguments for // when we launch auto args = GetStrings(arguments, "args"); - if (!args.empty()) + if (!args.empty()) g_vsc.launch_info.SetArguments(MakeArgv(args).data(), true); // Pass any environment variables along that the user specified. auto envs = GetStrings(arguments, "env"); + + if (launchWithDebuggerEnvironment) { + char** env_var_pointer = environ; + std::vector vscode_env_variables; + for (char* env_variable = *env_var_pointer; env_variable; env_variable=*++env_var_pointer){ + vscode_env_variables.push_back(env_variable); + } + envs.insert(std::end(envs), std::begin(vscode_env_variables), std::end(vscode_env_variables)); + } + if (!envs.empty()) g_vsc.launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true); + auto flags = g_vsc.launch_info.GetLaunchFlags(); diff --git a/lldb/tools/lldb-vscode/package.json b/lldb/tools/lldb-vscode/package.json --- a/lldb/tools/lldb-vscode/package.json +++ b/lldb/tools/lldb-vscode/package.json @@ -84,6 +84,11 @@ "description": "Additional environment variables.", "default": [] }, + "inheritEnvironment": { + "type": "boolean", + "description": "Inherit the VSCode Environment Variables", + "default": false + }, "stopOnEntry": { "type": "boolean", "description": "Automatically stop after launch.",