From 0c10a85000074f1e8ac0fa88c853ede7b45818d4 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Mon, 8 Dec 2014 23:13:56 +0000 Subject: [PATCH] Add the ability for an SBValue to create a persisted version of itself. Such a persisted version is equivalent to evaluating the value via the expression evaluator, and holding on to the $n result of the expression, except this API can be used on SBValues that do not obviously come from an expression (e.g. are the result of a memory lookup) Expose this via SBValue::Persist() in our public API layer, and ValueObject::Persist() in the lldb_private layer Includes testcase Fixes rdar://19136664 llvm-svn: 223711 --- lldb/include/lldb/API/SBValue.h | 3 + lldb/include/lldb/Core/ValueObject.h | 3 + lldb/include/lldb/Core/ValueObjectConstResult.h | 6 +- .../lldb/Expression/ClangExpressionVariable.h | 5 ++ lldb/scripts/Python/interface/SBValue.i | 3 + lldb/source/API/SBValue.cpp | 13 +++ lldb/source/Core/ValueObject.cpp | 26 ++++++ lldb/source/Core/ValueObjectConstResult.cpp | 12 ++- lldb/source/Expression/ClangExpressionVariable.cpp | 11 +++ lldb/test/python_api/sbvalue_persist/Makefile | 8 ++ .../sbvalue_persist/TestSBValuePersist.py | 94 ++++++++++++++++++++++ lldb/test/python_api/sbvalue_persist/main.cpp | 14 ++++ 12 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 lldb/test/python_api/sbvalue_persist/Makefile create mode 100644 lldb/test/python_api/sbvalue_persist/TestSBValuePersist.py create mode 100644 lldb/test/python_api/sbvalue_persist/main.cpp diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 427b9ef..bedac4e 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -353,6 +353,9 @@ public: lldb::SBType GetType(); + + lldb::SBValue + Persist (); bool GetDescription (lldb::SBStream &description); diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 75c4f34..6f56955 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -814,6 +814,9 @@ public: const DumpValueObjectOptions& options); + lldb::ValueObjectSP + Persist (); + // returns true if this is a char* or a char[] // if it is a char* and check_pointer is true, // it also checks that the pointer is valid diff --git a/lldb/include/lldb/Core/ValueObjectConstResult.h b/lldb/include/lldb/Core/ValueObjectConstResult.h index a1d6181..4e05d50 100644 --- a/lldb/include/lldb/Core/ValueObjectConstResult.h +++ b/lldb/include/lldb/Core/ValueObjectConstResult.h @@ -59,7 +59,8 @@ public: static lldb::ValueObjectSP Create (ExecutionContextScope *exe_scope, Value &value, - const ConstString &name); + const ConstString &name, + Module* module = nullptr); // When an expression fails to evaluate, we return an error static lldb::ValueObjectSP @@ -172,7 +173,8 @@ private: ValueObjectConstResult (ExecutionContextScope *exe_scope, const Value &value, - const ConstString &name); + const ConstString &name, + Module* module = nullptr); ValueObjectConstResult (ExecutionContextScope *exe_scope, const Error& error); diff --git a/lldb/include/lldb/Expression/ClangExpressionVariable.h b/lldb/include/lldb/Expression/ClangExpressionVariable.h index 5ee7a30..6c21010 100644 --- a/lldb/include/lldb/Expression/ClangExpressionVariable.h +++ b/lldb/include/lldb/Expression/ClangExpressionVariable.h @@ -65,6 +65,11 @@ class ClangExpressionVariable public: ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size); + ClangExpressionVariable (ExecutionContextScope *exe_scope, + Value &value, + const ConstString &name, + uint16_t flags = EVNone); + ClangExpressionVariable(const lldb::ValueObjectSP &valobj_sp); //---------------------------------------------------------------------- diff --git a/lldb/scripts/Python/interface/SBValue.i b/lldb/scripts/Python/interface/SBValue.i index 728dae9..0393807 100644 --- a/lldb/scripts/Python/interface/SBValue.i +++ b/lldb/scripts/Python/interface/SBValue.i @@ -413,6 +413,9 @@ public: lldb::SBAddress GetAddress(); + lldb::SBValue + Persist (); + %feature("docstring", "Returns an expression path for this value." ) GetExpressionPath; bool diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index f56013a..f8c75eb 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -1892,3 +1892,16 @@ SBValue::WatchPointee (bool resolve_location, bool read, bool write, SBError &er sb_watchpoint = Dereference().Watch (resolve_location, read, write, error); return sb_watchpoint; } + +lldb::SBValue +SBValue::Persist () +{ + ValueLocker locker; + lldb::ValueObjectSP value_sp(GetSP(locker)); + SBValue persisted_sb; + if (value_sp) + { + persisted_sb.SetSP(value_sp->Persist()); + } + return persisted_sb; +} diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 1c3d148..f6d1352 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -37,6 +37,9 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" +#include "lldb/Expression/ClangExpressionVariable.h" +#include "lldb/Expression/ClangPersistentVariables.h" + #include "lldb/Host/Endian.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -4180,3 +4183,26 @@ ValueObject::CanProvideValue () { return (false == GetClangType().IsAggregateType()); } + +ValueObjectSP +ValueObject::Persist () +{ + if (!UpdateValueIfNeeded()) + return nullptr; + + TargetSP target_sp(GetTargetSP()); + if (!target_sp) + return nullptr; + + ConstString name(target_sp->GetPersistentVariables().GetNextPersistentVariableName()); + + ClangExpressionVariableSP clang_var_sp(new ClangExpressionVariable(target_sp.get(), GetValue(), name)); + if (clang_var_sp) + { + clang_var_sp->m_live_sp = clang_var_sp->m_frozen_sp; + clang_var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference; + target_sp->GetPersistentVariables().AddVariable(clang_var_sp); + } + + return clang_var_sp->GetValueObject(); +} diff --git a/lldb/source/Core/ValueObjectConstResult.cpp b/lldb/source/Core/ValueObjectConstResult.cpp index b88830f..fc870d7 100644 --- a/lldb/source/Core/ValueObjectConstResult.cpp +++ b/lldb/source/Core/ValueObjectConstResult.cpp @@ -122,9 +122,10 @@ ValueObjectConstResult::Create (ExecutionContextScope *exe_scope, ValueObjectSP ValueObjectConstResult::Create (ExecutionContextScope *exe_scope, Value &value, - const ConstString &name) + const ConstString &name, + Module *module) { - return (new ValueObjectConstResult (exe_scope, value, name))->GetSP(); + return (new ValueObjectConstResult (exe_scope, value, name, module))->GetSP(); } ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope, @@ -222,15 +223,18 @@ ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope, const Value &value, - const ConstString &name) : + const ConstString &name, + Module *module) : ValueObject (exe_scope), m_type_name (), m_byte_size (0), m_impl(this) { m_value = value; - m_value.GetData(m_data); m_name = name; + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, module); } ValueObjectConstResult::~ValueObjectConstResult() diff --git a/lldb/source/Expression/ClangExpressionVariable.cpp b/lldb/source/Expression/ClangExpressionVariable.cpp index c3eae41..e86016e 100644 --- a/lldb/source/Expression/ClangExpressionVariable.cpp +++ b/lldb/source/Expression/ClangExpressionVariable.cpp @@ -28,6 +28,17 @@ ClangExpressionVariable::ClangExpressionVariable(ExecutionContextScope *exe_scop { } +ClangExpressionVariable::ClangExpressionVariable (ExecutionContextScope *exe_scope, + Value &value, + const ConstString &name, + uint16_t flags) : + m_parser_vars(), + m_jit_vars (), + m_flags (flags), + m_frozen_sp (ValueObjectConstResult::Create (exe_scope, value, name)) +{ +} + ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &valobj_sp) : m_parser_vars(), m_jit_vars (), diff --git a/lldb/test/python_api/sbvalue_persist/Makefile b/lldb/test/python_api/sbvalue_persist/Makefile new file mode 100644 index 0000000..ddffdcf --- /dev/null +++ b/lldb/test/python_api/sbvalue_persist/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../make + +CXX_SOURCES := main.cpp + +# Clean renamed executable on 'make clean' +clean: OBJECTS+=no_synth + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/python_api/sbvalue_persist/TestSBValuePersist.py b/lldb/test/python_api/sbvalue_persist/TestSBValuePersist.py new file mode 100644 index 0000000..d05274f --- /dev/null +++ b/lldb/test/python_api/sbvalue_persist/TestSBValuePersist.py @@ -0,0 +1,94 @@ +"""Test SBValue::Persist""" + +import os, sys, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class SBValuePersistTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @python_api_test + @dsym_test + def test_with_dsym(self): + """Test SBValue::Persist""" + self.buildDsym() + self.setTearDownCleanup() + self.doTest() + + @python_api_test + @dwarf_test + def test_with_dwarf(self): + """Test SBValue::Persist""" + self.buildDwarf() + self.setTearDownCleanup() + self.doTest() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + def doTest(self): + """Test SBValue::Persist""" + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_source_regexp (self, "break here") + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', + 'stop reason = breakpoint']) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd('type format clear', check=False) + self.runCmd('type summary clear', check=False) + self.runCmd('type filter clear', check=False) + self.runCmd('type synthetic clear', check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + 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.assertTrue(fooPersist.GetValueAsUnsigned(0) == 10, "fooPersist != 10") + self.assertTrue(barPersist.GetPointeeData().sint32[0] == 4, "barPersist != 4") + self.assertTrue(bazPersist.GetSummary() == '"85"', "bazPersist != 85") + + 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.assertTrue(fooPersist.GetValueAsUnsigned(0) == 10, "fooPersist != 10") + self.assertTrue(barPersist.GetPointeeData().sint32[0] == 4, "barPersist != 4") + self.assertTrue(bazPersist.GetSummary() == '"85"', "bazPersist != 85") + + self.expect("expr *(%s)" % (barPersist.GetName()), substrs = ['= 4']) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/python_api/sbvalue_persist/main.cpp b/lldb/test/python_api/sbvalue_persist/main.cpp new file mode 100644 index 0000000..650d87a --- /dev/null +++ b/lldb/test/python_api/sbvalue_persist/main.cpp @@ -0,0 +1,14 @@ +#include +#include + +void f() {} + +int main() { + int foo = 10; + int *bar = new int(4); + std::string baz = "85"; + + f(); // break here + f(); // break here + return 0; +} \ No newline at end of file -- 2.7.4