diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -3131,7 +3131,15 @@ ExpressionVariableSP persistent_var_sp = persistent_state->CreatePersistentVariable(const_result_sp); persistent_var_sp->m_live_sp = persistent_var_sp->m_frozen_sp; - persistent_var_sp->m_flags |= ExpressionVariable::EVIsProgramReference; + + // ConstResult values don't refer to a location in memory of the target + // process, so they need to be allocated explicitly. + if (GetValueType() == lldb::eValueTypeConstResult) { + persistent_var_sp->m_flags |= ExpressionVariable::EVNeedsAllocation; + persistent_var_sp->m_flags |= ExpressionVariable::EVNeedsFreezeDry; + } else { + persistent_var_sp->m_flags |= ExpressionVariable::EVIsProgramReference; + } return persistent_var_sp->GetValueObject(); } diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -284,13 +284,11 @@ .getValueOr(0)); // Read the contents of the spare memory area - - m_persistent_variable_sp->ValueUpdated(); + auto byte_size = m_persistent_variable_sp->GetByteSize().getValueOr(0); + auto buffer = std::make_shared(byte_size, 0); Status read_error; - - map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, - m_persistent_variable_sp->GetByteSize().getValueOr(0), read_error); + map.ReadMemory(buffer->GetBytes(), mem, byte_size, read_error); if (!read_error.Success()) { err.SetErrorStringWithFormat( @@ -300,8 +298,12 @@ return; } - m_persistent_variable_sp->m_flags &= - ~ExpressionVariable::EVNeedsFreezeDry; + m_persistent_variable_sp->m_frozen_sp = ValueObjectConstResult::Create( + map.GetBestExecutionContextScope(), + m_persistent_variable_sp->GetCompilerType(), + m_persistent_variable_sp->GetName(), + DataExtractor(buffer, map.GetByteOrder(), map.GetAddressByteSize()), + LLDB_INVALID_ADDRESS); } } else { err.SetErrorStringWithFormat( diff --git a/lldb/test/API/python_api/sbvalue_persist/TestSBValuePersist.py b/lldb/test/API/python_api/sbvalue_persist/TestSBValuePersist.py --- a/lldb/test/API/python_api/sbvalue_persist/TestSBValuePersist.py +++ b/lldb/test/API/python_api/sbvalue_persist/TestSBValuePersist.py @@ -1,7 +1,5 @@ """Test SBValue::Persist""" - - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * @@ -13,9 +11,7 @@ mydir = TestBase.compute_mydir(__file__) NO_DEBUG_INFO_TESTCASE = True - @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24772") - def test(self): - """Test SBValue::Persist""" + def _setup(self): self.build() self.setTearDownCleanup() self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) @@ -40,42 +36,103 @@ # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) + @add_test_categories(['pyapi']) + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24772") + def test_std_string(self): + """Test SBValue::Persist for a variable of type std::string""" + self._setup() + + baz = self.frame().FindVariable("baz") + self.assertTrue(baz.IsValid(), "baz is not valid") + + bazPersist = baz.Persist() + self.assertTrue(bazPersist.IsValid(), "bazPersist is not valid") + self.assertEqual(bazPersist.GetSummary(), '"85"') + + self.runCmd("continue") + + self.assertTrue(bazPersist.IsValid(), "bazPersist is not valid") + self.assertEqual(bazPersist.GetSummary(), '"85"') + + @add_test_categories(['pyapi']) + def test(self): + """Test SBValue::Persist""" + self._setup() + foo = self.frame().FindVariable("foo") bar = self.frame().FindVariable("bar") - baz = self.frame().FindVariable("baz") self.assertTrue(foo.IsValid(), "foo is not valid") self.assertTrue(bar.IsValid(), "bar is not valid") - self.assertTrue(baz.IsValid(), "baz is not valid") fooPersist = foo.Persist() barPersist = bar.Persist() - bazPersist = baz.Persist() self.assertTrue(fooPersist.IsValid(), "fooPersist is not valid") self.assertTrue(barPersist.IsValid(), "barPersist is not valid") - self.assertTrue(bazPersist.IsValid(), "bazPersist is not valid") - self.assertEqual( - fooPersist.GetValueAsUnsigned(0), 10, - "fooPersist != 10") - self.assertEqual( - barPersist.GetPointeeData().sint32[0], 4, - "barPersist != 4") - self.assertEquals(bazPersist.GetSummary(), '"85"', "bazPersist != 85") + self.assertEqual(fooPersist.GetValueAsUnsigned(0), 10) + self.assertEqual(barPersist.GetPointeeData().sint32[0], 4) self.runCmd("continue") self.assertTrue(fooPersist.IsValid(), "fooPersist is not valid") self.assertTrue(barPersist.IsValid(), "barPersist is not valid") - self.assertTrue(bazPersist.IsValid(), "bazPersist is not valid") - self.assertEqual( - fooPersist.GetValueAsUnsigned(0), 10, - "fooPersist != 10") - self.assertEqual( - barPersist.GetPointeeData().sint32[0], 4, - "barPersist != 4") - self.assertEquals(bazPersist.GetSummary(), '"85"', "bazPersist != 85") + self.assertEqual(fooPersist.GetValueAsUnsigned(0), 10) + self.assertEqual(barPersist.GetPointeeData().sint32[0], 4) self.expect("expr *(%s)" % (barPersist.GetName()), substrs=['= 4']) + + @add_test_categories(['pyapi']) + def test_ephemeral(self): + self._setup() + + # Test persisting values created from data, i.e. not pointing to any + # location in the process memory. + var = self.frame().EvaluateExpression("1+1") + varPersist = var.Persist() + self.assertTrue(varPersist.IsValid(), "varPersist is not valid") + self.assertEqual(varPersist.value, "2") + # Shortcut for variable name. + p = varPersist.name + + val = self.frame().EvaluateExpression("{}".format(p)) + self.assertEqual(val.value, "2") + + val = self.frame().EvaluateExpression("++{}".format(p)) + self.assertEqual(val.value, "3") + + val = self.frame().EvaluateExpression("{}++ + {}".format(p, p)) + self.assertEqual(val.value, "7") + + val = self.frame().EvaluateExpression("{}".format(p)) + self.assertEqual(val.value, "4") + + val = self.frame().EvaluateExpression("{} + 1".format(p)) + self.assertEqual(val.value, "5") + + @add_test_categories(['pyapi']) + def test_cast_struct(self): + self._setup() + + var = self.frame().EvaluateExpression("(P&)mem") + varPersist = var.Persist() + self.assertTrue(varPersist.IsValid(), "varPersist is not valid") + # Shortcut for variable name. + p = varPersist.name + + val = self.frame().EvaluateExpression("{}.x".format(p)) + self.assertEqual(val.value, "1") + + val = self.frame().EvaluateExpression("{}.y".format(p)) + self.assertEqual(val.value, "1.5") + + val = self.frame().EvaluateExpression("++{}.y".format(p)) + self.assertEqual(val.value, "2.5") + + val = self.frame().EvaluateExpression("{}.y".format(p)) + self.assertEqual(val.value, "2.5") + + val = self.frame().EvaluateExpression("mem[1]".format(p)) + self.assertEqual(val.value, "1069547520") # 0x3fc00000 diff --git a/lldb/test/API/python_api/sbvalue_persist/main.cpp b/lldb/test/API/python_api/sbvalue_persist/main.cpp --- a/lldb/test/API/python_api/sbvalue_persist/main.cpp +++ b/lldb/test/API/python_api/sbvalue_persist/main.cpp @@ -1,14 +1,21 @@ -#include #include +#include void f() {} +struct P { + int x; + float y; +} _p; + int main() { - int foo = 10; - int *bar = new int(4); - std::string baz = "85"; - - f(); // break here - f(); // break here - return 0; + int foo = 10; + int *bar = new int(4); + std::string baz = "85"; + + int mem[] = {1, 0x3fc00000}; // P { x = 1, y = 1.5 } + + f(); // break here + f(); // break here + return 0; }