From: Enrico Granata Date: Tue, 28 Oct 2014 21:07:00 +0000 (+0000) Subject: Add a feature where a string data formatter can now be partially composed of Python... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=88282c69f3cb26aa9c2b805768866bda575cac84;p=platform%2Fupstream%2Fllvm.git Add a feature where a string data formatter can now be partially composed of Python summary functions This works similarly to the {thread/frame/process/target.script:...} feature - you write a summary string, part of which is ${var.script:someFuncName} someFuncName is expected to be declared as def someFuncName(SBValue,otherArgument) - essentially the same as a summary function Since . -> [] are the only allowed separators, and % is used for custom formatting, .script: would not be a legitimate symbol anyway, which makes this non-ambiguous llvm-svn: 220821 --- diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index e7a456d..e1b7647 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -152,6 +152,11 @@ public: const char* session_dictionary_name, lldb::StackFrameSP& frame, std::string& output); + + typedef bool (*SWIGPythonScriptKeyword_Value) (const char* python_function_name, + const char* session_dictionary_name, + lldb::ValueObjectSP& value, + std::string& output); typedef void* (*SWIGPython_GetDynamicSetting) (void* module, const char* setting, @@ -556,6 +561,16 @@ public: } virtual bool + RunScriptFormatKeyword (const char* impl_function, + ValueObject* value, + std::string& output, + Error& error) + { + error.SetErrorString("unimplemented"); + return false; + } + + virtual bool GetDocumentationForItem (const char* item, std::string& dest) { dest.clear(); @@ -621,6 +636,7 @@ public: SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, + SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, SWIGPython_GetDynamicSetting swig_plugin_get, SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, SWIGPythonCallThreadPlan swig_call_thread_plan); diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index 2cdb839..3890264 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -232,6 +232,12 @@ public: Error& error); virtual bool + RunScriptFormatKeyword (const char* impl_function, + ValueObject* value, + std::string& output, + Error& error); + + virtual bool LoadScriptingModule (const char* filename, bool can_reload, bool init_session, @@ -296,6 +302,7 @@ public: SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, + SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, SWIGPython_GetDynamicSetting swig_plugin_get, SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, SWIGPythonCallThreadPlan swig_call_thread_plan); diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig index 35145c2..1eaa52b 100644 --- a/lldb/scripts/Python/python-wrapper.swig +++ b/lldb/scripts/Python/python-wrapper.swig @@ -1060,6 +1060,44 @@ std::string& output) } SWIGEXPORT bool +LLDBSWIGPythonRunScriptKeywordValue +(const char* python_function_name, +const char* session_dictionary_name, +lldb::ValueObjectSP& value, +std::string& output) + +{ + bool retval = false; + + if (python_function_name == NULL || python_function_name[0] == '\0' || !session_dictionary_name) + return retval; + + lldb::SBValue value_sb(value); + + { + PyErr_Cleaner py_err_cleaner(true); + + PyCallable pfunc = PyCallable::FindWithFunctionName(python_function_name,session_dictionary_name); + + if (!pfunc) + return retval; + + PyObject* session_dict = NULL; + PyObject* pvalue = NULL; + pvalue = pfunc(value_sb, session_dict = FindSessionDictionary(session_dictionary_name)); + + Py_XINCREF (session_dict); + + if (PyObjectToString(pvalue,output)) + retval = true; + + Py_XDECREF(pvalue); + } + + return retval; +} + +SWIGEXPORT bool LLDBSwigPythonCallModuleInit ( const char *python_module_name, diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp index 4e65c4f..e9e5b1f 100644 --- a/lldb/source/API/SBCommandInterpreter.cpp +++ b/lldb/source/API/SBCommandInterpreter.cpp @@ -679,6 +679,12 @@ LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name, lldb::StackFrameSP& frame, std::string& output); +extern "C" bool +LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name, + const char* session_dictionary_name, + lldb::ValueObjectSP& value, + std::string& output); + extern "C" void* LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, @@ -715,6 +721,7 @@ SBCommandInterpreter::InitializeSWIG () LLDBSWIGPythonRunScriptKeywordThread, LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame, + LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting, LLDBSwigPythonCreateScriptedThreadPlan, LLDBSWIGPythonCallThreadPlan); diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 4948b83..11328e4 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1735,6 +1735,15 @@ FormatPromptRecurse target = valobj; val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; } + else if (IsToken (var_name_begin, "var.script:")) + { + var_name_begin += ::strlen("var.script:"); + std::string script_name(var_name_begin,var_name_end); + ScriptInterpreter* script_interpreter = valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (RunScriptFormatKeyword (s, script_interpreter, valobj, script_name)) + var_success = true; + break; + } else if (IsToken (var_name_begin,"var%")) { was_var_format = true; diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index 87bfc95..45e3b44 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -132,6 +132,7 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, + SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, SWIGPython_GetDynamicSetting swig_plugin_get, SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, SWIGPythonCallThreadPlan swig_call_thread_plan) @@ -157,6 +158,7 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call swig_run_script_keyword_thread, swig_run_script_keyword_target, swig_run_script_keyword_frame, + swig_run_script_keyword_value, swig_plugin_get, swig_thread_plan_script, swig_call_thread_plan); diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 8e03e7b..aee0ae4 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -67,6 +67,7 @@ static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyw static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = nullptr; static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr; static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr; +static ScriptInterpreter::SWIGPythonScriptKeyword_Value g_swig_run_script_keyword_value = nullptr; static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr; static ScriptInterpreter::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr; static ScriptInterpreter::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr; @@ -2376,6 +2377,38 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } return ret_val; } + +bool +ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, + ValueObject *value, + std::string& output, + Error& error) +{ + bool ret_val; + if (!value) + { + error.SetErrorString("no value"); + return false; + } + if (!impl_function || !impl_function[0]) + { + error.SetErrorString("no function to execute"); + return false; + } + if (!g_swig_run_script_keyword_value) + { + error.SetErrorString("internal helper function missing"); + return false; + } + { + ValueObjectSP value_sp(value->GetSP()); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = g_swig_run_script_keyword_value (impl_function, m_dictionary_name.c_str(), value_sp, output); + if (!ret_val) + error.SetErrorString("python script evaluation failed"); + } + return ret_val; +} uint64_t replace_all(std::string& str, const std::string& oldStr, const std::string& newStr) { @@ -2676,6 +2709,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, + SWIGPythonScriptKeyword_Value swig_run_script_keyword_value, SWIGPython_GetDynamicSetting swig_plugin_get, SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, SWIGPythonCallThreadPlan swig_call_thread_plan) @@ -2700,6 +2734,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb g_swig_run_script_keyword_thread = swig_run_script_keyword_thread; g_swig_run_script_keyword_target = swig_run_script_keyword_target; g_swig_run_script_keyword_frame = swig_run_script_keyword_frame; + g_swig_run_script_keyword_value = swig_run_script_keyword_value; g_swig_plugin_get = swig_plugin_get; g_swig_thread_plan_script = swig_thread_plan_script; g_swig_call_thread_plan = swig_call_thread_plan; diff --git a/lldb/test/functionalities/data-formatter/varscript_formatting/Makefile b/lldb/test/functionalities/data-formatter/varscript_formatting/Makefile new file mode 100644 index 0000000..314f1cb --- /dev/null +++ b/lldb/test/functionalities/data-formatter/varscript_formatting/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/data-formatter/varscript_formatting/TestDataFormatterVarScriptFormatting.py b/lldb/test/functionalities/data-formatter/varscript_formatting/TestDataFormatterVarScriptFormatting.py new file mode 100644 index 0000000..f49706f --- /dev/null +++ b/lldb/test/functionalities/data-formatter/varscript_formatting/TestDataFormatterVarScriptFormatting.py @@ -0,0 +1,71 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil +import os.path + +class PythonSynthDataFormatterTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym_and_run_command(self): + """Test data formatter commands.""" + self.buildDsym() + self.data_formatter_commands() + + @skipIfFreeBSD # llvm.org/pr20545 bogus output confuses buildbot parser + @dwarf_test + def test_with_dwarf_and_run_command(self): + """Test data formatter commands.""" + self.buildDwarf() + self.data_formatter_commands() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number('main.cpp', ' // Set breakpoint here.') + + def data_formatter_commands(self): + """Test using Python synthetic children provider.""" + 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=True) + + 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 synth clear', check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.runCmd("command script import helperfunc.py") + self.runCmd('type summary add -x "^something<.*>$" -s "T is a ${var.script:helperfunc.f}"') + + self.expect("frame variable x", substrs = ['T is a non-pointer type']); + + self.expect("frame variable y", substrs = ['T is a pointer type']); + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/varscript_formatting/helperfunc.py b/lldb/test/functionalities/data-formatter/varscript_formatting/helperfunc.py new file mode 100644 index 0000000..01562c5 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/varscript_formatting/helperfunc.py @@ -0,0 +1,5 @@ +import lldb + +def f(value,d): + return "pointer type" if value.GetType().GetTemplateArgumentType(0).IsPointerType() else "non-pointer type" + diff --git a/lldb/test/functionalities/data-formatter/varscript_formatting/main.cpp b/lldb/test/functionalities/data-formatter/varscript_formatting/main.cpp new file mode 100644 index 0000000..4dc94af --- /dev/null +++ b/lldb/test/functionalities/data-formatter/varscript_formatting/main.cpp @@ -0,0 +1,8 @@ +template +struct something {}; + +int main() { + something x; + something y; + return 0; // Set breakpoint here. +} \ No newline at end of file