Index: include/lldb/API/SBExpressionOptions.h =================================================================== --- include/lldb/API/SBExpressionOptions.h +++ include/lldb/API/SBExpressionOptions.h @@ -110,6 +110,12 @@ void SetPrefix (const char *prefix); + + bool + GetTopLevel (); + + void + SetTopLevel (bool b = true); protected: Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -257,8 +257,10 @@ { public: static const uint32_t default_timeout = 500000; + static const ExecutionPolicy default_execution_policy = eExecutionPolicyOnlyWhenNeeded; + EvaluateExpressionOptions() : - m_execution_policy(eExecutionPolicyOnlyWhenNeeded), + m_execution_policy(default_execution_policy), m_language (lldb::eLanguageTypeUnknown), m_prefix (), // A prefix specific to this expression that is added after the prefix from the settings (if any) m_coerce_to_id (false), Index: packages/Python/lldbsuite/test/expression_command/top-level/Makefile =================================================================== --- packages/Python/lldbsuite/test/expression_command/top-level/Makefile +++ packages/Python/lldbsuite/test/expression_command/top-level/Makefile @@ -0,0 +1,12 @@ +LEVEL = ../../make + +default: a.out dummy + +CXX_SOURCES := main.cpp test.cpp + +dummy: dummy.cpp + +clean:: + rm -rf dummy dummy.dSYM + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/expression_command/top-level/TestTopLevelExprs.py =================================================================== --- packages/Python/lldbsuite/test/expression_command/top-level/TestTopLevelExprs.py +++ packages/Python/lldbsuite/test/expression_command/top-level/TestTopLevelExprs.py @@ -0,0 +1,83 @@ +""" +Test top-level expressions. +""" + +from __future__ import print_function + + + +import unittest2 + +import os, time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TopLevelExpressionsTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break for main.c. + self.line = line_number('main.cpp', + '// Set breakpoint here') + self.dummy_line = line_number('dummy.cpp', + '// Set breakpoint here') + + # Disable confirmation prompt to avoid infinite wait + self.runCmd("settings set auto-confirm true") + self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm")) + + + def build_and_run(self): + """Test top-level expressions.""" + self.build() + + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=False) + + self.runCmd("run", RUN_SUCCEEDED) + + def run_dummy(self): + self.runCmd("file dummy", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line (self, "dummy.cpp", self.dummy_line, num_expected_locations=1, loc_exact=False) + + self.runCmd("run", RUN_SUCCEEDED) + + @add_test_categories(['pyapi']) + def test_top_level_expressions(self): + self.build_and_run() + + resultFromCode = self.frame().EvaluateExpression("doTest()").GetValueAsUnsigned() + + self.runCmd("kill") + + self.run_dummy() + + codeFile = open('test.cpp', 'r') + + expressions = [] + current_expression = "" + + for line in codeFile: + if line.startswith("// --"): + expressions.append(current_expression) + current_expression = "" + else: + current_expression += line + + options = lldb.SBExpressionOptions() + options.SetLanguage(lldb.eLanguageTypeC_plus_plus) + options.SetTopLevel(True) + + for expression in expressions: + self.frame().EvaluateExpression(expression, options) + + resultFromTopLevel = self.frame().EvaluateExpression("doTest()").GetValueAsUnsigned() + + self.assertEqual(resultFromCode, resultFromTopLevel) Index: packages/Python/lldbsuite/test/expression_command/top-level/dummy.cpp =================================================================== --- packages/Python/lldbsuite/test/expression_command/top-level/dummy.cpp +++ packages/Python/lldbsuite/test/expression_command/top-level/dummy.cpp @@ -0,0 +1,7 @@ +#include + +int main() +{ + printf("This is a dummy\n"); // Set breakpoint here + return 0; +} Index: packages/Python/lldbsuite/test/expression_command/top-level/main.cpp =================================================================== --- packages/Python/lldbsuite/test/expression_command/top-level/main.cpp +++ packages/Python/lldbsuite/test/expression_command/top-level/main.cpp @@ -0,0 +1,9 @@ +#include + +extern int doTest(); + +int main() +{ + printf("%d\n", doTest()); // Set breakpoint here + return 0; +} Index: packages/Python/lldbsuite/test/expression_command/top-level/test.cpp =================================================================== --- packages/Python/lldbsuite/test/expression_command/top-level/test.cpp +++ packages/Python/lldbsuite/test/expression_command/top-level/test.cpp @@ -0,0 +1,63 @@ +class MyClass +{ +public: + int memberResult() + { + return 1; + } + static int staticResult() + { + return 1; + } + int externResult(); +}; + +// -- + +int MyClass::externResult() +{ + return 1; +} + +// -- + +MyClass m; + +// -- + +enum MyEnum { + myEnumOne = 1, + myEnumTwo, + myEnumThree +}; + +// -- + +class AnotherClass +{ +public: + __attribute__ ((always_inline)) int complicatedFunction() + { + struct { + int i; + } s = { 15 }; + + int as[4] = { 2, 3, 4, 5 }; + + for (signed char a : as) + { + s.i -= a; + } + + return s.i; + } +}; + +// -- + +int doTest() +{ + return m.memberResult() + MyClass::staticResult() + m.externResult() + MyEnum::myEnumThree + myEnumOne + AnotherClass().complicatedFunction(); +} + +// -- Index: source/API/SBExpressionOptions.cpp =================================================================== --- source/API/SBExpressionOptions.cpp +++ source/API/SBExpressionOptions.cpp @@ -197,6 +197,18 @@ return m_opaque_ap->SetPrefix(prefix); } +bool +SBExpressionOptions::GetTopLevel () +{ + return m_opaque_ap->GetExecutionPolicy() == eExecutionPolicyTopLevel; +} + +void +SBExpressionOptions::SetTopLevel (bool b) +{ + m_opaque_ap->SetExecutionPolicy(b ? eExecutionPolicyTopLevel : m_opaque_ap->default_execution_policy); +} + EvaluateExpressionOptions * SBExpressionOptions::get() const { Index: source/Commands/CommandObjectExpression.h =================================================================== --- source/Commands/CommandObjectExpression.h +++ source/Commands/CommandObjectExpression.h @@ -54,6 +54,7 @@ // Options table: Required for subclasses of Options. static OptionDefinition g_option_table[]; + bool top_level; bool unwind_on_error; bool ignore_breakpoints; bool show_types; Index: source/Commands/CommandObjectExpression.cpp =================================================================== --- source/Commands/CommandObjectExpression.cpp +++ source/Commands/CommandObjectExpression.cpp @@ -62,6 +62,7 @@ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug", 'g', OptionParser::eNoArgument , nullptr, nullptr, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."}, { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specifies the Language to use when parsing the expression. If not set the target.language setting is used." }, { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, nullptr, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "top-level", 'p', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Interpret the expression as top-level definitions rather than code to be immediately executed."} }; uint32_t @@ -148,6 +149,10 @@ unwind_on_error = false; ignore_breakpoints = false; break; + + case 'p': + top_level = true; + break; default: error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); @@ -178,6 +183,7 @@ debug = false; language = eLanguageTypeUnknown; m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact; + top_level = false; } const OptionDefinition* @@ -294,6 +300,8 @@ options.SetTryAllThreads(m_command_options.try_all_threads); options.SetDebug(m_command_options.debug); options.SetLanguage(m_command_options.language); + if (m_command_options.top_level) + options.SetExecutionPolicy(eExecutionPolicyTopLevel); // If there is any chance we are going to stop and want to see // what went wrong with our expression, we should generate debug info