diff options
-rw-r--r-- | lldb/include/lldb/Core/Debugger.h | 52 | ||||
-rw-r--r-- | lldb/include/lldb/Core/FormatManager.h | 77 | ||||
-rw-r--r-- | lldb/include/lldb/Core/InputReader.h | 65 | ||||
-rw-r--r-- | lldb/include/lldb/Core/InputReaderEZ.h | 18 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectType.cpp | 1046 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectType.h | 145 | ||||
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 84 | ||||
-rw-r--r-- | lldb/source/Core/InputReaderEZ.cpp | 10 | ||||
-rw-r--r-- | lldb/source/Core/ValueObject.cpp | 135 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Symbol/TypeHierarchyNavigator.cpp | 8 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py | 71 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-script/main.cpp | 4 |
13 files changed, 1137 insertions, 580 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index ea9a648ee12..7bbdf0632fb 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -525,6 +525,32 @@ public: GetCount(); }; + class SystemSummaryFormats + { + public: + + static bool + Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry); + + static void + Add(const ConstString &type, const SummaryFormat::SharedPointer &entry); + + static bool + Delete(const ConstString &type); + + static void + Clear(); + + static void + LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton); + + static uint32_t + GetCurrentRevision(); + + static uint32_t + GetCount(); + }; + class RegexSummaryFormats { public: @@ -551,6 +577,32 @@ public: GetCount(); }; + class SystemRegexSummaryFormats + { + public: + + static bool + Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry); + + static void + Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry); + + static bool + Delete(const ConstString &type); + + static void + Clear(); + + static void + LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton); + + static uint32_t + GetCurrentRevision(); + + static uint32_t + GetCount(); + }; + class NamedSummaryFormats { public: diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index 1fc4756f0bf..42579fc6b1c 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -150,19 +150,22 @@ struct SummaryFormat bool m_dont_show_children; bool m_dont_show_value; bool m_show_members_oneliner; + bool m_is_system; SummaryFormat(bool casc = false, bool skipptr = false, bool skipref = false, bool nochildren = true, bool novalue = true, - bool oneliner = false) : + bool oneliner = false, + bool system = false) : m_cascades(casc), m_skip_pointers(skipptr), m_skip_references(skipref), m_dont_show_children(nochildren), m_dont_show_value(novalue), - m_show_members_oneliner(oneliner) + m_show_members_oneliner(oneliner), + m_is_system(system) { } @@ -200,6 +203,12 @@ struct SummaryFormat return m_show_members_oneliner; } + bool + IsSystem() const + { + return m_is_system; + } + virtual ~SummaryFormat() { @@ -228,8 +237,9 @@ struct StringSummaryFormat : public SummaryFormat bool nochildren = true, bool novalue = true, bool oneliner = false, + bool system = false, std::string f = "") : - SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner), + SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner,system), m_format(f) { } @@ -252,13 +262,14 @@ struct StringSummaryFormat : public SummaryFormat GetDescription() { StreamString sstr; - sstr.Printf ("`%s`%s%s%s%s%s%s\n", m_format.c_str(), + sstr.Printf ("`%s`%s%s%s%s%s%s%s", m_format.c_str(), m_cascades ? "" : " (not cascading)", m_dont_show_children ? "" : " (show children)", m_dont_show_value ? " (hide value)" : "", m_show_members_oneliner ? " (one-line printout)" : "", m_skip_pointers ? " (skip pointers)" : "", - m_skip_references ? " (skip references)" : ""); + m_skip_references ? " (skip references)" : "", + m_is_system ? " (system)" : ""); return sstr.GetString(); } @@ -276,9 +287,10 @@ struct ScriptSummaryFormat : public SummaryFormat bool nochildren = true, bool novalue = true, bool oneliner = false, + bool system = false, std::string fname = "", std::string pscri = "") : - SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner), + SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner,system), m_function_name(fname), m_python_script(pscri) { @@ -312,10 +324,14 @@ struct ScriptSummaryFormat : public SummaryFormat GetDescription() { StreamString sstr; - sstr.Printf ("%s%s%s\n%s\n", m_cascades ? "" : " (not cascading)", - m_skip_pointers ? " (skip pointers)" : "", - m_skip_references ? " (skip references)" : "", - m_python_script.c_str()); + sstr.Printf ("%s%s%s%s%s%s%s\n%s", m_cascades ? "" : " (not cascading)", + m_dont_show_children ? "" : " (show children)", + m_dont_show_value ? " (hide value)" : "", + m_show_members_oneliner ? " (one-line printout)" : "", + m_skip_pointers ? " (skip pointers)" : "", + m_skip_references ? " (skip references)" : "", + m_is_system ? " (system)" : "", + m_python_script.c_str()); return sstr.GetString(); } @@ -727,12 +743,12 @@ private: ValueNavigator m_value_nav; SummaryNavigator m_summary_nav; + SummaryNavigator m_system_summary_nav; RegexSummaryNavigator m_regex_summary_nav; - + RegexSummaryNavigator m_system_regex_summary_nav; + NamedSummariesMap m_named_summaries_map; - - ScriptNavigator m_script_nav; - + uint32_t m_last_revision; public: @@ -740,19 +756,48 @@ public: FormatManager() : m_value_nav(this), m_summary_nav(this), + m_system_summary_nav(this), m_regex_summary_nav(this), + m_system_regex_summary_nav(this), m_named_summaries_map(this), - m_script_nav(this), m_last_revision(0) { + // add some default stuff + // most formats, summaries, ... actually belong to the users' lldbinit file rather than here + SummaryFormat::SharedPointer string_format(new StringSummaryFormat(false, + true, + false, + true, + false, + false, + true, + "${var%s}")); + + + SummaryFormat::SharedPointer string_array_format(new StringSummaryFormat(false, + true, + false, + false, + false, + false, + true, + "${var%s}")); + + lldb::RegularExpressionSP any_size_char_arr(new RegularExpression("char \\[[0-9]+\\]")); + + + SystemSummary().Add(ConstString("char *").GetCString(), string_format); + SystemSummary().Add(ConstString("const char *").GetCString(), string_format); + SystemRegexSummary().Add(any_size_char_arr, string_array_format); } ValueNavigator& Value() { return m_value_nav; } SummaryNavigator& Summary() { return m_summary_nav; } + SummaryNavigator& SystemSummary() { return m_system_summary_nav; } RegexSummaryNavigator& RegexSummary() { return m_regex_summary_nav; } + RegexSummaryNavigator& SystemRegexSummary() { return m_system_regex_summary_nav; } NamedSummariesMap& NamedSummary() { return m_named_summaries_map; } - ScriptNavigator& Script() { return m_script_nav; } static bool GetFormatFromCString (const char *format_cstr, diff --git a/lldb/include/lldb/Core/InputReader.h b/lldb/include/lldb/Core/InputReader.h index e1cc6aa2c08..15a81760c99 100644 --- a/lldb/include/lldb/Core/InputReader.h +++ b/lldb/include/lldb/Core/InputReader.h @@ -52,6 +52,65 @@ public: bool GetBatchMode(); }; + + struct InitializationParameters + { + private: + void* m_baton; + lldb::InputReaderGranularity m_token_size; + char* m_end_token; + char* m_prompt; + bool m_echo; + public: + InitializationParameters() : + m_baton(NULL), + m_token_size(lldb::eInputReaderGranularityLine), + m_echo(true) + { + SetEndToken("DONE"); + SetPrompt("> "); + } + + InitializationParameters& + SetEcho(bool e) + { + m_echo = e; + return *this; + } + + InitializationParameters& + SetBaton(void* b) + { + m_baton = b; + return *this; + } + + InitializationParameters& + SetGranularity(lldb::InputReaderGranularity g) + { + m_token_size = g; + return *this; + } + + InitializationParameters& + SetEndToken(const char* e) + { + m_end_token = new char[strlen(e)+1]; + ::strcpy(m_end_token,e); + return *this; + } + + InitializationParameters& + SetPrompt(const char* p) + { + m_prompt = new char[strlen(p)+1]; + ::strcpy(m_prompt,p); + return *this; + } + + friend class InputReaderEZ; + + }; InputReader (Debugger &debugger); @@ -75,6 +134,12 @@ public: return Error("unimplemented"); } + virtual Error + Initialize(InitializationParameters& params) + { + return Error("unimplemented"); + } + // to use these handlers instead of the Callback function, you must subclass // InputReaderEZ, and redefine the handlers for the events you care about virtual void diff --git a/lldb/include/lldb/Core/InputReaderEZ.h b/lldb/include/lldb/Core/InputReaderEZ.h index 95f6af9fc95..b41eb61f8ea 100644 --- a/lldb/include/lldb/Core/InputReaderEZ.h +++ b/lldb/include/lldb/Core/InputReaderEZ.h @@ -10,6 +10,8 @@ #ifndef liblldb_InputReaderEZ_h_ #define liblldb_InputReaderEZ_h_ +#include <string.h> + #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" #include "lldb/Core/Debugger.h" @@ -30,7 +32,7 @@ private: const char *bytes, size_t bytes_len); public: - + InputReaderEZ (Debugger &debugger) : InputReader(debugger) {} @@ -38,11 +40,15 @@ public: virtual ~InputReaderEZ (); - virtual Error Initialize(void* baton, - lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine, - const char* end_token = "DONE", - const char *prompt = "> ", - bool echo = true); + virtual Error + Initialize(void* baton, + lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine, + const char* end_token = "DONE", + const char *prompt = "> ", + bool echo = true); + + virtual Error + Initialize(InitializationParameters& params); virtual void ActivateHandler(HandlerData&) {} diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index b1e7c12bf46..770d61f15e8 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -176,7 +176,7 @@ public: return false; } - if(m_options.m_format == eFormatInvalid) + if (m_options.m_format == eFormatInvalid) { result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); @@ -265,7 +265,7 @@ public: const char* typeA = command.GetArgumentAtIndex(0); ConstString typeCS(typeA); - if(!typeCS) + if (!typeCS) { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); @@ -418,34 +418,8 @@ CommandObjectTypeFormatList_LoopCallback ( // CommandObjectTypeSummaryAdd //------------------------------------------------------------------------- -class ScriptAddOptions -{ - -public: - - bool m_skip_pointers; - bool m_skip_references; - bool m_cascade; - bool m_callback_is_synchronous; - StringList m_target_types; - StringList m_user_source; - - ScriptAddOptions(bool p, - bool r, - bool c) : - m_skip_pointers(p), - m_skip_references(r), - m_cascade(c), - m_target_types(), - m_user_source() - { - } - - typedef lldb::SharedPtr<ScriptAddOptions>::Type SharedPointer; - -}; - -static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end."; +static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" + "def function (valobj,dict):"; class TypeScriptAddInputReader : public InputReaderEZ { @@ -560,473 +534,542 @@ public: script_format.reset(new ScriptSummaryFormat(options->m_cascade, options->m_skip_pointers, options->m_skip_references, - true, - true, - false, + options->m_no_children, + options->m_no_value, + options->m_one_liner, + options->m_is_system, std::string(funct_name), options->m_user_source.CopyList(" "))); + Error error; + for (int i = 0; i < options->m_target_types.GetSize(); i++) { const char *type_name = options->m_target_types.GetStringAtIndex(i); - Debugger::SummaryFormats::Add(ConstString(type_name), script_format); + CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), + script_format, + (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary), + options->m_is_system, + &error); + if (error.Fail()) + { + out_stream->Printf (error.AsCString()); + out_stream->Flush(); + return; + } + } + + if (options->m_name) + { + if ( (bool)(*(options->m_name)) ) + { + CommandObjectTypeSummaryAdd::AddSummary(*(options->m_name), + script_format, + CommandObjectTypeSummaryAdd::eNamedSummary, + options->m_is_system, + &error); + if (error.Fail()) + { + out_stream->Printf (error.AsCString()); + out_stream->Flush(); + return; + } + } + else + { + out_stream->Printf (error.AsCString()); + out_stream->Flush(); + return; + } } } }; -class CommandObjectTypeSummaryAdd : public CommandObject +Error +CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg) { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + bool success; -private: + switch (short_option) + { + case 'C': + m_cascade = Args::StringToBoolean(option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg); + break; + case 'e': + m_no_children = false; + break; + case 'v': + m_no_value = true; + break; + case 'c': + m_one_liner = true; + break; + case 'f': + m_format_string = std::string(option_arg); + break; + case 'p': + m_skip_pointers = true; + break; + case 'r': + m_skip_references = true; + break; + case 'x': + m_regex = true; + break; + case 'n': + m_name = new ConstString(option_arg); + break; + case 's': + m_python_script = std::string(option_arg); + m_is_add_script = true; + break; + case 'F': + m_python_function = std::string(option_arg); + m_is_add_script = true; + break; + case 'P': + m_is_add_script = true; + break; + case 'w': + m_is_system = true; + break; + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } - class CommandOptions : public Options + return error; +} + +void +CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting () +{ + m_cascade = true; + m_no_children = true; + m_no_value = false; + m_one_liner = false; + m_skip_references = false; + m_skip_pointers = false; + m_regex = false; + m_name = NULL; + m_python_script = ""; + m_python_function = ""; + m_is_add_script = false; + m_is_system = false; +} + +void +CommandObjectTypeSummaryAdd::CollectPythonScript (ScriptAddOptions *options, + CommandReturnObject &result) +{ + InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger())); + if (reader_sp && options) { - public: - CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) - { - } - - virtual - ~CommandOptions (){} + InputReaderEZ::InitializationParameters ipr; - virtual Error - SetOptionValue (uint32_t option_idx, const char *option_arg) + Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" "))); + if (err.Success()) { - Error error; - char short_option = (char) m_getopt_table[option_idx].val; - bool success; - - switch (short_option) - { - case 'C': - m_cascade = Args::StringToBoolean(option_arg, true, &success); - if (!success) - error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg); - break; - case 'e': - m_no_children = false; - break; - case 'v': - m_no_value = true; - break; - case 'c': - m_one_liner = true; - break; - case 'f': - m_format_string = std::string(option_arg); - break; - case 'p': - m_skip_pointers = true; - break; - case 'r': - m_skip_references = true; - break; - case 'x': - m_regex = true; - break; - case 'n': - m_name = new ConstString(option_arg); - break; - case 's': - m_python_script = std::string(option_arg); - m_is_add_script = true; - break; - case 'F': - m_python_function = std::string(option_arg); - m_is_add_script = true; - break; - case 'P': - m_is_add_script = true; - break; - default: - error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); - break; - } - - return error; + m_interpreter.GetDebugger().PushInputReader (reader_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); } - - void - OptionParsingStarting () - { - m_cascade = true; - m_no_children = true; - m_no_value = false; - m_one_liner = false; - m_skip_references = false; - m_skip_pointers = false; - m_regex = false; - m_name = NULL; - m_python_script = ""; - m_python_function = ""; - m_is_add_script = false; - } - - const OptionDefinition* - GetDefinitions () + else { - return g_option_table; + result.AppendError (err.AsCString()); + result.SetStatus (eReturnStatusFailed); } - - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - bool m_cascade; - bool m_no_children; - bool m_no_value; - bool m_one_liner; - bool m_skip_references; - bool m_skip_pointers; - bool m_regex; - std::string m_format_string; - ConstString* m_name; - std::string m_python_script; - std::string m_python_function; - bool m_is_add_script; - }; - - CommandOptions m_options; - - virtual Options * - GetOptions () - { - return &m_options; } - -public: - CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter) : - CommandObject (interpreter, - "type summary add", - "Add a new summary style for a type.", - NULL), m_options (interpreter) + else { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back (type_style_arg); - - m_arguments.push_back (type_arg); - - SetHelpLong( - "Some examples of using this command.\n" - "We use as reference the following snippet of code:\n" - "struct JustADemo\n" - "{\n" - "int* ptr;\n" - "float value;\n" - "JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n" - "};\n" - "JustADemo object(42,3.14);\n" - "struct AnotherDemo : public JustADemo\n" - "{\n" - "uint8_t byte;\n" - "AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n" - "};\n" - "AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n" - "\n" - "type summary add -f \"the answer is ${*var.ptr}\" JustADemo\n" - "when typing frame variable object you will get \"the answer is 42\"\n" - "type summary add -f \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n" - "when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n" - "\n" - "Alternatively, you could also say\n" - "type summary add -f \"${var%V} -> ${*var}\" \"int *\"\n" - "and replace the above summary string with\n" - "type summary add -f \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n" - "to obtain a similar result\n" - "\n" - "To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n" - "type summary add -f \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n" - "\n" - "This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n" - "If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n" - "type summary add -f \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n" - "A similar option -r exists for references.\n" - "\n" - "If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n" - "you can use the -c option, without giving any summary string:\n" - "type summary add -c JustADemo\n" - "frame variable object\n" - "the output being similar to (ptr=0xsomeaddress, value=3.14)\n" - "\n" - "If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n" - "type summary add -e -f \"*ptr = ${*var.ptr}\" JustADemo\n" - "Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n" - "to get an output like:\n" - "\n" - "*ptr = 42 {\n" - " ptr = 0xsomeaddress\n" - " value = 3.14\n" - "}\n" - "\n" - "A command you may definitely want to try if you're doing C++ debugging is:\n" - "type summary add -f \"${var._M_dataplus._M_p}\" std::string\n" - ); + result.AppendError("out of memory"); + result.SetStatus (eReturnStatusFailed); } - ~CommandObjectTypeSummaryAdd () +} + +bool +CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturnObject &result) +{ + const size_t argc = command.GetArgumentCount(); + + if (argc < 1 && !m_options.m_name) { + result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; } - void - CollectPythonScript - ( - ScriptAddOptions *options, - CommandReturnObject &result - ) + SummaryFormatSP script_format; + + if (!m_options.m_python_function.empty()) // we have a Python function ready to use { - InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger())); - if (reader_sp && options) + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (!interpreter) { - - Error err (reader_sp->Initialize (options)); - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } + result.AppendError ("Internal error #1N: no script attached.\n"); + result.SetStatus (eReturnStatusFailed); + return false; } - else + const char *funct_name = m_options.m_python_function.c_str(); + if (!funct_name || !funct_name[0]) { - result.AppendError("out of memory"); + result.AppendError ("Internal error #2N: no script attached.\n"); result.SetStatus (eReturnStatusFailed); + return false; } + script_format.reset(new ScriptSummaryFormat(m_options.m_cascade, + m_options.m_skip_pointers, + m_options.m_skip_references, + m_options.m_no_children, + m_options.m_no_value, + m_options.m_one_liner, + m_options.m_is_system, + std::string(funct_name), + " " + m_options.m_python_function + "(valobj,dict)")); } - - bool - Execute (Args& command, CommandReturnObject &result) - { - if (m_options.m_is_add_script) - return Execute_ScriptSummary(command, result); - else - return Execute_StringSummary(command, result); - } - - bool - Execute_ScriptSummary (Args& command, CommandReturnObject &result) + else if (!m_options.m_python_script.empty()) // we have a quick 1-line script, just use it { - const size_t argc = command.GetArgumentCount(); - - if (argc < 1) + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (!interpreter) { - result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); + result.AppendError ("Internal error #1Q: no script attached.\n"); + result.SetStatus (eReturnStatusFailed); return false; } - - if (!m_options.m_python_function.empty()) // we have a Python function ready to use + StringList funct_sl; + funct_sl << m_options.m_python_script.c_str(); + StringList funct_name_sl; + if (!interpreter->GenerateTypeScriptFunction (funct_sl, + funct_name_sl)) { - ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); - if (!interpreter) - { - result.AppendError ("Internal error #1N: no script attached.\n"); - result.SetStatus (eReturnStatusFailed); - return false; - } - const char *funct_name = m_options.m_python_function.c_str(); - if (!funct_name || !funct_name[0]) - { - result.AppendError ("Internal error #2N: no script attached.\n"); - result.SetStatus (eReturnStatusFailed); - return false; - } - // now I have a valid function name, let's add this as script for every type in the list - - SummaryFormatSP script_format; - script_format.reset(new ScriptSummaryFormat(m_options.m_cascade, - m_options.m_skip_pointers, - m_options.m_skip_references, - true, - true, - false, - std::string(funct_name), - " " + m_options.m_python_function + "(valobj,dict)")); - - for (int i = 0; i < command.GetArgumentCount(); i++) - { - const char *type_name = command.GetArgumentAtIndex(i); - Debugger::SummaryFormats::Add(ConstString(type_name), script_format); - } + result.AppendError ("Internal error #2Q: no script attached.\n"); + result.SetStatus (eReturnStatusFailed); + return false; } - else if (m_options.m_python_script.empty()) // use an InputReader to grab Python code from the user - { - ScriptAddOptions *options = new ScriptAddOptions(m_options.m_skip_pointers, - m_options.m_skip_references, - m_options.m_cascade); - - for(int 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(); + if (funct_name_sl.GetSize() == 0) + { + result.AppendError ("Internal error #3Q: no script attached.\n"); + result.SetStatus (eReturnStatusFailed); + return false; } - else // we have a quick 1-line script, just use it + const char *funct_name = funct_name_sl.GetStringAtIndex(0); + if (!funct_name || !funct_name[0]) { - ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); - if (!interpreter) - { - result.AppendError ("Internal error #1Q: no script attached.\n"); - result.SetStatus (eReturnStatusFailed); - return false; - } - StringList funct_sl; - funct_sl << m_options.m_python_script.c_str(); - StringList funct_name_sl; - if (!interpreter->GenerateTypeScriptFunction (funct_sl, - funct_name_sl)) - { - result.AppendError ("Internal error #2Q: no script attached.\n"); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (funct_name_sl.GetSize() == 0) - { - result.AppendError ("Internal error #3Q: no script attached.\n"); - result.SetStatus (eReturnStatusFailed); - return false; - } - const char *funct_name = funct_name_sl.GetStringAtIndex(0); - if (!funct_name || !funct_name[0]) + result.AppendError ("Internal error #4Q: no script attached.\n"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + script_format.reset(new ScriptSummaryFormat(m_options.m_cascade, + m_options.m_skip_pointers, + m_options.m_skip_references, + m_options.m_no_children, + m_options.m_no_value, + m_options.m_one_liner, + m_options.m_is_system, + std::string(funct_name), + " " + m_options.m_python_script)); + } + else // use an InputReader to grab Python code from the user + { + ScriptAddOptions *options = new ScriptAddOptions(m_options.m_skip_pointers, + m_options.m_skip_references, + m_options.m_cascade, + m_options.m_no_children, + m_options.m_no_value, + m_options.m_one_liner, + m_options.m_regex, + m_options.m_is_system, + m_options.m_name); + + for(int i = 0; i < argc; i++) { + const char* typeA = command.GetArgumentAtIndex(i); + if (typeA && *typeA) + options->m_target_types << typeA; + else { - result.AppendError ("Internal error #4Q: no script attached.\n"); - result.SetStatus (eReturnStatusFailed); + result.AppendError("empty typenames not allowed"); + result.SetStatus(eReturnStatusFailed); return false; } - // now I have a valid function name, let's add this as script for every type in the list - - ScriptFormatSP script_format; - script_format.reset(new ScriptSummaryFormat(m_options.m_cascade, - m_options.m_skip_pointers, - m_options.m_skip_references, - true, - true, - false, - std::string(funct_name), - " " + m_options.m_python_script)); - - for (int i = 0; i < command.GetArgumentCount(); i++) - { - const char *type_name = command.GetArgumentAtIndex(i); - Debugger::SummaryFormats::Add(ConstString(type_name), script_format); - } } + CollectPythonScript(options,result); return result.Succeeded(); } - - bool - Execute_StringSummary (Args& command, CommandReturnObject &result) + + // if I am here, script_format must point to something good, so I can add that + // as a script summary to all interested parties + + Error error; + + for (int i = 0; i < command.GetArgumentCount(); i++) { - const size_t argc = command.GetArgumentCount(); - - if (argc < 1 && !m_options.m_name) + const char *type_name = command.GetArgumentAtIndex(i); + CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), + script_format, + (m_options.m_regex ? eRegexSummary : eRegularSummary), + m_options.m_is_system, + &error); + if (error.Fail()) { - result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); + result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } - - if(!m_options.m_one_liner && m_options.m_format_string.empty()) + } + + if (m_options.m_name) + { + if ( (bool)(*(m_options.m_name)) ) { - result.AppendError("empty summary strings not allowed"); + AddSummary(*(m_options.m_name), script_format, eNamedSummary, m_options.m_is_system, &error); + if (error.Fail()) + { + result.AppendError(error.AsCString()); + result.AppendError("added to types, but not given a name"); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + else + { + result.AppendError("added to types, but not given a name"); result.SetStatus(eReturnStatusFailed); return false; } - - const char* format_cstr = (m_options.m_one_liner ? "" : m_options.m_format_string.c_str()); - - Error error; - - SummaryFormat::SharedPointer entry(new StringSummaryFormat(m_options.m_cascade, - m_options.m_skip_pointers, - m_options.m_skip_references, - m_options.m_no_children, - m_options.m_no_value, - m_options.m_one_liner, - format_cstr)); - - if (error.Fail()) + } + + return result.Succeeded(); +} + +bool +CommandObjectTypeSummaryAdd::Execute_StringSummary (Args& command, CommandReturnObject &result) +{ + const size_t argc = command.GetArgumentCount(); + + if (argc < 1 && !m_options.m_name) + { + result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (!m_options.m_one_liner && m_options.m_format_string.empty()) + { + result.AppendError("empty summary strings not allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const char* format_cstr = (m_options.m_one_liner ? "" : m_options.m_format_string.c_str()); + + Error error; + + SummaryFormat::SharedPointer entry(new StringSummaryFormat(m_options.m_cascade, + m_options.m_skip_pointers, + m_options.m_skip_references, + m_options.m_no_children, + m_options.m_no_value, + m_options.m_one_liner, + m_options.m_is_system, + format_cstr)); + + if (error.Fail()) + { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // now I have a valid format, let's add it to every type + + for(int i = 0; i < argc; i++) { + const char* typeA = command.GetArgumentAtIndex(i); + if (!typeA || typeA[0] == '\0') { - result.AppendError(error.AsCString()); + result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } + ConstString typeCS(typeA); - // now I have a valid format, let's add it to every type + AddSummary(typeCS, + entry, + (m_options.m_regex ? eRegexSummary : eRegularSummary), + m_options.m_is_system, + &error); - for(int i = 0; i < argc; i++) { - const char* typeA = command.GetArgumentAtIndex(i); - if (!typeA || typeA[0] == '\0') - { - result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); - return false; - } - ConstString typeCS(typeA); - if (!m_options.m_regex) - { - Debugger::SummaryFormats::Add(typeCS, entry); - } - else - { - RegularExpressionSP typeRX(new RegularExpression()); - if(!typeRX->Compile(typeA)) - { - result.AppendError("regex format error (maybe this is not really a regex?)"); - result.SetStatus(eReturnStatusFailed); - return false; - } - Debugger::RegexSummaryFormats::Delete(typeCS); - Debugger::RegexSummaryFormats::Add(typeRX, entry); - } + if (error.Fail()) + { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; } - - if (m_options.m_name) + } + + if (m_options.m_name) + { + if ( (bool)(*(m_options.m_name)) ) { - if( (bool)(*(m_options.m_name)) ) - { - Debugger::NamedSummaryFormats::Add(*(m_options.m_name), entry); - } - else + AddSummary(*(m_options.m_name), entry, eNamedSummary, m_options.m_is_system, &error); + if (error.Fail()) { + result.AppendError(error.AsCString()); result.AppendError("added to types, but not given a name"); result.SetStatus(eReturnStatusFailed); return false; } } - - result.SetStatus(eReturnStatusSuccessFinishNoResult); - return result.Succeeded(); + else + { + result.AppendError("added to types, but not given a name"); + result.SetStatus(eReturnStatusFailed); + return false; + } } -}; + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); +} + +CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter) : +CommandObject (interpreter, + "type summary add", + "Add a new summary style for a type.", + NULL), m_options (interpreter) +{ + CommandArgumentEntry type_arg; + CommandArgumentData type_style_arg; + + type_style_arg.arg_type = eArgTypeName; + type_style_arg.arg_repetition = eArgRepeatPlus; + + type_arg.push_back (type_style_arg); + + m_arguments.push_back (type_arg); + + SetHelpLong( + "Some examples of using this command.\n" + "We use as reference the following snippet of code:\n" + "struct JustADemo\n" + "{\n" + "int* ptr;\n" + "float value;\n" + "JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n" + "};\n" + "JustADemo object(42,3.14);\n" + "struct AnotherDemo : public JustADemo\n" + "{\n" + "uint8_t byte;\n" + "AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n" + "};\n" + "AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n" + "\n" + "type summary add -f \"the answer is ${*var.ptr}\" JustADemo\n" + "when typing frame variable object you will get \"the answer is 42\"\n" + "type summary add -f \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n" + "when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n" + "\n" + "Alternatively, you could also say\n" + "type summary add -f \"${var%V} -> ${*var}\" \"int *\"\n" + "and replace the above summary string with\n" + "type summary add -f \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n" + "to obtain a similar result\n" + "\n" + "To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n" + "type summary add -f \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n" + "\n" + "This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n" + "If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n" + "type summary add -f \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n" + "A similar option -r exists for references.\n" + "\n" + "If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n" + "you can use the -c option, without giving any summary string:\n" + "type summary add -c JustADemo\n" + "frame variable object\n" + "the output being similar to (ptr=0xsomeaddress, value=3.14)\n" + "\n" + "If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n" + "type summary add -e -f \"*ptr = ${*var.ptr}\" JustADemo\n" + "Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n" + "to get an output like:\n" + "\n" + "*ptr = 42 {\n" + " ptr = 0xsomeaddress\n" + " value = 3.14\n" + "}\n" + "\n" + "A command you may definitely want to try if you're doing C++ debugging is:\n" + "type summary add -f \"${var._M_dataplus._M_p}\" std::string\n" + ); +} + +bool +CommandObjectTypeSummaryAdd::Execute (Args& command, CommandReturnObject &result) +{ + if (m_options.m_is_add_script) + return Execute_ScriptSummary(command, result); + else + return Execute_StringSummary(command, result); +} + +bool +CommandObjectTypeSummaryAdd::AddSummary(const ConstString& type_name, + SummaryFormatSP entry, + SummaryFormatType type, + bool is_system, + Error* error) +{ + if (type == eRegexSummary) + { + RegularExpressionSP typeRX(new RegularExpression()); + if (!typeRX->Compile(type_name.GetCString())) + { + if (error) + error->SetErrorString("regex format error (maybe this is not really a regex?)"); + return false; + } + + if (!is_system) + { + Debugger::RegexSummaryFormats::Delete(type_name); + Debugger::RegexSummaryFormats::Add(typeRX, entry); + } + else + { + Debugger::SystemRegexSummaryFormats::Delete(type_name); + Debugger::SystemRegexSummaryFormats::Add(typeRX, entry); + } + return true; + } + else if (type == eNamedSummary) + { + // system named summaries do not exist (yet?) + Debugger::NamedSummaryFormats::Add(type_name,entry); + return true; + } + else + { + if (!is_system) + Debugger::SummaryFormats::Add(type_name,entry); + else + Debugger::SystemSummaryFormats::Add(type_name,entry); + return true; + } +} OptionDefinition CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] = { + { LLDB_OPT_SET_ALL, false, "system", 'w', no_argument, NULL, 0, eArgTypeBoolean, "This is a system summary (makes it harder to delete it by accident)."}, { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."}, { LLDB_OPT_SET_ALL, false, "no-value", 'v', no_argument, NULL, 0, eArgTypeBoolean, "Don't show the value, just show the summary, for this type."}, { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for pointers-to-type objects."}, @@ -1034,11 +1077,11 @@ CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeBoolean, "Type names are actually regular expressions."}, { LLDB_OPT_SET_1 , true, "inline-children", 'c', no_argument, NULL, 0, eArgTypeBoolean, "If true, inline all child values into summary string."}, { LLDB_OPT_SET_2 , true, "format-string", 'f', required_argument, NULL, 0, eArgTypeSummaryString, "Format string used to display text and object contents."}, - { LLDB_OPT_SET_2, false, "expand", 'e', no_argument, NULL, 0, eArgTypeBoolean, "Expand aggregate data types to show children on separate lines."}, - { LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeName, "A name for this summary string."}, { LLDB_OPT_SET_3, false, "python-script", 's', required_argument, NULL, 0, eArgTypeName, "Give a one-liner Python script as part of the command."}, { LLDB_OPT_SET_3, false, "python-function", 'F', required_argument, NULL, 0, eArgTypeName, "Give the name of a Python function to use for this type."}, { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeName, "Input Python code to use for this type manually."}, + { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', no_argument, NULL, 0, eArgTypeBoolean, "Expand aggregate data types to show children on separate lines."}, + { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, 0, eArgTypeName, "A name for this summary string."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; @@ -1049,12 +1092,73 @@ CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] = class CommandObjectTypeSummaryDelete : public CommandObject { +private: + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter) + { + } + + virtual + ~CommandOptions (){} + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'a': + m_delete_system = true; + break; + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; + } + + void + OptionParsingStarting () + { + m_delete_system = false; + } + + const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + bool m_delete_system; + }; + + CommandOptions m_options; + + virtual Options * + GetOptions () + { + return &m_options; + } + public: CommandObjectTypeSummaryDelete (CommandInterpreter &interpreter) : CommandObject (interpreter, "type summary delete", "Delete an existing summary style for a type.", - NULL) + NULL), m_options(interpreter) { CommandArgumentEntry type_arg; CommandArgumentData type_style_arg; @@ -1087,7 +1191,7 @@ public: const char* typeA = command.GetArgumentAtIndex(0); ConstString typeCS(typeA); - if(!typeCS) + if (!typeCS) { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); @@ -1097,8 +1201,10 @@ public: bool delete_summary = Debugger::SummaryFormats::Delete(typeCS); bool delete_regex = Debugger::RegexSummaryFormats::Delete(typeCS); bool delete_named = Debugger::NamedSummaryFormats::Delete(typeCS); + bool delete_sys = m_options.m_delete_system ? Debugger::SystemSummaryFormats::Delete(typeCS) : false; + bool delete_sys_regex = m_options.m_delete_system ? Debugger::SystemRegexSummaryFormats::Delete(typeCS) : false; - if (delete_summary || delete_regex || delete_named) + if (delete_summary || delete_regex || delete_named || delete_sys || delete_sys_regex) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); @@ -1111,7 +1217,13 @@ public: } } - +}; + +OptionDefinition +CommandObjectTypeSummaryDelete::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Also delete system summaries (not recommended)."}, + { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- @@ -1120,12 +1232,74 @@ public: class CommandObjectTypeSummaryClear : public CommandObject { +private: + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter) + { + } + + virtual + ~CommandOptions (){} + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'a': + m_delete_system = true; + break; + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; + } + + void + OptionParsingStarting () + { + m_delete_system = false; + } + + const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + bool m_delete_system; + }; + + CommandOptions m_options; + + virtual Options * + GetOptions () + { + return &m_options; + } + public: CommandObjectTypeSummaryClear (CommandInterpreter &interpreter) : CommandObject (interpreter, "type summary clear", "Delete all existing summary styles.", - NULL) + NULL), m_options(interpreter) { } @@ -1139,12 +1313,26 @@ public: Debugger::SummaryFormats::Clear(); Debugger::RegexSummaryFormats::Clear(); Debugger::NamedSummaryFormats::Clear(); + + if (m_options.m_delete_system) + { + Debugger::SystemSummaryFormats::Clear(); + Debugger::SystemRegexSummaryFormats::Clear(); + } + result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; +OptionDefinition +CommandObjectTypeSummaryClear::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Also clear system summaries (not recommended)."}, + { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } +}; + //------------------------------------------------------------------------- // CommandObjectTypeSummaryList //------------------------------------------------------------------------- @@ -1210,9 +1398,10 @@ public: else param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result); Debugger::SummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); + Debugger::SystemSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); delete param; - if(Debugger::RegexSummaryFormats::GetCount() > 0) + if (Debugger::RegexSummaryFormats::GetCount() > 0 || Debugger::SystemRegexSummaryFormats::GetCount() > 0 ) { result.GetOutputStream().Printf("Regex-based summaries (slower):\n"); if (argc == 1) { @@ -1223,10 +1412,11 @@ public: else rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result); Debugger::RegexSummaryFormats::LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, rxparam); + Debugger::SystemRegexSummaryFormats::LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, rxparam); delete rxparam; } - if(Debugger::NamedSummaryFormats::GetCount() > 0) + if (Debugger::NamedSummaryFormats::GetCount() > 0) { result.GetOutputStream().Printf("Named summaries:\n"); if (argc == 1) { @@ -1259,7 +1449,6 @@ private: friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry); friend bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry); - }; bool @@ -1282,7 +1471,6 @@ CommandObjectTypeRXSummaryList_LoopCallback ( return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result); } - class CommandObjectTypeFormat : public CommandObjectMultiword { public: diff --git a/lldb/source/Commands/CommandObjectType.h b/lldb/source/Commands/CommandObjectType.h index 994d1fca049..0c453785e41 100644 --- a/lldb/source/Commands/CommandObjectType.h +++ b/lldb/source/Commands/CommandObjectType.h @@ -19,13 +19,57 @@ #include "lldb/lldb-types.h" #include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/Options.h" namespace lldb_private { -//------------------------------------------------------------------------- -// CommandObjectMultiwordBreakpoint -//------------------------------------------------------------------------- - +class ScriptAddOptions +{ + +public: + + bool m_skip_pointers; + bool m_skip_references; + bool m_cascade; + StringList m_target_types; + StringList m_user_source; + + bool m_no_children; + bool m_no_value; + bool m_one_liner; + bool m_regex; + + bool m_is_system; + + ConstString* m_name; + + ScriptAddOptions(bool sptr, + bool sref, + bool casc, + bool noch, + bool novl, + bool onel, + bool regx, + bool syst, + ConstString* name) : + m_skip_pointers(sptr), + m_skip_references(sref), + m_cascade(casc), + m_target_types(), + m_user_source(), + m_no_children(noch), + m_no_value(novl), + m_one_liner(onel), + m_regex(regx), + m_is_system(syst), + m_name(name) + { + } + + typedef lldb::SharedPtr<ScriptAddOptions>::Type SharedPointer; + +}; + class CommandObjectType : public CommandObjectMultiword { public: @@ -35,6 +79,99 @@ public: ~CommandObjectType (); }; +class CommandObjectTypeSummaryAdd : public CommandObject +{ + +private: + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter) + { + } + + virtual + ~CommandOptions (){} + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg); + + void + OptionParsingStarting (); + + const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + bool m_cascade; + bool m_no_children; + bool m_no_value; + bool m_one_liner; + bool m_skip_references; + bool m_skip_pointers; + bool m_regex; + std::string m_format_string; + ConstString* m_name; + std::string m_python_script; + std::string m_python_function; + bool m_is_add_script; + bool m_is_system; + }; + + CommandOptions m_options; + + virtual Options * + GetOptions () + { + return &m_options; + } + + void + CollectPythonScript(ScriptAddOptions *options, + CommandReturnObject &result); + + bool + Execute_ScriptSummary (Args& command, CommandReturnObject &result); + + bool + Execute_StringSummary (Args& command, CommandReturnObject &result); + +public: + + enum SummaryFormatType + { + eRegularSummary, + eRegexSummary, + eNamedSummary, + }; + + CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter); + + ~CommandObjectTypeSummaryAdd () + { + } + + bool + Execute (Args& command, CommandReturnObject &result); + + static bool + AddSummary(const ConstString& type_name, + lldb::SummaryFormatSP entry, + SummaryFormatType type, + bool is_system, + Error* error = NULL); +}; } // namespace lldb_private diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 029a1d85b53..cde5da77d05 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1798,6 +1798,48 @@ Debugger::SummaryFormats::GetCount() } bool +Debugger::SystemSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) +{ + return GetFormatManager().SystemSummary().Get(vobj,entry); +} + +void +Debugger::SystemSummaryFormats::Add(const ConstString &type, const SummaryFormat::SharedPointer &entry) +{ + GetFormatManager().SystemSummary().Add(type.AsCString(),entry); +} + +bool +Debugger::SystemSummaryFormats::Delete(const ConstString &type) +{ + return GetFormatManager().SystemSummary().Delete(type.AsCString()); +} + +void +Debugger::SystemSummaryFormats::Clear() +{ + GetFormatManager().SystemSummary().Clear(); +} + +void +Debugger::SystemSummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton) +{ + GetFormatManager().SystemSummary().LoopThrough(callback, callback_baton); +} + +uint32_t +Debugger::SystemSummaryFormats::GetCurrentRevision() +{ + return GetFormatManager().GetCurrentRevision(); +} + +uint32_t +Debugger::SystemSummaryFormats::GetCount() +{ + return GetFormatManager().SystemSummary().GetCount(); +} + +bool Debugger::RegexSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) { return GetFormatManager().RegexSummary().Get(vobj,entry); @@ -1840,6 +1882,48 @@ Debugger::RegexSummaryFormats::GetCount() } bool +Debugger::SystemRegexSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) +{ + return GetFormatManager().SystemRegexSummary().Get(vobj,entry); +} + +void +Debugger::SystemRegexSummaryFormats::Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry) +{ + GetFormatManager().SystemRegexSummary().Add(type,entry); +} + +bool +Debugger::SystemRegexSummaryFormats::Delete(const ConstString &type) +{ + return GetFormatManager().SystemRegexSummary().Delete(type.AsCString()); +} + +void +Debugger::SystemRegexSummaryFormats::Clear() +{ + GetFormatManager().SystemRegexSummary().Clear(); +} + +void +Debugger::SystemRegexSummaryFormats::LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton) +{ + GetFormatManager().SystemRegexSummary().LoopThrough(callback, callback_baton); +} + +uint32_t +Debugger::SystemRegexSummaryFormats::GetCurrentRevision() +{ + return GetFormatManager().GetCurrentRevision(); +} + +uint32_t +Debugger::SystemRegexSummaryFormats::GetCount() +{ + return GetFormatManager().SystemRegexSummary().GetCount(); +} + +bool Debugger::NamedSummaryFormats::Get(const ConstString &type, SummaryFormat::SharedPointer &entry) { return GetFormatManager().NamedSummary().Get(type.AsCString(),entry); diff --git a/lldb/source/Core/InputReaderEZ.cpp b/lldb/source/Core/InputReaderEZ.cpp index 839d744a5ac..295bfb82b31 100644 --- a/lldb/source/Core/InputReaderEZ.cpp +++ b/lldb/source/Core/InputReaderEZ.cpp @@ -75,6 +75,16 @@ InputReaderEZ::Initialize(void* baton, echo); } +Error +InputReaderEZ::Initialize(InitializationParameters& params) +{ + return Initialize(params.m_baton, + params.m_token_size, + params.m_end_token, + params.m_prompt, + params.m_echo); +} + InputReaderEZ::~InputReaderEZ () { }
\ No newline at end of file diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index ca0b0aca0c6..5264db2c4cb 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -209,8 +209,14 @@ ValueObject::UpdateFormatsIfNeeded() if (m_last_value_format.get()) m_last_value_format.reset((ValueFormat*)NULL); Debugger::ValueFormats::Get(*this, m_last_value_format); + // to find a summary we look for a direct summary, then if there is none + // we look for a regex summary. if there is none we look for a system + // summary (direct), and if also that fails, we look for a system + // regex summary if (!Debugger::SummaryFormats::Get(*this, m_last_summary_format)) - Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format); + if (!Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format)) + if (!Debugger::SystemSummaryFormats::Get(*this, m_last_summary_format)) + Debugger::SystemRegexSummaryFormats::Get(*this, m_last_summary_format); m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision(); ClearUserVisibleData(); @@ -518,7 +524,7 @@ ValueObject::GetSummaryAsCString () { clang_type_t clang_type = GetClangType(); - // See if this is a pointer to a C string? + // Do some default printout for function pointers if (clang_type) { StreamString sstr; @@ -530,116 +536,7 @@ ValueObject::GetSummaryAsCString () ExecutionContextScope *exe_scope = GetExecutionContextScope(); if (exe_scope) { - if (type_flags.AnySet (ClangASTContext::eTypeIsArray | ClangASTContext::eTypeIsPointer) && - ClangASTContext::IsCharType (elem_or_pointee_clang_type)) - { - Target *target = exe_scope->CalculateTarget(); - if (target != NULL) - { - lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS; - AddressType cstr_address_type = eAddressTypeInvalid; - - size_t cstr_len = 0; - bool capped_data = false; - if (type_flags.Test (ClangASTContext::eTypeIsArray)) - { - // We have an array - cstr_len = ClangASTContext::GetArraySize (clang_type); - if (cstr_len > 512) // TODO: make cap a setting - { - cstr_len = ClangASTContext::GetArraySize (clang_type); - if (cstr_len > 512) // TODO: make cap a setting - { - capped_data = true; - cstr_len = 512; - } - } - cstr_address = GetAddressOf (cstr_address_type, true); - } - else - { - // We have a pointer - cstr_address = GetPointerValue (cstr_address_type, true); - } - if (cstr_address != LLDB_INVALID_ADDRESS) - { - Address cstr_so_addr (NULL, cstr_address); - DataExtractor data; - size_t bytes_read = 0; - std::vector<char> data_buffer; - Error error; - bool prefer_file_cache = false; - if (cstr_len > 0) - { - data_buffer.resize(cstr_len); - data.SetData (&data_buffer.front(), data_buffer.size(), lldb::endian::InlHostByteOrder()); - bytes_read = target->ReadMemory (cstr_so_addr, - prefer_file_cache, - &data_buffer.front(), - cstr_len, - error); - if (bytes_read > 0) - { - sstr << '"'; - data.Dump (&sstr, - 0, // Start offset in "data" - eFormatCharArray, // Print as characters - 1, // Size of item (1 byte for a char!) - bytes_read, // How many bytes to print? - UINT32_MAX, // num per line - LLDB_INVALID_ADDRESS,// base address - 0, // bitfield bit size - 0); // bitfield bit offset - if (capped_data) - sstr << "..."; - sstr << '"'; - } - } - else - { - const size_t k_max_buf_size = 256; - data_buffer.resize (k_max_buf_size + 1); - // NULL terminate in case we don't get the entire C string - data_buffer.back() = '\0'; - - sstr << '"'; - - data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder()); - while ((bytes_read = target->ReadMemory (cstr_so_addr, - prefer_file_cache, - &data_buffer.front(), - k_max_buf_size, - error)) > 0) - { - size_t len = strlen(&data_buffer.front()); - if (len == 0) - break; - if (len > bytes_read) - len = bytes_read; - - data.Dump (&sstr, - 0, // Start offset in "data" - eFormatCharArray, // Print as characters - 1, // Size of item (1 byte for a char!) - len, // How many bytes to print? - UINT32_MAX, // num per line - LLDB_INVALID_ADDRESS,// base address - 0, // bitfield bit size - 0); // bitfield bit offset - - if (len < k_max_buf_size) - break; - cstr_so_addr.Slide (k_max_buf_size); - } - sstr << '"'; - } - } - } - - if (sstr.GetSize() > 0) - m_summary_str.assign (sstr.GetData(), sstr.GetSize()); - } - else if (ClangASTContext::IsFunctionPointerType (clang_type)) + if (ClangASTContext::IsFunctionPointerType (clang_type)) { AddressType func_ptr_address_type = eAddressTypeInvalid; lldb::addr_t func_ptr_address = GetPointerValue (func_ptr_address_type, true); @@ -988,7 +885,7 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d RefCounter ref(&m_dump_printable_counter); - if(custom_format != lldb::eFormatInvalid) + if (custom_format != lldb::eFormatInvalid) SetFormat(custom_format); const char * return_value; @@ -1146,10 +1043,10 @@ ValueObject::DumpPrintableRepresentation(Stream& s, return false; } const char *targetvalue = GetPrintableRepresentation(val_obj_display, custom_format); - if(targetvalue) + if (targetvalue) s.PutCString(targetvalue); bool var_success = (targetvalue != NULL); - if(custom_format != eFormatInvalid) + if (custom_format != eFormatInvalid) SetFormat(eFormatDefault); return var_success; } @@ -1624,7 +1521,7 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp { const bool is_deref_of_parent = IsDereferenceOfParent (); - if(is_deref_of_parent && epformat == eDereferencePointers) { + if (is_deref_of_parent && epformat == eDereferencePointers) { // this is the original format of GetExpressionPath() producing code like *(a_ptr).memberName, which is entirely // fine, until you put this into StackFrame::GetValueForVariableExpressionPath() which prefers to see a_ptr->memberName. // the eHonorPointers mode is meant to produce strings in this latter format @@ -1639,7 +1536,7 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp // if we are a deref_of_parent just because we are synthetic array // members made up to allow ptr[%d] syntax to work in variable // printing, then add our name ([%d]) to the expression path - if(m_is_array_item_for_pointer && epformat == eHonorPointers) + if (m_is_array_item_for_pointer && epformat == eHonorPointers) s.PutCString(m_name.AsCString()); if (!IsBaseClass()) @@ -1654,7 +1551,7 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp { const uint32_t non_base_class_parent_type_info = ClangASTContext::GetTypeInfo (non_base_class_parent_clang_type, NULL, NULL); - if(parent && parent->IsDereferenceOfParent() && epformat == eHonorPointers) + if (parent && parent->IsDereferenceOfParent() && epformat == eHonorPointers) { s.PutCString("->"); } @@ -2584,7 +2481,7 @@ ValueObject::DumpValueObject if (val_cstr && (!entry || entry->DoesPrintValue() || !sum_cstr)) s.Printf(" %s", valobj->GetValueAsCString()); - if(sum_cstr) + if (sum_cstr) { // for some reason, using %@ (ObjC description) in a summary string, makes // us believe we need to reset ourselves, thus invalidating the content of diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index 8ccde5ce1e9..f99270a5143 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -117,7 +117,7 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type) clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); // We currently can't complete objective C types through the newly added ASTContext // because it only supports TagDecl objects right now... - if(class_interface_decl) + if (class_interface_decl) { bool is_forward_decl = class_interface_decl->isForwardDecl(); if (is_forward_decl && class_interface_decl->hasExternalLexicalStorage()) diff --git a/lldb/source/Symbol/TypeHierarchyNavigator.cpp b/lldb/source/Symbol/TypeHierarchyNavigator.cpp index fdbe795be6e..6bf43385358 100644 --- a/lldb/source/Symbol/TypeHierarchyNavigator.cpp +++ b/lldb/source/Symbol/TypeHierarchyNavigator.cpp @@ -61,7 +61,7 @@ TypeHierarchyNavigator::LoopThrough(const clang::QualType& qual_type, */ Error error; ValueObject* target = m_value_object.Dereference(error).get(); - if(error.Fail() || !target) + if (error.Fail() || !target) return true; if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false) return false; @@ -73,10 +73,10 @@ TypeHierarchyNavigator::LoopThrough(const clang::QualType& qual_type, if (ClangASTContext::GetCompleteType(ast, m_value_object.GetClangType()) && !objc_class_type->isObjCId()) { clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); - if(class_interface_decl) + if (class_interface_decl) { clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); - if(superclass_interface_decl) + if (superclass_interface_decl) { clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl)); return LoopThrough(ivar_qual_type, callback, eObjCBaseClass, callback_baton); @@ -95,7 +95,7 @@ TypeHierarchyNavigator::LoopThrough(const clang::QualType& qual_type, if (record->hasDefinition()) { clang::CXXRecordDecl::base_class_iterator pos,end; - if( record->getNumBases() > 0) + if ( record->getNumBases() > 0) { end = record->bases_end(); for (pos = record->bases_begin(); pos != end; pos++) diff --git a/lldb/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py b/lldb/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py index 77a0368b7d4..2ba39705326 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py @@ -56,7 +56,7 @@ class DataFormatterTestCase(TestBase): # Set the script here to ease the formatting script = 'a = valobj.GetChildMemberWithName(\'integer\'); a_val = a.GetValue(); str = \'Hello from Python, \' + a_val + \' time\'; return str + (\'!\' if a_val == \'1\' else \'s!\');' - self.runCmd("type summary add add i_am_cool -s \"%s\"" % script) + self.runCmd("type summary add i_am_cool -s \"%s\"" % script) self.expect("frame variable one", substrs = ['Hello from Python', @@ -85,6 +85,9 @@ class DataFormatterTestCase(TestBase): self.expect("frame variable two", substrs = ['int says 1']) + + self.expect("frame variable twoptr", + substrs = ['int says 1']) # Change the summary self.runCmd("type summary add -f \"int says ${var.integer}, and float says ${var.floating}\" i_am_cool") @@ -103,6 +106,72 @@ class DataFormatterTestCase(TestBase): self.expect("frame variable twoptr", matching=False, substrs = ['and float says 2.71']) + script = 'return \'Python summary\''; + + self.runCmd("type summary add --name test_summary -s \"%s\"" % script) + + # attach the Python named summary to someone + self.runCmd("frame variable one --summary test_summary") + + self.expect("frame variable one", + substrs = ['Python summary']) + + # should not bind to the type + self.expect("frame variable two", matching=False, + substrs = ['Python summary']) + + self.runCmd("type summary add i_am_cool -f \"Text summary\"") + + self.expect("frame variable one", + substrs = ['Python summary']) + + # use the type summary + self.expect("frame variable two", + substrs = ['Text summary']) + + self.runCmd("n"); # skip ahead to make values change + + # both should use the type summary now + self.expect("frame variable one", + substrs = ['Text summary']) + + self.expect("frame variable two", + substrs = ['Text summary']) + + # disable type summary for pointers, and make a Python regex summary + self.runCmd("type summary add i_am_cool -p -f \"Text summary\"") + self.runCmd("type summary add -x cool -s \"%s\"" % script) + + # variables should stick to the type summary + self.expect("frame variable one", + substrs = ['Text summary']) + + self.expect("frame variable two", + substrs = ['Text summary']) + + # array and pointer should match the Python one + self.expect("frame variable twoptr", + substrs = ['Python summary']) + + self.expect("frame variable array", + substrs = ['Python summary']) + + # return pointers to the type summary + self.runCmd("type summary add i_am_cool -f \"Text summary\"") + + self.expect("frame variable one", + substrs = ['Text summary']) + + self.expect("frame variable two", + substrs = ['Text summary']) + + self.expect("frame variable twoptr", + substrs = ['Text summary']) + + self.expect("frame variable array", + substrs = ['Python summary']) + + if __name__ == '__main__': import atexit lldb.SBDebugger.Initialize() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-script/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-script/main.cpp index 357062234e1..aaccb6329ac 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-script/main.cpp +++ b/lldb/test/functionalities/data-formatter/data-formatter-script/main.cpp @@ -41,9 +41,13 @@ int main (int argc, const char * argv[]) i_am_cool* twoptr = &two; + i_am_cool array[5]; + i_am_cooler three(10,4,1985,1/1/2011,'B','E'); // Set break point at this line. two.integer = 1; + int dummy = 1; + return 0; }
\ No newline at end of file |