//===-- CommandObjectType.cpp ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "CommandObjectType.h" // C Includes #include // C++ Includes #include #include "llvm/ADT/StringRef.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/IOHandler.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/State.h" #include "lldb/Core/StringList.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadList.h" using namespace lldb; using namespace lldb_private; class ScriptAddOptions { public: TypeSummaryImpl::Flags m_flags; StringList m_target_types; bool m_regex; ConstString m_name; std::string m_category; ScriptAddOptions(const TypeSummaryImpl::Flags& flags, bool regx, const ConstString& name, std::string catg) : m_flags(flags), m_regex(regx), m_name(name), m_category(catg) { } typedef std::shared_ptr SharedPointer; }; class SynthAddOptions { public: bool m_skip_pointers; bool m_skip_references; bool m_cascade; bool m_regex; StringList m_target_types; std::string m_category; SynthAddOptions(bool sptr, bool sref, bool casc, bool regx, std::string catg) : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc), m_regex(regx), m_target_types(), m_category(catg) { } typedef std::shared_ptr SharedPointer; }; static bool WarnOnPotentialUnquotedUnsignedType (Args& command, CommandReturnObject &result) { for (unsigned idx = 0; idx < command.GetArgumentCount(); idx++) { const char* arg = command.GetArgumentAtIndex(idx); if (idx+1 < command.GetArgumentCount()) { if (arg && 0 == strcmp(arg,"unsigned")) { const char* next = command.GetArgumentAtIndex(idx+1); if (next && (0 == strcmp(next, "int") || 0 == strcmp(next, "short") || 0 == strcmp(next, "char") || 0 == strcmp(next, "long"))) { result.AppendWarningWithFormat("%s %s being treated as two types. if you meant the combined type name use quotes, as in \"%s %s\"\n", arg,next,arg,next); return true; } } } } return false; } class CommandObjectTypeSummaryAdd : public CommandObjectParsed, public IOHandlerDelegateMultiline { 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. TypeSummaryImpl::Flags m_flags; 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; std::string m_category; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } bool Execute_ScriptSummary (Args& command, CommandReturnObject &result); bool Execute_StringSummary (Args& command, CommandReturnObject &result); public: enum SummaryFormatType { eRegularSummary, eRegexSummary, eNamedSummary }; CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter); ~CommandObjectTypeSummaryAdd () { } virtual void IOHandlerActivated (IOHandler &io_handler) { static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" "def function (valobj,internal_dict):\n" " \"\"\"valobj: an SBValue which you want to provide a summary for\n" " internal_dict: an LLDB support object not to be used\"\"\"\n"; StreamFileSP output_sp(io_handler.GetOutputStreamFile()); if (output_sp) { output_sp->PutCString(g_summary_addreader_instructions); output_sp->Flush(); } } virtual void IOHandlerInputComplete (IOHandler &io_handler, std::string &data) { StreamFileSP error_sp = io_handler.GetErrorStreamFile(); #ifndef LLDB_DISABLE_PYTHON ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (interpreter) { StringList lines; lines.SplitIntoLines(data); if (lines.GetSize() > 0) { ScriptAddOptions *options_ptr = ((ScriptAddOptions*)io_handler.GetUserData()); if (options_ptr) { ScriptAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (interpreter) { std::string funct_name_str; if (interpreter->GenerateTypeScriptFunction (lines, funct_name_str)) { if (funct_name_str.empty()) { error_sp->Printf ("unable to obtain a valid function name from the script interpreter.\n"); error_sp->Flush(); } else { // now I have a valid function name, let's add this as script for every type in the list TypeSummaryImplSP script_format; script_format.reset(new ScriptSummaryFormat(options->m_flags, funct_name_str.c_str(), lines.CopyList(" ").c_str())); Error error; for (size_t i = 0; i < options->m_target_types.GetSize(); i++) { const char *type_name = options->m_target_types.GetStringAtIndex(i); CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), script_format, (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary), options->m_category, &error); if (error.Fail()) { error_sp->Printf ("error: %s", error.AsCString()); error_sp->Flush(); } } if (options->m_name) { CommandObjectTypeSummaryAdd::AddSummary (options->m_name, script_format, CommandObjectTypeSummaryAdd::eNamedSummary, options->m_category, &error); if (error.Fail()) { CommandObjectTypeSummaryAdd::AddSummary (options->m_name, script_format, CommandObjectTypeSummaryAdd::eNamedSummary, options->m_category, &error); if (error.Fail()) { error_sp->Printf ("error: %s", error.AsCString()); error_sp->Flush(); } } else { error_sp->Printf ("error: %s", error.AsCString()); error_sp->Flush(); } } else { if (error.AsCString()) { error_sp->Printf ("error: %s", error.AsCString()); error_sp->Flush(); } } } } else { error_sp->Printf ("error: unable to generate a function.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: no script interpreter.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: internal synchronization information missing or invalid.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: empty function, didn't add python command.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); error_sp->Flush(); } #endif // #ifndef LLDB_DISABLE_PYTHON io_handler.SetIsDone(true); } static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry, SummaryFormatType type, std::string category, Error* error = NULL); protected: bool DoExecute (Args& command, CommandReturnObject &result); }; static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" "You must define a Python class with these methods:\n" " def __init__(self, valobj, dict):\n" " def num_children(self):\n" " def get_child_at_index(self, index):\n" " def get_child_index(self, name):\n" " def update(self):\n" " '''Optional'''\n" "class synthProvider:\n"; class CommandObjectTypeSynthAdd : public CommandObjectParsed, public IOHandlerDelegateMultiline { 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; const int short_option = 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", option_arg); break; case 'P': handwrite_python = true; break; case 'l': m_class_name = std::string(option_arg); is_class_based = true; break; case 'p': m_skip_pointers = true; break; case 'r': m_skip_references = true; break; case 'w': m_category = std::string(option_arg); break; case 'x': m_regex = true; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_cascade = true; m_class_name = ""; m_skip_pointers = false; m_skip_references = false; m_category = "default"; is_class_based = false; handwrite_python = false; m_regex = 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_cascade; bool m_skip_references; bool m_skip_pointers; std::string m_class_name; bool m_input_python; std::string m_category; bool is_class_based; bool handwrite_python; bool m_regex; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } bool Execute_HandwritePython (Args& command, CommandReturnObject &result); bool Execute_PythonClass (Args& command, CommandReturnObject &result); protected: bool DoExecute (Args& command, CommandReturnObject &result) { WarnOnPotentialUnquotedUnsignedType(command, result); if (m_options.handwrite_python) return Execute_HandwritePython(command, result); else if (m_options.is_class_based) return Execute_PythonClass(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; } } virtual void IOHandlerActivated (IOHandler &io_handler) { StreamFileSP output_sp(io_handler.GetOutputStreamFile()); if (output_sp) { output_sp->PutCString(g_synth_addreader_instructions); output_sp->Flush(); } } virtual void IOHandlerInputComplete (IOHandler &io_handler, std::string &data) { StreamFileSP error_sp = io_handler.GetErrorStreamFile(); #ifndef LLDB_DISABLE_PYTHON ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (interpreter) { StringList lines; lines.SplitIntoLines(data); if (lines.GetSize() > 0) { SynthAddOptions *options_ptr = ((SynthAddOptions*)io_handler.GetUserData()); if (options_ptr) { SynthAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (interpreter) { std::string class_name_str; if (interpreter->GenerateTypeSynthClass (lines, class_name_str)) { if (class_name_str.empty()) { error_sp->Printf ("error: unable to obtain a proper name for the class.\n"); error_sp->Flush(); } else { // everything should be fine now, let's add the synth provider class SyntheticChildrenSP synth_provider; synth_provider.reset(new ScriptedSyntheticChildren(SyntheticChildren::Flags().SetCascades(options->m_cascade). SetSkipPointers(options->m_skip_pointers). SetSkipReferences(options->m_skip_references), class_name_str.c_str())); lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(options->m_category.c_str()), category); Error error; for (size_t i = 0; i < options->m_target_types.GetSize(); i++) { const char *type_name = options->m_target_types.GetStringAtIndex(i); ConstString const_type_name(type_name); if (const_type_name) { if (!CommandObjectTypeSynthAdd::AddSynth(const_type_name, synth_provider, options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth, options->m_category, &error)) { error_sp->Printf("error: %s\n", error.AsCString()); error_sp->Flush(); break; } } else { error_sp->Printf ("error: invalid type name.\n"); error_sp->Flush(); break; } } } } else { error_sp->Printf ("error: unable to generate a class.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: no script interpreter.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: internal synchronization data missing.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: empty function, didn't add python command.\n"); error_sp->Flush(); } } else { error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); error_sp->Flush(); } #endif // #ifndef LLDB_DISABLE_PYTHON io_handler.SetIsDone(true); } public: enum SynthFormatType { eRegularSynth, eRegexSynth }; CommandObjectTypeSynthAdd (CommandInterpreter &interpreter); ~CommandObjectTypeSynthAdd () { } static bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry, SynthFormatType type, std::string category_name, Error* error); }; //------------------------------------------------------------------------- // CommandObjectTypeFormatAdd //------------------------------------------------------------------------- class CommandObjectTypeFormatAdd : public CommandObjectParsed { private: class CommandOptions : public OptionGroup { public: CommandOptions () : OptionGroup() { } virtual ~CommandOptions () { } virtual uint32_t GetNumDefinitions (); virtual const OptionDefinition* GetDefinitions () { return g_option_table; } virtual void OptionParsingStarting (CommandInterpreter &interpreter) { m_cascade = true; m_skip_pointers = false; m_skip_references = false; m_regex = false; m_category.assign("default"); m_custom_type_name.clear(); } virtual Error SetOptionValue (CommandInterpreter &interpreter, uint32_t option_idx, const char *option_value) { Error error; const int short_option = g_option_table[option_idx].short_option; bool success; switch (short_option) { case 'C': m_cascade = Args::StringToBoolean(option_value, true, &success); if (!success) error.SetErrorStringWithFormat("invalid value for cascade: %s", option_value); break; case 'p': m_skip_pointers = true; break; case 'w': m_category.assign(option_value); break; case 'r': m_skip_references = true; break; case 'x': m_regex = true; break; case 't': m_custom_type_name.assign(option_value); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } // 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_skip_references; bool m_skip_pointers; bool m_regex; std::string m_category; std::string m_custom_type_name; }; OptionGroupOptions m_option_group; OptionGroupFormat m_format_options; CommandOptions m_command_options; virtual Options * GetOptions () { return &m_option_group; } public: CommandObjectTypeFormatAdd (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type format add", "Add a new formatting style for a type.", NULL), m_option_group (interpreter), m_format_options (eFormatInvalid), m_command_options () { 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( R"( The following examples of 'type format add' refer to this code snippet for context: typedef int Aint; typedef float Afloat; typedef Aint Bint; typedef Afloat Bfloat; Aint ix = 5; Bint iy = 5; Afloat fx = 3.14; BFloat fy = 3.14; Adding default formatting: (lldb) type format add -f hex AInt (lldb) frame variable iy )" " Produces hexidecimal display of iy, because no formatter is available for Bint and \ the one for Aint is used instead." R"( To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains: (lldb) type format add -f hex -C no AInt Similar reasoning applies to this: (lldb) type format add -f hex -C no float -p )" " All float values and float references are now formatted as hexadecimal, but not \ pointers to floats. Nor will it change the default display for Afloat and Bfloat objects." ); // Add the "--format" to all options groups m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1); m_option_group.Append (&m_command_options); m_option_group.Finalize(); } ~CommandObjectTypeFormatAdd () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc < 1) { result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } const Format format = m_format_options.GetFormat(); if (format == eFormatInvalid && m_command_options.m_custom_type_name.empty()) { result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } TypeFormatImplSP entry; if (m_command_options.m_custom_type_name.empty()) entry.reset(new TypeFormatImpl_Format(format, TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade). SetSkipPointers(m_command_options.m_skip_pointers). SetSkipReferences(m_command_options.m_skip_references))); else entry.reset(new TypeFormatImpl_EnumType(ConstString(m_command_options.m_custom_type_name.c_str()), TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade). SetSkipPointers(m_command_options.m_skip_pointers). SetSkipReferences(m_command_options.m_skip_references))); // now I have a valid format, let's add it to every type TypeCategoryImplSP category_sp; DataVisualization::Categories::GetCategory(ConstString(m_command_options.m_category), category_sp); if (!category_sp) return false; WarnOnPotentialUnquotedUnsignedType(command, result); for (size_t i = 0; i < argc; i++) { const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (typeCS) { if (m_command_options.m_regex) { RegularExpressionSP typeRX(new RegularExpression()); if (!typeRX->Compile(typeCS.GetCString())) { result.AppendError("regex format error (maybe this is not really a regex?)"); result.SetStatus(eReturnStatusFailed); return false; } category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS); category_sp->GetRegexTypeFormatsContainer()->Add(typeRX, entry); } else category_sp->GetTypeFormatsContainer()->Add(typeCS, entry); } else { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } } result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } }; OptionDefinition CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."}, { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."}, { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."}, { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."}, { LLDB_OPT_SET_2, false, "type", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Format variables as if they were of this type."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; uint32_t CommandObjectTypeFormatAdd::CommandOptions::GetNumDefinitions () { return sizeof(g_option_table) / sizeof (OptionDefinition); } //------------------------------------------------------------------------- // CommandObjectTypeFormatDelete //------------------------------------------------------------------------- class CommandObjectTypeFormatDelete : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; case 'w': m_category = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = false; m_category = "default"; } 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_all; std::string m_category; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& category_sp) { ConstString *name = (ConstString*)param; category_sp->Delete(*name, eFormatCategoryItemValue | eFormatCategoryItemRegexValue); return true; } public: CommandObjectTypeFormatDelete (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type format delete", "Delete an existing formatting 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 = eArgRepeatPlain; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeFormatDelete () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc != 1) { result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } const char* typeA = command.GetArgumentAtIndex(0); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_delete_all) { DataVisualization::Categories::LoopThrough(PerCategoryCallback, &typeCS); result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); bool delete_category = category->Delete(typeCS, eFormatCategoryItemValue | eFormatCategoryItemRegexValue); if (delete_category) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } else { result.AppendErrorWithFormat ("no custom format for %s.\n", typeA); result.SetStatus(eReturnStatusFailed); return false; } } }; OptionDefinition CommandObjectTypeFormatDelete::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."}, { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- // CommandObjectTypeFormatClear //------------------------------------------------------------------------- class CommandObjectTypeFormatClear : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = 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_all; bool m_delete_named; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { cate->GetTypeFormatsContainer()->Clear(); cate->GetRegexTypeFormatsContainer()->Clear(); return true; } public: CommandObjectTypeFormatClear (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type format clear", "Delete all existing format styles.", NULL), m_options(interpreter) { } ~CommandObjectTypeFormatClear () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { if (m_options.m_delete_all) DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL); else { lldb::TypeCategoryImplSP category; if (command.GetArgumentCount() > 0) { const char* cat_name = command.GetArgumentAtIndex(0); ConstString cat_nameCS(cat_name); DataVisualization::Categories::GetCategory(cat_nameCS, category); } else DataVisualization::Categories::GetCategory(ConstString(NULL), category); category->Clear(eFormatCategoryItemValue | eFormatCategoryItemRegexValue); } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; OptionDefinition CommandObjectTypeFormatClear::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- // CommandObjectTypeFormatList //------------------------------------------------------------------------- bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry); bool CommandObjectTypeRXFormatList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeFormatImplSP& entry); class CommandObjectTypeFormatList; struct CommandObjectTypeFormatList_LoopCallbackParam { CommandObjectTypeFormatList* self; CommandReturnObject* result; RegularExpression* regex; RegularExpression* cate_regex; CommandObjectTypeFormatList_LoopCallbackParam(CommandObjectTypeFormatList* S, CommandReturnObject* R, RegularExpression* X = NULL, RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {} }; class CommandObjectTypeFormatList : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'w': m_category_regex = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_category_regex = ""; } 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. std::string m_category_regex; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } public: CommandObjectTypeFormatList (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type format list", "Show a list of current formatting styles.", NULL), m_options(interpreter) { CommandArgumentEntry type_arg; CommandArgumentData type_style_arg; type_style_arg.arg_type = eArgTypeName; type_style_arg.arg_repetition = eArgRepeatOptional; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeFormatList () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); CommandObjectTypeFormatList_LoopCallbackParam *param; RegularExpression* cate_regex = m_options.m_category_regex.empty() ? NULL : new RegularExpression(m_options.m_category_regex.c_str()); if (argc == 1) { RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); regex->Compile(command.GetArgumentAtIndex(0)); param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result,regex,cate_regex); } else param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); delete param; if (cate_regex) delete cate_regex; result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } private: static bool PerCategoryCallback(void* param_vp, const lldb::TypeCategoryImplSP& cate) { CommandObjectTypeFormatList_LoopCallbackParam* param = (CommandObjectTypeFormatList_LoopCallbackParam*)param_vp; CommandReturnObject* result = param->result; const char* cate_name = cate->GetName(); // if the category is disabled or empty and there is no regex, just skip it if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemValue | eFormatCategoryItemRegexValue) == 0) && param->cate_regex == NULL) return true; // if we have a regex and this category does not match it, just skip it if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false) return true; result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n", cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); cate->GetTypeFormatsContainer()->LoopThrough(CommandObjectTypeFormatList_LoopCallback, param_vp); if (cate->GetRegexTypeSummariesContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based summaries (slower):\n"); cate->GetRegexTypeFormatsContainer()->LoopThrough(CommandObjectTypeRXFormatList_LoopCallback, param_vp); } return true; } bool LoopCallback (const char* type, const lldb::TypeFormatImplSP& entry, RegularExpression* regex, CommandReturnObject *result) { if (regex == NULL || strcmp(type,regex->GetText()) == 0 || regex->Execute(type)) result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str()); return true; } friend bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry); friend bool CommandObjectTypeRXFormatList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeFormatImplSP& entry); }; bool CommandObjectTypeFormatList_LoopCallback ( void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry) { CommandObjectTypeFormatList_LoopCallbackParam* param = (CommandObjectTypeFormatList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result); } bool CommandObjectTypeRXFormatList_LoopCallback ( void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeFormatImplSP& entry) { CommandObjectTypeFormatList_LoopCallbackParam* param = (CommandObjectTypeFormatList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result); } OptionDefinition CommandObjectTypeFormatList::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #ifndef LLDB_DISABLE_PYTHON //------------------------------------------------------------------------- // CommandObjectTypeSummaryAdd //------------------------------------------------------------------------- #endif // #ifndef LLDB_DISABLE_PYTHON Error CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg) { Error error; const int short_option = m_getopt_table[option_idx].val; bool success; switch (short_option) { case 'C': m_flags.SetCascades(Args::StringToBoolean(option_arg, true, &success)); if (!success) error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg); break; case 'e': m_flags.SetDontShowChildren(false); break; case 'v': m_flags.SetDontShowValue(true); break; case 'c': m_flags.SetShowMembersOneLiner(true); break; case 's': m_format_string = std::string(option_arg); break; case 'p': m_flags.SetSkipPointers(true); break; case 'r': m_flags.SetSkipReferences(true); break; case 'x': m_regex = true; break; case 'n': m_name.SetCString(option_arg); break; case 'o': 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_category = std::string(option_arg); break; case 'O': m_flags.SetHideItemNames(true); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting () { m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false); m_flags.SetShowMembersOneLiner(false).SetSkipPointers(false).SetSkipReferences(false).SetHideItemNames(false); m_regex = false; m_name.Clear(); m_python_script = ""; m_python_function = ""; m_format_string = ""; m_is_add_script = false; m_category = "default"; } #ifndef LLDB_DISABLE_PYTHON 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; } TypeSummaryImplSP script_format; if (!m_options.m_python_function.empty()) // we have a Python function ready to use { const char *funct_name = m_options.m_python_function.c_str(); if (!funct_name || !funct_name[0]) { result.AppendError ("function name empty.\n"); result.SetStatus (eReturnStatusFailed); return false; } std::string code = (" " + m_options.m_python_function + "(valobj,internal_dict)"); script_format.reset(new ScriptSummaryFormat(m_options.m_flags, funct_name, code.c_str())); ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (interpreter && interpreter->CheckObjectExists(funct_name) == false) result.AppendWarningWithFormat("The provided function \"%s\" does not exist - " "please define it before attempting to use this summary.\n", funct_name); } else if (!m_options.m_python_script.empty()) // we have a quick 1-line script, just use it { ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (!interpreter) { result.AppendError ("script interpreter missing - unable to generate function wrapper.\n"); result.SetStatus (eReturnStatusFailed); return false; } StringList funct_sl; funct_sl << m_options.m_python_script.c_str(); std::string funct_name_str; if (!interpreter->GenerateTypeScriptFunction (funct_sl, funct_name_str)) { result.AppendError ("unable to generate function wrapper.\n"); result.SetStatus (eReturnStatusFailed); return false; } if (funct_name_str.empty()) { result.AppendError ("script interpreter failed to generate a valid function name.\n"); result.SetStatus (eReturnStatusFailed); return false; } std::string code = " " + m_options.m_python_script; script_format.reset(new ScriptSummaryFormat(m_options.m_flags, funct_name_str.c_str(), code.c_str())); } else { // Use an IOHandler to grab Python code from the user ScriptAddOptions *options = new ScriptAddOptions(m_options.m_flags, m_options.m_regex, m_options.m_name, m_options.m_category); 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; } } m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt *this, // IOHandlerDelegate true, // Run IOHandler in async mode options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } // 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 (size_t i = 0; i < command.GetArgumentCount(); i++) { const char *type_name = command.GetArgumentAtIndex(i); CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), script_format, (m_options.m_regex ? eRegexSummary : eRegularSummary), m_options.m_category, &error); if (error.Fail()) { result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } } if (m_options.m_name) { AddSummary(m_options.m_name, script_format, eNamedSummary, m_options.m_category, &error); if (error.Fail()) { result.AppendError(error.AsCString()); result.AppendError("added to types, but not given a name"); result.SetStatus(eReturnStatusFailed); return false; } } return result.Succeeded(); } #endif 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_flags.GetShowMembersOneLiner() && 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_flags.GetShowMembersOneLiner() ? "" : m_options.m_format_string.c_str()); // ${var%S} is an endless recursion, prevent it if (strcmp(format_cstr, "${var%S}") == 0) { result.AppendError("recursive summary not allowed"); result.SetStatus(eReturnStatusFailed); return false; } Error error; lldb::TypeSummaryImplSP entry(new StringSummaryFormat(m_options.m_flags, 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 (size_t 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); AddSummary(typeCS, entry, (m_options.m_regex ? eRegexSummary : eRegularSummary), m_options.m_category, &error); if (error.Fail()) { result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } } if (m_options.m_name) { AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category, &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(); } CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type summary add", "Add a new summary style for a type.", NULL), IOHandlerDelegateMultiline ("DONE"), 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( R"( The following examples of 'type summary add' refer to this code snippet for context: struct JustADemo { int* ptr; float value; JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {} }; JustADemo demo_instance(42, 3.14); typedef JustADemo NewDemo; NewDemo new_demo_instance(42, 3.14); (lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42" (lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14" )" "Alternatively, you could define formatting for all pointers to integers and \ rely on that when formatting JustADemo to obtain the same result:" R"( (lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *" (lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo )" "Type summaries are automatically applied to derived typedefs, so the examples \ above apply to both JustADemo and NewDemo. The cascade option can be used to \ suppress this behavior:" R"( (lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no The summary will now be used for values of JustADemo but not NewDemo. )" "By default summaries are shown for pointers and references to values of the \ specified type. To suppress formatting for pointers use the -p option, or apply \ the corresponding -r option to suppress formatting for references:" R"( (lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo )" "One-line summaries including all fields in a type can be inferred without supplying an \ explicit summary string by passing the -c option:" R"( (lldb) type summary add -c JustADemo (lldb) frame variable demo_instance (ptr=
, value=3.14) )" "Type summaries normally suppress the nested display of individual fields. To \ supply a summary to supplement the default structure add the -e option:" R"( (lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo )" "Now when displaying JustADemo values the int* is displayed, followed by the \ standard LLDB sequence of children, one per line:" R"( *ptr = 42 { ptr =
value = 3.14 } )" "You can also add summaries written in Python. These scripts use lldb public API to \ gather information from your variables and produce a meaningful summary. To start a \ multi-line script use the -P option. The function declaration will be displayed along with \ a comment describing the two arguments. End your script with the word 'DONE' on a line by \ itself:" R"( (lldb) type summary add JustADemo -P def function (valobj,internal_dict): """valobj: an SBValue which you want to provide a summary for internal_dict: an LLDB support object not to be used""" value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue(); DONE Alternatively, the -o option can be used when providing a simple one-line Python script: (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")" ); } bool CommandObjectTypeSummaryAdd::DoExecute (Args& command, CommandReturnObject &result) { WarnOnPotentialUnquotedUnsignedType(command, result); if (m_options.m_is_add_script) { #ifndef LLDB_DISABLE_PYTHON return Execute_ScriptSummary(command, result); #else result.AppendError ("python is disabled"); result.SetStatus(eReturnStatusFailed); return false; #endif } return Execute_StringSummary(command, result); } static bool FixArrayTypeNameWithRegex (ConstString &type_name) { llvm::StringRef type_name_ref(type_name.GetStringRef()); if (type_name_ref.endswith("[]")) { std::string type_name_str(type_name.GetCString()); type_name_str.resize(type_name_str.length()-2); if (type_name_str.back() != ' ') type_name_str.append(" \\[[0-9]+\\]"); else type_name_str.append("\\[[0-9]+\\]"); type_name.SetCString(type_name_str.c_str()); return true; } return false; } bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, TypeSummaryImplSP entry, SummaryFormatType type, std::string category_name, Error* error) { lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category); if (type == eRegularSummary) { if (FixArrayTypeNameWithRegex (type_name)) type = eRegexSummary; } 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; } category->GetRegexTypeSummariesContainer()->Delete(type_name); category->GetRegexTypeSummariesContainer()->Add(typeRX, entry); return true; } else if (type == eNamedSummary) { // system named summaries do not exist (yet?) DataVisualization::NamedSummaryFormats::Add(type_name,entry); return true; } else { category->GetTypeSummariesContainer()->Add(type_name, entry); return true; } } OptionDefinition CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."}, { LLDB_OPT_SET_ALL, false, "no-value", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type."}, { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."}, { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."}, { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."}, { LLDB_OPT_SET_1 , true, "inline-children", 'c', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "If true, inline all child values into summary string."}, { LLDB_OPT_SET_1 , false, "omit-names", 'O', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "If true, omit value names in the summary display."}, { LLDB_OPT_SET_2 , true, "summary-string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeSummaryString, "Summary string used to display text and object contents."}, { LLDB_OPT_SET_3, false, "python-script", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command."}, { LLDB_OPT_SET_3, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."}, { LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."}, { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."}, { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "A name for this summary string."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- // CommandObjectTypeSummaryDelete //------------------------------------------------------------------------- class CommandObjectTypeSummaryDelete : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; case 'w': m_category = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = false; m_category = "default"; } 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_all; std::string m_category; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& category_sp) { ConstString *name = (ConstString*)param; category_sp->Delete(*name, eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary); return true; } public: CommandObjectTypeSummaryDelete (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type summary delete", "Delete an existing 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 = eArgRepeatPlain; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeSummaryDelete () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc != 1) { result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } const char* typeA = command.GetArgumentAtIndex(0); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_delete_all) { DataVisualization::Categories::LoopThrough(PerCategoryCallback, &typeCS); result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); bool delete_category = category->Delete(typeCS, eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary); bool delete_named = DataVisualization::NamedSummaryFormats::Delete(typeCS); if (delete_category || delete_named) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } else { result.AppendErrorWithFormat ("no custom summary for %s.\n", typeA); result.SetStatus(eReturnStatusFailed); return false; } } }; OptionDefinition CommandObjectTypeSummaryDelete::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."}, { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; class CommandObjectTypeSummaryClear : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = 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_all; bool m_delete_named; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { cate->GetTypeSummariesContainer()->Clear(); cate->GetRegexTypeSummariesContainer()->Clear(); return true; } public: CommandObjectTypeSummaryClear (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type summary clear", "Delete all existing summary styles.", NULL), m_options(interpreter) { } ~CommandObjectTypeSummaryClear () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { if (m_options.m_delete_all) DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL); else { lldb::TypeCategoryImplSP category; if (command.GetArgumentCount() > 0) { const char* cat_name = command.GetArgumentAtIndex(0); ConstString cat_nameCS(cat_name); DataVisualization::Categories::GetCategory(cat_nameCS, category); } else DataVisualization::Categories::GetCategory(ConstString(NULL), category); category->Clear(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary); } DataVisualization::NamedSummaryFormats::Clear(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; OptionDefinition CommandObjectTypeSummaryClear::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- // CommandObjectTypeSummaryList //------------------------------------------------------------------------- bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, ConstString type, const StringSummaryFormat::SharedPointer& entry); bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const StringSummaryFormat::SharedPointer& entry); class CommandObjectTypeSummaryList; struct CommandObjectTypeSummaryList_LoopCallbackParam { CommandObjectTypeSummaryList* self; CommandReturnObject* result; RegularExpression* regex; RegularExpression* cate_regex; CommandObjectTypeSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R, RegularExpression* X = NULL, RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {} }; class CommandObjectTypeSummaryList : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'w': m_category_regex = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_category_regex = ""; } 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. std::string m_category_regex; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } public: CommandObjectTypeSummaryList (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type summary list", "Show a list of current summary styles.", NULL), m_options(interpreter) { CommandArgumentEntry type_arg; CommandArgumentData type_style_arg; type_style_arg.arg_type = eArgTypeName; type_style_arg.arg_repetition = eArgRepeatOptional; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeSummaryList () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); CommandObjectTypeSummaryList_LoopCallbackParam *param; RegularExpression* cate_regex = m_options.m_category_regex.empty() ? NULL : new RegularExpression(m_options.m_category_regex.c_str()); if (argc == 1) { RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); regex->Compile(command.GetArgumentAtIndex(0)); param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex,cate_regex); } else param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); delete param; if (DataVisualization::NamedSummaryFormats::GetCount() > 0) { result.GetOutputStream().Printf("Named summaries:\n"); if (argc == 1) { RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); regex->Compile(command.GetArgumentAtIndex(0)); param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex); } else param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result); DataVisualization::NamedSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); delete param; } if (cate_regex) delete cate_regex; result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } private: static bool PerCategoryCallback(void* param_vp, const lldb::TypeCategoryImplSP& cate) { CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)param_vp; CommandReturnObject* result = param->result; const char* cate_name = cate->GetName(); // if the category is disabled or empty and there is no regex, just skip it if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary) == 0) && param->cate_regex == NULL) return true; // if we have a regex and this category does not match it, just skip it if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false) return true; result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n", cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); cate->GetTypeSummariesContainer()->LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param_vp); if (cate->GetRegexTypeSummariesContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based summaries (slower):\n"); cate->GetRegexTypeSummariesContainer()->LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, param_vp); } return true; } bool LoopCallback (const char* type, const lldb::TypeSummaryImplSP& entry, RegularExpression* regex, CommandReturnObject *result) { if (regex == NULL || strcmp(type,regex->GetText()) == 0 || regex->Execute(type)) result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str()); return true; } friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeSummaryImplSP& entry); friend bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeSummaryImplSP& entry); }; bool CommandObjectTypeSummaryList_LoopCallback ( void* pt2self, ConstString type, const lldb::TypeSummaryImplSP& entry) { CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result); } bool CommandObjectTypeRXSummaryList_LoopCallback ( void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeSummaryImplSP& entry) { CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result); } OptionDefinition CommandObjectTypeSummaryList::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- // CommandObjectTypeCategoryEnable //------------------------------------------------------------------------- class CommandObjectTypeCategoryEnable : public CommandObjectParsed { public: CommandObjectTypeCategoryEnable (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type category enable", "Enable a category as a source of formatters.", NULL) { 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); } ~CommandObjectTypeCategoryEnable () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc < 1) { result.AppendErrorWithFormat ("%s takes 1 or more args.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0) { DataVisualization::Categories::EnableStar(); } else { for (int i = argc - 1; i >= 0; i--) { const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty category name not allowed"); result.SetStatus(eReturnStatusFailed); return false; } DataVisualization::Categories::Enable(typeCS); lldb::TypeCategoryImplSP cate; if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate.get()) { if (cate->GetCount() == 0) { result.AppendWarning("empty category enabled (typo?)"); } } } } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; //------------------------------------------------------------------------- // CommandObjectTypeCategoryDelete //------------------------------------------------------------------------- class CommandObjectTypeCategoryDelete : public CommandObjectParsed { public: CommandObjectTypeCategoryDelete (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type category delete", "Delete a category and all associated formatters.", NULL) { 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); } ~CommandObjectTypeCategoryDelete () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc < 1) { result.AppendErrorWithFormat ("%s takes 1 or more arg.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } bool success = true; // the order is not relevant here for (int i = argc - 1; i >= 0; i--) { const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty category name not allowed"); result.SetStatus(eReturnStatusFailed); return false; } if (!DataVisualization::Categories::Delete(typeCS)) success = false; // keep deleting even if we hit an error } if (success) { result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } else { result.AppendError("cannot delete one or more categories\n"); result.SetStatus(eReturnStatusFailed); return false; } } }; //------------------------------------------------------------------------- // CommandObjectTypeCategoryDisable //------------------------------------------------------------------------- class CommandObjectTypeCategoryDisable : public CommandObjectParsed { public: CommandObjectTypeCategoryDisable (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type category disable", "Disable a category as a source of formatters.", NULL) { 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); } ~CommandObjectTypeCategoryDisable () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc < 1) { result.AppendErrorWithFormat ("%s takes 1 or more args.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0) { DataVisualization::Categories::DisableStar(); } else { // the order is not relevant here for (int i = argc - 1; i >= 0; i--) { const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty category name not allowed"); result.SetStatus(eReturnStatusFailed); return false; } DataVisualization::Categories::Disable(typeCS); } } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; //------------------------------------------------------------------------- // CommandObjectTypeCategoryList //------------------------------------------------------------------------- class CommandObjectTypeCategoryList : public CommandObjectParsed { private: struct CommandObjectTypeCategoryList_CallbackParam { CommandReturnObject* result; RegularExpression* regex; CommandObjectTypeCategoryList_CallbackParam(CommandReturnObject* res, RegularExpression* rex = NULL) : result(res), regex(rex) { } }; static bool PerCategoryCallback(void* param_vp, const lldb::TypeCategoryImplSP& cate) { CommandObjectTypeCategoryList_CallbackParam* param = (CommandObjectTypeCategoryList_CallbackParam*)param_vp; CommandReturnObject* result = param->result; RegularExpression* regex = param->regex; const char* cate_name = cate->GetName(); if (regex == NULL || strcmp(cate_name, regex->GetText()) == 0 || regex->Execute(cate_name)) result->GetOutputStream().Printf("Category %s is%s enabled\n", cate_name, (cate->IsEnabled() ? "" : " not")); return true; } public: CommandObjectTypeCategoryList (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type category list", "Provide a list of all existing categories.", NULL) { CommandArgumentEntry type_arg; CommandArgumentData type_style_arg; type_style_arg.arg_type = eArgTypeName; type_style_arg.arg_repetition = eArgRepeatOptional; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeCategoryList () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); RegularExpression* regex = NULL; if (argc == 0) ; else if (argc == 1) regex = new RegularExpression(command.GetArgumentAtIndex(0)); else { result.AppendErrorWithFormat ("%s takes 0 or one arg.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } CommandObjectTypeCategoryList_CallbackParam param(&result, regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback, ¶m); if (regex) delete regex; result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; //------------------------------------------------------------------------- // CommandObjectTypeFilterList //------------------------------------------------------------------------- bool CommandObjectTypeFilterList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry); bool CommandObjectTypeFilterRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry); class CommandObjectTypeFilterList; struct CommandObjectTypeFilterList_LoopCallbackParam { CommandObjectTypeFilterList* self; CommandReturnObject* result; RegularExpression* regex; RegularExpression* cate_regex; CommandObjectTypeFilterList_LoopCallbackParam(CommandObjectTypeFilterList* S, CommandReturnObject* R, RegularExpression* X = NULL, RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {} }; class CommandObjectTypeFilterList : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'w': m_category_regex = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_category_regex = ""; } 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. std::string m_category_regex; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } public: CommandObjectTypeFilterList (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type filter list", "Show a list of current filters.", NULL), m_options(interpreter) { CommandArgumentEntry type_arg; CommandArgumentData type_style_arg; type_style_arg.arg_type = eArgTypeName; type_style_arg.arg_repetition = eArgRepeatOptional; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeFilterList () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); CommandObjectTypeFilterList_LoopCallbackParam *param; RegularExpression* cate_regex = m_options.m_category_regex.empty() ? NULL : new RegularExpression(m_options.m_category_regex.c_str()); if (argc == 1) { RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); regex->Compile(command.GetArgumentAtIndex(0)); param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,regex,cate_regex); } else param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); delete param; if (cate_regex) delete cate_regex; result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } private: static bool PerCategoryCallback(void* param_vp, const lldb::TypeCategoryImplSP& cate) { const char* cate_name = cate->GetName(); CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)param_vp; CommandReturnObject* result = param->result; // if the category is disabled or empty and there is no regex, just skip it if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter) == 0) && param->cate_regex == NULL) return true; // if we have a regex and this category does not match it, just skip it if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false) return true; result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n", cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); cate->GetTypeFiltersContainer()->LoopThrough(CommandObjectTypeFilterList_LoopCallback, param_vp); if (cate->GetRegexTypeFiltersContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based filters (slower):\n"); cate->GetRegexTypeFiltersContainer()->LoopThrough(CommandObjectTypeFilterRXList_LoopCallback, param_vp); } return true; } bool LoopCallback (const char* type, const SyntheticChildren::SharedPointer& entry, RegularExpression* regex, CommandReturnObject *result) { if (regex == NULL || regex->Execute(type)) result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str()); return true; } friend bool CommandObjectTypeFilterList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry); friend bool CommandObjectTypeFilterRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry); }; bool CommandObjectTypeFilterList_LoopCallback (void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry) { CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result); } bool CommandObjectTypeFilterRXList_LoopCallback (void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry) { CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result); } OptionDefinition CommandObjectTypeFilterList::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #ifndef LLDB_DISABLE_PYTHON //------------------------------------------------------------------------- // CommandObjectTypeSynthList //------------------------------------------------------------------------- bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry); bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry); class CommandObjectTypeSynthList; struct CommandObjectTypeSynthList_LoopCallbackParam { CommandObjectTypeSynthList* self; CommandReturnObject* result; RegularExpression* regex; RegularExpression* cate_regex; CommandObjectTypeSynthList_LoopCallbackParam(CommandObjectTypeSynthList* S, CommandReturnObject* R, RegularExpression* X = NULL, RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {} }; class CommandObjectTypeSynthList : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'w': m_category_regex = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_category_regex = ""; } 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. std::string m_category_regex; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } public: CommandObjectTypeSynthList (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type synthetic list", "Show a list of current synthetic providers.", NULL), m_options(interpreter) { CommandArgumentEntry type_arg; CommandArgumentData type_style_arg; type_style_arg.arg_type = eArgTypeName; type_style_arg.arg_repetition = eArgRepeatOptional; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeSynthList () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); CommandObjectTypeSynthList_LoopCallbackParam *param; RegularExpression* cate_regex = m_options.m_category_regex.empty() ? NULL : new RegularExpression(m_options.m_category_regex.c_str()); if (argc == 1) { RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); regex->Compile(command.GetArgumentAtIndex(0)); param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,regex,cate_regex); } else param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); delete param; if (cate_regex) delete cate_regex; result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } private: static bool PerCategoryCallback(void* param_vp, const lldb::TypeCategoryImplSP& cate) { CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)param_vp; CommandReturnObject* result = param->result; const char* cate_name = cate->GetName(); // if the category is disabled or empty and there is no regex, just skip it if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth) == 0) && param->cate_regex == NULL) return true; // if we have a regex and this category does not match it, just skip it if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false) return true; result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n", cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); cate->GetTypeSyntheticsContainer()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp); if (cate->GetRegexTypeSyntheticsContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based synthetic providers (slower):\n"); cate->GetRegexTypeSyntheticsContainer()->LoopThrough(CommandObjectTypeSynthRXList_LoopCallback, param_vp); } return true; } bool LoopCallback (const char* type, const SyntheticChildren::SharedPointer& entry, RegularExpression* regex, CommandReturnObject *result) { if (regex == NULL || regex->Execute(type)) result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str()); return true; } friend bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry); friend bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry); }; bool CommandObjectTypeSynthList_LoopCallback (void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry) { CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result); } bool CommandObjectTypeSynthRXList_LoopCallback (void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry) { CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result); } OptionDefinition CommandObjectTypeSynthList::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "category-regex", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Only show categories matching this filter."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #endif // #ifndef LLDB_DISABLE_PYTHON //------------------------------------------------------------------------- // CommandObjectTypeFilterDelete //------------------------------------------------------------------------- class CommandObjectTypeFilterDelete : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; case 'w': m_category = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = false; m_category = "default"; } 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_all; std::string m_category; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { ConstString *name = (ConstString*)param; return cate->Delete(*name, eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter); } public: CommandObjectTypeFilterDelete (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type filter delete", "Delete an existing filter 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 = eArgRepeatPlain; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeFilterDelete () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc != 1) { result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } const char* typeA = command.GetArgumentAtIndex(0); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_delete_all) { DataVisualization::Categories::LoopThrough(PerCategoryCallback, (void*)&typeCS); result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); bool delete_category = category->GetTypeFiltersContainer()->Delete(typeCS); delete_category = category->GetRegexTypeFiltersContainer()->Delete(typeCS) || delete_category; if (delete_category) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } else { result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA); result.SetStatus(eReturnStatusFailed); return false; } } }; OptionDefinition CommandObjectTypeFilterDelete::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."}, { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #ifndef LLDB_DISABLE_PYTHON //------------------------------------------------------------------------- // CommandObjectTypeSynthDelete //------------------------------------------------------------------------- class CommandObjectTypeSynthDelete : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; case 'w': m_category = std::string(option_arg); break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = false; m_category = "default"; } 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_all; std::string m_category; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { ConstString* name = (ConstString*)param; return cate->Delete(*name, eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth); } public: CommandObjectTypeSynthDelete (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type synthetic delete", "Delete an existing synthetic provider 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 = eArgRepeatPlain; type_arg.push_back (type_style_arg); m_arguments.push_back (type_arg); } ~CommandObjectTypeSynthDelete () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc != 1) { result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } const char* typeA = command.GetArgumentAtIndex(0); ConstString typeCS(typeA); if (!typeCS) { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_delete_all) { DataVisualization::Categories::LoopThrough(PerCategoryCallback, (void*)&typeCS); result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); bool delete_category = category->GetTypeSyntheticsContainer()->Delete(typeCS); delete_category = category->GetRegexTypeSyntheticsContainer()->Delete(typeCS) || delete_category; if (delete_category) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } else { result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA); result.SetStatus(eReturnStatusFailed); return false; } } }; OptionDefinition CommandObjectTypeSynthDelete::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Delete from every category."}, { LLDB_OPT_SET_2, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Delete from given category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #endif // #ifndef LLDB_DISABLE_PYTHON //------------------------------------------------------------------------- // CommandObjectTypeFilterClear //------------------------------------------------------------------------- class CommandObjectTypeFilterClear : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = 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_all; bool m_delete_named; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { cate->Clear(eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter); return true; } public: CommandObjectTypeFilterClear (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type filter clear", "Delete all existing filters.", NULL), m_options(interpreter) { } ~CommandObjectTypeFilterClear () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { if (m_options.m_delete_all) DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL); else { lldb::TypeCategoryImplSP category; if (command.GetArgumentCount() > 0) { const char* cat_name = command.GetArgumentAtIndex(0); ConstString cat_nameCS(cat_name); DataVisualization::Categories::GetCategory(cat_nameCS, category); } else DataVisualization::Categories::GetCategory(ConstString(NULL), category); category->GetTypeFiltersContainer()->Clear(); category->GetRegexTypeFiltersContainer()->Clear(); } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; OptionDefinition CommandObjectTypeFilterClear::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #ifndef LLDB_DISABLE_PYTHON //------------------------------------------------------------------------- // CommandObjectTypeSynthClear //------------------------------------------------------------------------- class CommandObjectTypeSynthClear : public CommandObjectParsed { 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; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'a': m_delete_all = true; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_delete_all = 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_all; bool m_delete_named; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } static bool PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { cate->Clear(eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth); return true; } public: CommandObjectTypeSynthClear (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type synthetic clear", "Delete all existing synthetic providers.", NULL), m_options(interpreter) { } ~CommandObjectTypeSynthClear () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { if (m_options.m_delete_all) DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL); else { lldb::TypeCategoryImplSP category; if (command.GetArgumentCount() > 0) { const char* cat_name = command.GetArgumentAtIndex(0); ConstString cat_nameCS(cat_name); DataVisualization::Categories::GetCategory(cat_nameCS, category); } else DataVisualization::Categories::GetCategory(ConstString(NULL), category); category->GetTypeSyntheticsContainer()->Clear(); category->GetRegexTypeSyntheticsContainer()->Clear(); } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } }; OptionDefinition CommandObjectTypeSynthClear::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "all", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Clear every category."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; bool CommandObjectTypeSynthAdd::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_regex, 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; } } m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt *this, // IOHandlerDelegate true, // Run IOHandler in async mode options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } bool CommandObjectTypeSynthAdd::Execute_PythonClass (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc < 1) { result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_class_name.empty() && !m_options.m_input_python) { result.AppendErrorWithFormat ("%s needs either a Python class name or -P to directly input Python code.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } SyntheticChildrenSP entry; ScriptedSyntheticChildren* impl = new ScriptedSyntheticChildren(SyntheticChildren::Flags(). SetCascades(m_options.m_cascade). SetSkipPointers(m_options.m_skip_pointers). SetSkipReferences(m_options.m_skip_references), m_options.m_class_name.c_str()); entry.reset(impl); ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); if (interpreter && interpreter->CheckObjectExists(impl->GetPythonClassName()) == false) result.AppendWarning("The provided class does not exist - please define it before attempting to use this synthetic provider"); // now I have a valid provider, let's add it to every type lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); Error error; for (size_t i = 0; i < argc; i++) { const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (typeCS) { if (!AddSynth(typeCS, entry, m_options.m_regex ? eRegexSynth : eRegularSynth, m_options.m_category, &error)) { result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } } else { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } } result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type synthetic add", "Add a new synthetic provider for a type.", NULL), IOHandlerDelegateMultiline ("DONE"), 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); } bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name, SyntheticChildrenSP entry, SynthFormatType type, std::string category_name, Error* error) { lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category); if (type == eRegularSynth) { if (FixArrayTypeNameWithRegex (type_name)) type = eRegexSynth; } if (category->AnyMatches(type_name, eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter, false)) { if (error) error->SetErrorStringWithFormat("cannot add synthetic for type %s when filter is defined in same category!", type_name.AsCString()); return false; } if (type == eRegexSynth) { 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; } category->GetRegexTypeSyntheticsContainer()->Delete(type_name); category->GetRegexTypeSyntheticsContainer()->Add(typeRX, entry); return true; } else { category->GetTypeSyntheticsContainer()->Add(type_name, entry); return true; } } OptionDefinition CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."}, { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."}, { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-tNULL, ype objects."}, { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children."}, { LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument,NULL, NULL, 0, eArgTypeNone, "Type Python code to generate a class that NULL, provides synthetic children."}, { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; #endif // #ifndef LLDB_DISABLE_PYTHON class CommandObjectTypeFilterAdd : public CommandObjectParsed { private: class CommandOptions : public Options { typedef std::vector option_vector; public: CommandOptions (CommandInterpreter &interpreter) : Options (interpreter) { } virtual ~CommandOptions (){} virtual Error SetOptionValue (uint32_t option_idx, const char *option_arg) { Error error; const int short_option = 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", option_arg); break; case 'c': m_expr_paths.push_back(option_arg); has_child_list = true; break; case 'p': m_skip_pointers = true; break; case 'r': m_skip_references = true; break; case 'w': m_category = std::string(option_arg); break; case 'x': m_regex = true; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; } return error; } void OptionParsingStarting () { m_cascade = true; m_skip_pointers = false; m_skip_references = false; m_category = "default"; m_expr_paths.clear(); has_child_list = false; m_regex = 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_cascade; bool m_skip_references; bool m_skip_pointers; bool m_input_python; option_vector m_expr_paths; std::string m_category; bool has_child_list; bool m_regex; typedef option_vector::iterator ExpressionPathsIterator; }; CommandOptions m_options; virtual Options * GetOptions () { return &m_options; } enum FilterFormatType { eRegularFilter, eRegexFilter }; bool AddFilter(ConstString type_name, SyntheticChildrenSP entry, FilterFormatType type, std::string category_name, Error* error) { lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category); if (type == eRegularFilter) { if (FixArrayTypeNameWithRegex (type_name)) type = eRegexFilter; } if (category->AnyMatches(type_name, eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth, false)) { if (error) error->SetErrorStringWithFormat("cannot add filter for type %s when synthetic is defined in same category!", type_name.AsCString()); return false; } if (type == eRegexFilter) { 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; } category->GetRegexTypeFiltersContainer()->Delete(type_name); category->GetRegexTypeFiltersContainer()->Add(typeRX, entry); return true; } else { category->GetTypeFiltersContainer()->Add(type_name, entry); return true; } } public: CommandObjectTypeFilterAdd (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "type filter add", "Add a new filter 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( R"( The following examples of 'type filter add' refer to this code snippet for context: class Foo { int a; int b; int c; int d; int e; int f; int g; int h; int i; } Foo my_foo; Adding a simple filter: (lldb) type filter add --child a --child g Foo (lldb) frame variable my_foo )" "Produces output where only a and g are displayed. Other children of my_foo \ (b, c, d, e, f, h and i) are available by asking for them explicitly:" R"( (lldb) frame variable my_foo.b my_foo.c my_foo.i )" "The formatting option --raw on frame variable bypasses the filter, showing \ all children of my_foo as if no filter was defined:" R"( (lldb) frame variable my_foo --raw)" ); } ~CommandObjectTypeFilterAdd () { } protected: bool DoExecute (Args& command, CommandReturnObject &result) { const size_t argc = command.GetArgumentCount(); if (argc < 1) { result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_expr_paths.size() == 0) { result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } SyntheticChildrenSP entry; TypeFilterImpl* impl = new TypeFilterImpl(SyntheticChildren::Flags().SetCascades(m_options.m_cascade). SetSkipPointers(m_options.m_skip_pointers). SetSkipReferences(m_options.m_skip_references)); entry.reset(impl); // go through the expression paths CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end(); for (begin = m_options.m_expr_paths.begin(); begin != end; begin++) impl->AddExpressionPath(*begin); // now I have a valid provider, let's add it to every type lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); Error error; WarnOnPotentialUnquotedUnsignedType(command, result); for (size_t i = 0; i < argc; i++) { const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (typeCS) { if (!AddFilter(typeCS, entry, m_options.m_regex ? eRegexFilter : eRegularFilter, m_options.m_category, &error)) { result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } } else { result.AppendError("empty typenames not allowed"); result.SetStatus(eReturnStatusFailed); return false; } } result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } }; OptionDefinition CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."}, { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."}, { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."}, { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, { LLDB_OPT_SET_ALL, false, "child", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view."}, { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; template class CommandObjectFormatterInfo : public CommandObjectRaw { public: typedef std::function DiscoveryFunction; CommandObjectFormatterInfo (CommandInterpreter &interpreter, const char* formatter_name, DiscoveryFunction discovery_func) : CommandObjectRaw(interpreter, nullptr, nullptr, nullptr, eCommandRequiresFrame), m_formatter_name(formatter_name ? formatter_name : ""), m_discovery_function(discovery_func) { StreamString name; name.Printf("type %s info", formatter_name); SetCommandName(name.GetData()); StreamString help; help.Printf("This command evaluates the provided expression and shows which %s is applied to the resulting value (if any).", formatter_name); SetHelp(help.GetData()); StreamString syntax; syntax.Printf("type %s info ", formatter_name); SetSyntax(syntax.GetData()); } virtual ~CommandObjectFormatterInfo () { } protected: virtual bool DoExecute (const char *command, CommandReturnObject &result) { auto target_sp = m_interpreter.GetDebugger().GetSelectedTarget(); auto frame_sp = target_sp->GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame(); ValueObjectSP result_valobj_sp; EvaluateExpressionOptions options; lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(command, frame_sp.get(), result_valobj_sp, options); if (expr_result == eExpressionCompleted && result_valobj_sp) { result_valobj_sp = result_valobj_sp->GetQualifiedRepresentationIfAvailable(target_sp->GetPreferDynamicValue(), target_sp->GetEnableSyntheticValue()); typename FormatterType::SharedPointer formatter_sp = m_discovery_function(*result_valobj_sp); if (formatter_sp) { std::string description(formatter_sp->GetDescription()); result.AppendMessageWithFormat("%s applied to (%s) %s is: %s\n", m_formatter_name.c_str(), result_valobj_sp->GetDisplayTypeName().AsCString(""), command, description.c_str()); result.SetStatus(lldb::eReturnStatusSuccessFinishResult); } else { result.AppendMessageWithFormat("no %s applies to (%s) %s\n", m_formatter_name.c_str(), result_valobj_sp->GetDisplayTypeName().AsCString(""), command); result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); } return true; } else { result.AppendError("failed to evaluate expression"); result.SetStatus(lldb::eReturnStatusFailed); return false; } } private: std::string m_formatter_name; DiscoveryFunction m_discovery_function; }; class CommandObjectTypeFormat : public CommandObjectMultiword { public: CommandObjectTypeFormat (CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "type format", "A set of commands for editing variable value display options", "type format [] ") { LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFormatAdd (interpreter))); LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFormatClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFormatDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFormatList (interpreter))); LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo(interpreter, "format", [](ValueObject& valobj) -> TypeFormatImpl::SharedPointer { return valobj.GetValueFormat(); }))); } ~CommandObjectTypeFormat () { } }; #ifndef LLDB_DISABLE_PYTHON class CommandObjectTypeSynth : public CommandObjectMultiword { public: CommandObjectTypeSynth (CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "type synthetic", "A set of commands for operating on synthetic type representations", "type synthetic [] ") { LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSynthAdd (interpreter))); LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter))); LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo(interpreter, "synthetic", [](ValueObject& valobj) -> SyntheticChildren::SharedPointer { return valobj.GetSyntheticChildren(); }))); } ~CommandObjectTypeSynth () { } }; #endif // #ifndef LLDB_DISABLE_PYTHON class CommandObjectTypeFilter : public CommandObjectMultiword { public: CommandObjectTypeFilter (CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "type filter", "A set of commands for operating on type filters", "type synthetic [] ") { LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFilterAdd (interpreter))); LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFilterClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFilterDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFilterList (interpreter))); } ~CommandObjectTypeFilter () { } }; class CommandObjectTypeCategory : public CommandObjectMultiword { public: CommandObjectTypeCategory (CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "type category", "A set of commands for operating on categories", "type category [] ") { LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTypeCategoryEnable (interpreter))); LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTypeCategoryDisable (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeCategoryDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeCategoryList (interpreter))); } ~CommandObjectTypeCategory () { } }; class CommandObjectTypeSummary : public CommandObjectMultiword { public: CommandObjectTypeSummary (CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "type summary", "A set of commands for editing variable summary display options", "type summary [] ") { LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter))); LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter))); LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo(interpreter, "summary", [](ValueObject& valobj) -> TypeSummaryImpl::SharedPointer { return valobj.GetSummaryFormat(); }))); } ~CommandObjectTypeSummary () { } }; //------------------------------------------------------------------------- // CommandObjectType //------------------------------------------------------------------------- CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "type", "A set of commands for operating on the type system", "type []") { LoadSubCommand ("category", CommandObjectSP (new CommandObjectTypeCategory (interpreter))); LoadSubCommand ("filter", CommandObjectSP (new CommandObjectTypeFilter (interpreter))); LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter))); LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter))); #ifndef LLDB_DISABLE_PYTHON LoadSubCommand ("synthetic", CommandObjectSP (new CommandObjectTypeSynth (interpreter))); #endif } CommandObjectType::~CommandObjectType () { }