diff options
Diffstat (limited to 'lldb')
-rw-r--r-- | lldb/include/lldb/Core/FormatClasses.h | 8 | ||||
-rw-r--r-- | lldb/include/lldb/Core/InputReader.h | 26 | ||||
-rw-r--r-- | lldb/include/lldb/Core/InputReaderEZ.h | 6 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/ScriptInterpreter.h | 6 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/ScriptInterpreterPython.h | 3 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectType.cpp | 221 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectType.h | 31 | ||||
-rw-r--r-- | lldb/source/Core/FormatClasses.cpp | 15 | ||||
-rw-r--r-- | lldb/source/Core/InputReader.cpp | 4 | ||||
-rw-r--r-- | lldb/source/Core/InputReaderEZ.cpp | 16 | ||||
-rw-r--r-- | lldb/source/Core/ValueObjectSyntheticFilter.cpp | 9 | ||||
-rw-r--r-- | lldb/source/Interpreter/ScriptInterpreterPython.cpp | 48 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py | 2 |
13 files changed, 375 insertions, 20 deletions
diff --git a/lldb/include/lldb/Core/FormatClasses.h b/lldb/include/lldb/Core/FormatClasses.h index 2bb8383fb41..c18f64b62ac 100644 --- a/lldb/include/lldb/Core/FormatClasses.h +++ b/lldb/include/lldb/Core/FormatClasses.h @@ -303,7 +303,7 @@ public: virtual uint32_t CalculateNumChildren() { - if (m_wrapper == NULL) + if (m_wrapper == NULL || m_interpreter == NULL) return 0; return m_interpreter->CalculateNumChildren(m_wrapper); } @@ -311,7 +311,7 @@ public: virtual lldb::ValueObjectSP GetChildAtIndex (uint32_t idx, bool can_create) { - if (m_wrapper == NULL) + if (m_wrapper == NULL || m_interpreter == NULL) return lldb::ValueObjectSP(); PyObject* py_return = (PyObject*)m_interpreter->GetChildAtIndex(m_wrapper, idx); @@ -323,7 +323,7 @@ public: lldb::SBValue *sb_ptr = m_interpreter->CastPyObjectToSBValue(py_return); - if (py_return == NULL) + if (py_return == NULL || sb_ptr == NULL) return lldb::ValueObjectSP(); return sb_ptr->m_opaque_sp; @@ -332,7 +332,7 @@ public: virtual uint32_t GetIndexOfChildWithName (const ConstString &name) { - if (m_wrapper == NULL) + if (m_wrapper == NULL || m_interpreter == NULL) return UINT32_MAX; return m_interpreter->GetIndexOfChildWithName(m_wrapper, name.GetCString()); } diff --git a/lldb/include/lldb/Core/InputReader.h b/lldb/include/lldb/Core/InputReader.h index 0a250d0ccab..fa86e9a39e2 100644 --- a/lldb/include/lldb/Core/InputReader.h +++ b/lldb/include/lldb/Core/InputReader.h @@ -15,6 +15,7 @@ #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" #include "lldb/Core/Error.h" +#include "lldb/Core/StringList.h" #include "lldb/Host/Predicate.h" @@ -63,11 +64,13 @@ public: char* m_end_token; char* m_prompt; bool m_echo; + bool m_save_user_input; public: InitializationParameters() : m_baton(NULL), m_token_size(lldb::eInputReaderGranularityLine), - m_echo(true) + m_echo(true), + m_save_user_input(false) { SetEndToken("DONE"); SetPrompt("> "); @@ -81,6 +84,13 @@ public: } InitializationParameters& + SetSaveUserInput(bool s) + { + m_save_user_input = s; + return *this; + } + + InitializationParameters& SetBaton(void* b) { m_baton = b; @@ -191,6 +201,18 @@ public: { return m_echo; } + + StringList& + GetUserInput() + { + return m_user_input; + } + + virtual bool + GetSaveUserInput() + { + return false; + } // Subclasses _can_ override this function to get input as it comes in // without any granularity @@ -239,6 +261,8 @@ protected: bool m_echo; bool m_active; Predicate<bool> m_reader_done; + StringList m_user_input; + bool m_save_user_input; private: DISALLOW_COPY_AND_ASSIGN (InputReader); diff --git a/lldb/include/lldb/Core/InputReaderEZ.h b/lldb/include/lldb/Core/InputReaderEZ.h index 1ff7f25629b..4f7bc11a4b5 100644 --- a/lldb/include/lldb/Core/InputReaderEZ.h +++ b/lldb/include/lldb/Core/InputReaderEZ.h @@ -75,6 +75,12 @@ public: virtual void DoneHandler(HandlerData&) {} + virtual bool + GetSaveUserInput() + { + return m_save_user_input; + } + protected: friend class Debugger; diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index b83617e6a45..484062bfb68 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -101,6 +101,12 @@ public: return false; } + virtual bool + GenerateTypeSynthClass (StringList &input, StringList &output) + { + return false; + } + virtual void* CreateSyntheticScriptedProvider (std::string class_name, lldb::ValueObjectSP valobj) diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index f107fe5c3da..563a7d3bc02 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -52,6 +52,9 @@ public: bool GenerateTypeScriptFunction (StringList &input, StringList &output); + bool + GenerateTypeSynthClass (StringList &input, StringList &output); + // use this if the function code is just a one-liner script bool GenerateTypeScriptFunction (const char* oneliner, StringList &output); diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index 0e15dbcf74f..aea2c82e5c8 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -691,7 +691,6 @@ CommandObjectTypeSummaryAdd::CollectPythonScript (ScriptAddOptions *options, result.AppendError("out of memory"); result.SetStatus (eReturnStatusFailed); } - } bool @@ -2372,6 +2371,148 @@ CommandObjectTypeSynthClear::CommandOptions::g_option_table[] = // CommandObjectTypeSynthAdd //------------------------------------------------------------------------- +static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" + "You must define a Python class with three methods:\n" + "def __init__(self, valobj, dict):\n" + "def get_child_at_index(self, index):\n" + "def get_child_index(self, name):\n" + "class synthProvider:"; + +class TypeSynthAddInputReader : public InputReaderEZ +{ +private: + DISALLOW_COPY_AND_ASSIGN (TypeSynthAddInputReader); +public: + TypeSynthAddInputReader(Debugger& debugger) : + InputReaderEZ(debugger) + {} + + virtual + ~TypeSynthAddInputReader() + { + } + + virtual void ActivateHandler(HandlerData& data) + { + StreamSP out_stream = data.GetOutStream(); + bool batch_mode = data.GetBatchMode(); + if (!batch_mode) + { + out_stream->Printf ("%s\n", g_synth_addreader_instructions); + if (data.reader.GetPrompt()) + out_stream->Printf ("%s", data.reader.GetPrompt()); + out_stream->Flush(); + } + } + + virtual void ReactivateHandler(HandlerData& data) + { + StreamSP out_stream = data.GetOutStream(); + bool batch_mode = data.GetBatchMode(); + if (data.reader.GetPrompt() && !batch_mode) + { + out_stream->Printf ("%s", data.reader.GetPrompt()); + out_stream->Flush(); + } + } + virtual void GotTokenHandler(HandlerData& data) + { + StreamSP out_stream = data.GetOutStream(); + bool batch_mode = data.GetBatchMode(); + if (data.bytes && data.bytes_len && data.baton) + { + ((SynthAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len); + } + if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode) + { + out_stream->Printf ("%s", data.reader.GetPrompt()); + out_stream->Flush(); + } + } + virtual void InterruptHandler(HandlerData& data) + { + StreamSP out_stream = data.GetOutStream(); + bool batch_mode = data.GetBatchMode(); + data.reader.SetIsDone (true); + if (!batch_mode) + { + out_stream->Printf ("Warning: No command attached to breakpoint.\n"); + out_stream->Flush(); + } + } + virtual void EOFHandler(HandlerData& data) + { + data.reader.SetIsDone (true); + } + virtual void DoneHandler(HandlerData& data) + { + StreamSP out_stream = data.GetOutStream(); + SynthAddOptions *options_ptr = ((SynthAddOptions*)data.baton); + if (!options_ptr) + { + out_stream->Printf ("Internal error #1: no script attached.\n"); + out_stream->Flush(); + return; + } + + SynthAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope + + ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (!interpreter) + { + out_stream->Printf ("Internal error #2: no script attached.\n"); + out_stream->Flush(); + return; + } + StringList class_name_sl; + if (!interpreter->GenerateTypeSynthClass (options->m_user_source, + class_name_sl)) + { + out_stream->Printf ("Internal error #3: no script attached.\n"); + out_stream->Flush(); + return; + } + if (class_name_sl.GetSize() == 0) + { + out_stream->Printf ("Internal error #4: no script attached.\n"); + out_stream->Flush(); + return; + } + const char *class_name = class_name_sl.GetStringAtIndex(0); + if (!class_name || !class_name[0]) + { + out_stream->Printf ("Internal error #5: no script attached.\n"); + out_stream->Flush(); + return; + } + + // everything should be fine now, let's add the synth provider class + + SyntheticChildrenSP synth_provider; + synth_provider.reset(new SyntheticScriptProvider(options->m_cascade, + options->m_skip_pointers, + options->m_skip_references, + std::string(class_name))); + + + lldb::FormatCategorySP category; + Debugger::Formatting::Categories::Get(ConstString(options->m_category), category); + + for (size_t i = 0; i < options->m_target_types.GetSize(); i++) { + const char *type_name = options->m_target_types.GetStringAtIndex(i); + ConstString typeCS(type_name); + if (typeCS) + category->Filter()->Add(typeCS.GetCString(), synth_provider); + else + { + out_stream->Printf ("Internal error #6: no script attached.\n"); + out_stream->Flush(); + return; + } + } + } +}; + class CommandObjectTypeSynthAdd : public CommandObject { @@ -2406,6 +2547,10 @@ private: break; case 'c': m_expr_paths.push_back(option_arg); + has_child_list = true; + break; + case 'P': + handwrite_python = true; break; case 'l': m_class_name = std::string(option_arg); @@ -2438,6 +2583,8 @@ private: m_category = NULL; m_expr_paths.clear(); is_class_based = false; + handwrite_python = false; + has_child_list = false; } const OptionDefinition* @@ -2462,6 +2609,10 @@ private: bool is_class_based; + bool handwrite_python; + + bool has_child_list; + typedef option_vector::iterator ExpressionPathsIterator; }; @@ -2473,6 +2624,61 @@ private: return &m_options; } + void + CollectPythonScript (SynthAddOptions *options, + CommandReturnObject &result) + { + InputReaderSP reader_sp (new TypeSynthAddInputReader(m_interpreter.GetDebugger())); + if (reader_sp && options) + { + + InputReaderEZ::InitializationParameters ipr; + + Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" "))); + if (err.Success()) + { + m_interpreter.GetDebugger().PushInputReader (reader_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError (err.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError("out of memory"); + result.SetStatus (eReturnStatusFailed); + } + } + + bool + Execute_HandwritePython (Args& command, CommandReturnObject &result) + { + SynthAddOptions *options = new SynthAddOptions ( m_options.m_skip_pointers, + m_options.m_skip_references, + m_options.m_cascade, + m_options.m_category); + + const size_t argc = command.GetArgumentCount(); + + for (size_t i = 0; i < argc; i++) { + const char* typeA = command.GetArgumentAtIndex(i); + if (typeA && *typeA) + options->m_target_types << typeA; + else + { + result.AppendError("empty typenames not allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + + CollectPythonScript(options,result); + return result.Succeeded(); + } + bool Execute_ChildrenList (Args& command, CommandReturnObject &result) { @@ -2606,10 +2812,18 @@ public: bool Execute (Args& command, CommandReturnObject &result) { - if (m_options.is_class_based) + if (m_options.handwrite_python) + return Execute_HandwritePython(command, result); + else if (m_options.is_class_based) return Execute_PythonClass(command, result); - else + else if (m_options.has_child_list) return Execute_ChildrenList(command, result); + else + { + result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line"); + result.SetStatus(eReturnStatusFailed); + return false; + } } }; @@ -2622,6 +2836,7 @@ CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, { LLDB_OPT_SET_1, false, "child", 'c', required_argument, NULL, 0, eArgTypeName, "Include this expression path in the synthetic view."}, { LLDB_OPT_SET_2, false, "python-class", 'l', required_argument, NULL, 0, eArgTypeName, "Use this Python class to produce synthetic children."}, + { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeBoolean, "Type Python code to generate a class that provides synthetic children."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; diff --git a/lldb/source/Commands/CommandObjectType.h b/lldb/source/Commands/CommandObjectType.h index c37bc70a8b3..1e5279de470 100644 --- a/lldb/source/Commands/CommandObjectType.h +++ b/lldb/source/Commands/CommandObjectType.h @@ -70,6 +70,37 @@ public: }; +class SynthAddOptions +{ + +public: + + bool m_skip_pointers; + bool m_skip_references; + bool m_cascade; + StringList m_user_source; + StringList m_target_types; + + const char* m_category; + + SynthAddOptions(bool sptr, + bool sref, + bool casc, + const char* catg) : + m_skip_pointers(sptr), + m_skip_references(sref), + m_cascade(casc), + m_user_source(), + m_target_types(), + m_category(catg) + { + } + + typedef lldb::SharedPtr<SynthAddOptions>::Type SharedPointer; + +}; + + class CommandObjectType : public CommandObjectMultiword { public: diff --git a/lldb/source/Core/FormatClasses.cpp b/lldb/source/Core/FormatClasses.cpp index 9a232ae7af4..e321a40a310 100644 --- a/lldb/source/Core/FormatClasses.cpp +++ b/lldb/source/Core/FormatClasses.cpp @@ -164,15 +164,26 @@ SyntheticScriptProvider::FrontEnd::FrontEnd(std::string pclass, SyntheticChildrenFrontEnd(be), m_python_class(pclass) { + if (be.get() == NULL) + { + m_interpreter = NULL; + m_wrapper = NULL; + return; + } + m_interpreter = be->GetUpdatePoint().GetTarget()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - m_wrapper = (PyObject*)m_interpreter->CreateSyntheticScriptedProvider(m_python_class, m_backend); + + if (m_interpreter == NULL) + m_wrapper = NULL; + else + m_wrapper = (PyObject*)m_interpreter->CreateSyntheticScriptedProvider(m_python_class, m_backend); } std::string SyntheticScriptProvider::GetDescription() { StreamString sstr; - sstr.Printf("%s%s%s Python class: %s", + sstr.Printf("%s%s%s Python class %s", m_cascades ? "" : " (not cascading)", m_skip_pointers ? " (skip pointers)" : "", m_skip_references ? " (skip references)" : "", diff --git a/lldb/source/Core/InputReader.cpp b/lldb/source/Core/InputReader.cpp index 84cd0a15f84..ebde2be9a96 100644 --- a/lldb/source/Core/InputReader.cpp +++ b/lldb/source/Core/InputReader.cpp @@ -25,7 +25,9 @@ InputReader::InputReader (Debugger &debugger) : m_done (true), m_echo (true), m_active (false), - m_reader_done (false) + m_reader_done (false), + m_user_input(), + m_save_user_input(false) { } diff --git a/lldb/source/Core/InputReaderEZ.cpp b/lldb/source/Core/InputReaderEZ.cpp index 295bfb82b31..c8362fbb8f5 100644 --- a/lldb/source/Core/InputReaderEZ.cpp +++ b/lldb/source/Core/InputReaderEZ.cpp @@ -45,7 +45,11 @@ InputReaderEZ::Callback_Impl(void *baton, reader.AsynchronousOutputWrittenHandler(hand_data); break; case eInputReaderGotToken: + { + if (reader.GetSaveUserInput()) + reader.GetUserInput().AppendString(bytes, bytes_len); reader.GotTokenHandler(hand_data); + } break; case eInputReaderInterrupt: reader.InterruptHandler(hand_data); @@ -78,11 +82,13 @@ InputReaderEZ::Initialize(void* baton, Error InputReaderEZ::Initialize(InitializationParameters& params) { - return Initialize(params.m_baton, - params.m_token_size, - params.m_end_token, - params.m_prompt, - params.m_echo); + Error ret = Initialize(params.m_baton, + params.m_token_size, + params.m_end_token, + params.m_prompt, + params.m_echo); + m_save_user_input = params.m_save_user_input; + return ret; } InputReaderEZ::~InputReaderEZ () diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp index d7d00b64611..252780cf11f 100644 --- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -131,7 +131,7 @@ ValueObjectSynthetic::GetChildAtIndex (uint32_t idx, bool can_create) if (iter == m_children_byindex.end()) { - if (can_create) + if (can_create && m_synth_filter != NULL) { lldb::ValueObjectSP synth_guy = m_synth_filter->GetChildAtIndex (idx, can_create); m_children_byindex[idx]= synth_guy; @@ -161,13 +161,16 @@ ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name) { NameToIndexIterator iter = m_name_toindex.find(name.GetCString()); - if (iter == m_name_toindex.end()) + if (iter == m_name_toindex.end() && m_synth_filter != NULL) { uint32_t index = m_synth_filter->GetIndexOfChildWithName (name); m_name_toindex[name.GetCString()] = index; return index; } - return iter->second; + else if (iter == m_name_toindex.end() && m_synth_filter == NULL) + return UINT32_MAX; + else /*if (iter != m_name_toindex.end())*/ + return iter->second; } bool diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 03eadc6f549..82cad851028 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -1249,6 +1249,54 @@ ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, Str return true; } +bool +ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, StringList &output) +{ + static int num_created_classes = 0; + user_input.RemoveBlankLines (); + int num_lines = user_input.GetSize (); + StreamString sstr; + + // Check to see if we have any data; if not, just return. + if (user_input.GetSize() == 0) + return false; + + // Wrap all user input into a Python class + + sstr.Printf ("lldb_autogen_python_type_synth_class_%d", num_created_classes); + ++num_created_classes; + std::string auto_generated_class_name = sstr.GetData(); + + sstr.Clear(); + StringList auto_generated_class; + + // Create the function name & definition string. + + sstr.Printf ("class %s:", auto_generated_class_name.c_str()); + auto_generated_class.AppendString (sstr.GetData()); + + // Wrap everything up inside the class, increasing the indentation. + + for (int i = 0; i < num_lines; ++i) + { + sstr.Clear (); + sstr.Printf (" %s", user_input.GetStringAtIndex (i)); + auto_generated_class.AppendString (sstr.GetData()); + } + + + // Verify that the results are valid Python. + // (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported) + // (TODO: rename that method to ExportDefinitionToInterpreter) + if (!ExportFunctionDefinitionToInterpreter (auto_generated_class)) + return false; + + // Store the name of the auto-generated class + + output.AppendString (auto_generated_class_name.c_str()); + return true; +} + void* ScriptInterpreterPython::CreateSyntheticScriptedProvider (std::string class_name, lldb::ValueObjectSP valobj) diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py index add34074fb0..2d953265c6b 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py @@ -13,4 +13,4 @@ class fooSynthProvider: if name == 'a': return 1; else: - return 0;
\ No newline at end of file + return 0; |