diff options
Diffstat (limited to 'source/Commands')
-rw-r--r-- | source/Commands/CommandCompletions.cpp | 6 | ||||
-rw-r--r-- | source/Commands/CommandObjectBreakpoint.cpp | 588 | ||||
-rw-r--r-- | source/Commands/CommandObjectBreakpoint.h | 14 | ||||
-rw-r--r-- | source/Commands/CommandObjectBreakpointCommand.cpp | 112 | ||||
-rw-r--r-- | source/Commands/CommandObjectCommands.cpp | 238 | ||||
-rw-r--r-- | source/Commands/CommandObjectExpression.cpp | 6 | ||||
-rw-r--r-- | source/Commands/CommandObjectMemory.cpp | 113 | ||||
-rw-r--r-- | source/Commands/CommandObjectPlatform.cpp | 5 | ||||
-rw-r--r-- | source/Commands/CommandObjectProcess.cpp | 27 | ||||
-rw-r--r-- | source/Commands/CommandObjectSource.cpp | 12 | ||||
-rw-r--r-- | source/Commands/CommandObjectSyntax.cpp | 6 | ||||
-rw-r--r-- | source/Commands/CommandObjectTarget.cpp | 120 | ||||
-rw-r--r-- | source/Commands/CommandObjectThread.cpp | 666 | ||||
-rw-r--r-- | source/Commands/CommandObjectType.cpp | 125 | ||||
-rw-r--r-- | source/Commands/CommandObjectWatchpointCommand.cpp | 15 |
15 files changed, 1618 insertions, 435 deletions
diff --git a/source/Commands/CommandCompletions.cpp b/source/Commands/CommandCompletions.cpp index f0ad4a8..c65dd9d 100644 --- a/source/Commands/CommandCompletions.cpp +++ b/source/Commands/CommandCompletions.cpp @@ -112,7 +112,7 @@ CommandCompletions::SourceFiles if (searcher == NULL) { lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); - SearchFilter null_searcher (target_sp); + SearchFilterForUnconstrainedSearches null_searcher (target_sp); completer.DoCompletion (&null_searcher); } else @@ -375,7 +375,7 @@ CommandCompletions::Modules if (searcher == NULL) { lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); - SearchFilter null_searcher (target_sp); + SearchFilterForUnconstrainedSearches null_searcher (target_sp); completer.DoCompletion (&null_searcher); } else @@ -406,7 +406,7 @@ CommandCompletions::Symbols if (searcher == NULL) { lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); - SearchFilter null_searcher (target_sp); + SearchFilterForUnconstrainedSearches null_searcher (target_sp); completer.DoCompletion (&null_searcher); } else diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp index 13bf127..3d4b3af 100644 --- a/source/Commands/CommandObjectBreakpoint.cpp +++ b/source/Commands/CommandObjectBreakpoint.cpp @@ -20,6 +20,8 @@ #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamString.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -145,6 +147,10 @@ public: m_condition.assign(option_arg); break; + case 'D': + m_use_dummy = true; + break; + case 'E': { LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg); @@ -236,6 +242,11 @@ public: m_func_name_type_mask |= eFunctionNameTypeAuto; break; + case 'N': + if (BreakpointID::StringIsBreakpointName(option_arg, error)) + m_breakpoint_names.push_back (option_arg); + break; + case 'o': m_one_shot = true; break; @@ -324,6 +335,8 @@ public: m_language = eLanguageTypeUnknown; m_skip_prologue = eLazyBoolCalculate; m_one_shot = false; + m_use_dummy = false; + m_breakpoint_names.clear(); } const OptionDefinition* @@ -343,6 +356,7 @@ public: uint32_t m_line_num; uint32_t m_column; std::vector<std::string> m_func_names; + std::vector<std::string> m_breakpoint_names; uint32_t m_func_name_type_mask; std::string m_func_regexp; std::string m_source_text_regexp; @@ -359,16 +373,18 @@ public: lldb::LanguageType m_language; LazyBool m_skip_prologue; bool m_one_shot; + bool m_use_dummy; }; protected: virtual bool DoExecute (Args& command, - CommandReturnObject &result) + CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); - if (target == NULL) + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + + if (target == nullptr) { result.AppendError ("Invalid target. Must set target before setting breakpoints (see 'target create' command)."); result.SetStatus (eReturnStatusFailed); @@ -551,6 +567,13 @@ protected: if (!m_options.m_condition.empty()) bp->GetOptions()->SetCondition(m_options.m_condition.c_str()); + + if (!m_options.m_breakpoint_names.empty()) + { + Error error; // We don't need to check the error here, since the option parser checked it... + for (auto name : m_options.m_breakpoint_names) + bp->AddName(name.c_str(), error); + } bp->SetOneShot (m_options.m_one_shot); } @@ -560,10 +583,17 @@ protected: Stream &output_stream = result.GetOutputStream(); const bool show_locations = false; bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, show_locations); - // Don't print out this warning for exception breakpoints. They can get set before the target - // is set, but we won't know how to actually set the breakpoint till we run. - if (bp->GetNumLocations() == 0 && break_type != eSetTypeException) - output_stream.Printf ("WARNING: Unable to resolve breakpoint to any actual locations.\n"); + if (target == m_interpreter.GetDebugger().GetDummyTarget()) + output_stream.Printf ("Breakpoint set in dummy target, will get copied into future targets.\n"); + else + { + // Don't print out this warning for exception breakpoints. They can get set before the target + // is set, but we won't know how to actually set the breakpoint till we run. + if (bp->GetNumLocations() == 0 && break_type != eSetTypeException) + { + output_stream.Printf ("WARNING: Unable to resolve breakpoint to any actual locations.\n"); + } + } result.SetStatus (eReturnStatusSuccessFinishResult); } else if (!bp) @@ -709,6 +739,12 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." }, + { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + + { LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, + "Adds this to the list of names for this breakopint."}, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -766,7 +802,8 @@ public: m_name_passed (false), m_queue_passed (false), m_condition_passed (false), - m_one_shot_passed (false) + m_one_shot_passed (false), + m_use_dummy (false) { } @@ -792,6 +829,9 @@ public: m_enable_passed = true; m_enable_value = false; break; + case 'D': + m_use_dummy = true; + break; case 'e': m_enable_passed = true; m_enable_value = true; @@ -888,6 +928,7 @@ public: m_name_passed = false; m_condition_passed = false; m_one_shot_passed = false; + m_use_dummy = false; } const OptionDefinition* @@ -918,6 +959,7 @@ public: bool m_queue_passed; bool m_condition_passed; bool m_one_shot_passed; + bool m_use_dummy; }; @@ -925,7 +967,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); if (target == NULL) { result.AppendError ("Invalid target. No existing target or breakpoints."); @@ -938,7 +980,7 @@ protected: BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1024,6 +1066,8 @@ CommandObjectBreakpointModify::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."}, { LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable the breakpoint."}, { LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Disable the breakpoint."}, +{ LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + { 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1055,7 +1099,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (target == NULL) { result.AppendError ("Invalid target. No existing target or breakpoints."); @@ -1088,7 +1132,7 @@ protected: { // Particular breakpoint selected; enable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1175,7 +1219,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (target == NULL) { result.AppendError ("Invalid target. No existing target or breakpoints."); @@ -1208,7 +1252,7 @@ protected: // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1293,7 +1337,8 @@ public: CommandOptions (CommandInterpreter &interpreter) : Options (interpreter), - m_level (lldb::eDescriptionLevelBrief) // Breakpoint List defaults to brief descriptions + m_level (lldb::eDescriptionLevelBrief), + m_use_dummy(false) { } @@ -1311,6 +1356,9 @@ public: case 'b': m_level = lldb::eDescriptionLevelBrief; break; + case 'D': + m_use_dummy = true; + break; case 'f': m_level = lldb::eDescriptionLevelFull; break; @@ -1333,6 +1381,7 @@ public: { m_level = lldb::eDescriptionLevelFull; m_internal = false; + m_use_dummy = false; } const OptionDefinition * @@ -1350,13 +1399,15 @@ public: lldb::DescriptionLevel m_level; bool m_internal; + bool m_use_dummy; }; protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + if (target == NULL) { result.AppendError ("Invalid target. No current target or breakpoints."); @@ -1394,7 +1445,7 @@ protected: { // Particular breakpoints selected; show info about that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1438,6 +1489,9 @@ CommandObjectBreakpointList::CommandOptions::g_option_table[] = { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)." }, + { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1540,7 +1594,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (target == NULL) { result.AppendError ("Invalid target. No existing target or breakpoints."); @@ -1656,7 +1710,8 @@ public: CommandObjectParsed (interpreter, "breakpoint delete", "Delete the specified breakpoint(s). If no breakpoints are specified, delete them all.", - NULL) + NULL), + m_options (interpreter) { CommandArgumentEntry arg; CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange); @@ -1667,11 +1722,78 @@ public: virtual ~CommandObjectBreakpointDelete () {} + virtual Options * + GetOptions () + { + return &m_options; + } + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter), + m_use_dummy (false), + m_force (false) + { + } + + 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 'f': + m_force = true; + break; + + case 'D': + m_use_dummy = true; + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; + } + + void + OptionParsingStarting () + { + m_use_dummy = false; + m_force = 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_use_dummy; + bool m_force; + }; + protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + if (target == NULL) { result.AppendError ("Invalid target. No existing target or breakpoints."); @@ -1695,7 +1817,7 @@ protected: if (command.GetArgumentCount() == 0) { - if (!m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true)) + if (!m_options.m_force && !m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true)) { result.AppendMessage("Operation cancelled..."); } @@ -1710,7 +1832,7 @@ protected: { // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1748,7 +1870,416 @@ protected: } return result.Succeeded(); } +private: + CommandOptions m_options; +}; + +OptionDefinition +CommandObjectBreakpointDelete::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "force", 'f', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Delete all breakpoints without querying for confirmation."}, + + { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Delete Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointName +//------------------------------------------------------------------------- + +static OptionDefinition +g_breakpoint_name_options[] = +{ + { LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."}, + { LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointID, "Specify a breakpoint id to use."}, + { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, }; +class BreakpointNameOptionGroup : public OptionGroup +{ +public: + BreakpointNameOptionGroup() : + OptionGroup(), + m_breakpoint(LLDB_INVALID_BREAK_ID), + m_use_dummy (false) + { + + } + + virtual + ~BreakpointNameOptionGroup () + { + } + + virtual uint32_t + GetNumDefinitions () + { + return sizeof (g_breakpoint_name_options) / sizeof (OptionDefinition); + } + + virtual const OptionDefinition* + GetDefinitions () + { + return g_breakpoint_name_options; + } + + virtual Error + SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_value) + { + Error error; + const int short_option = g_breakpoint_name_options[option_idx].short_option; + + switch (short_option) + { + case 'N': + if (BreakpointID::StringIsBreakpointName(option_value, error) && error.Success()) + m_name.SetValueFromCString(option_value); + break; + + case 'B': + if (m_breakpoint.SetValueFromCString(option_value).Fail()) + error.SetErrorStringWithFormat ("unrecognized value \"%s\" for breakpoint", option_value); + break; + case 'D': + if (m_use_dummy.SetValueFromCString(option_value).Fail()) + error.SetErrorStringWithFormat ("unrecognized value \"%s\" for use-dummy", option_value); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); + break; + } + return error; + } + + virtual void + OptionParsingStarting (CommandInterpreter &interpreter) + { + m_name.Clear(); + m_breakpoint.Clear(); + m_use_dummy.Clear(); + m_use_dummy.SetDefaultValue(false); + } + + OptionValueString m_name; + OptionValueUInt64 m_breakpoint; + OptionValueBoolean m_use_dummy; +}; + + +class CommandObjectBreakpointNameAdd : public CommandObjectParsed +{ +public: + CommandObjectBreakpointNameAdd (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "add", + "Add a name to the breakpoints provided.", + "breakpoint name add <command-options> <breakpoint-id-list>"), + m_name_options(), + m_option_group(interpreter) + { + // Create the first variant for the first (and only) argument for this command. + CommandArgumentEntry arg1; + CommandArgumentData id_arg; + id_arg.arg_type = eArgTypeBreakpointID; + id_arg.arg_repetition = eArgRepeatOptional; + arg1.push_back(id_arg); + m_arguments.push_back (arg1); + + m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectBreakpointNameAdd () {} + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + if (!m_name_options.m_name.OptionWasSet()) + { + result.SetError("No name option provided."); + return false; + } + + Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); + + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or breakpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Mutex::Locker locker; + target->GetBreakpointList().GetListMutex(locker); + + const BreakpointList &breakpoints = target->GetBreakpointList(); + + size_t num_breakpoints = breakpoints.GetSize(); + if (num_breakpoints == 0) + { + result.SetError("No breakpoints, cannot add names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // Particular breakpoint selected; disable that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + if (valid_bp_ids.GetSize() == 0) + { + result.SetError("No breakpoints specified, cannot add names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + size_t num_valid_ids = valid_bp_ids.GetSize(); + for (size_t index = 0; index < num_valid_ids; index++) + { + lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); + BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); + Error error; // We don't need to check the error here, since the option parser checked it... + bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error); + } + } + + return true; + } + +private: + BreakpointNameOptionGroup m_name_options; + OptionGroupOptions m_option_group; +}; + + + +class CommandObjectBreakpointNameDelete : public CommandObjectParsed +{ +public: + CommandObjectBreakpointNameDelete (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "delete", + "Delete a name from the breakpoints provided.", + "breakpoint name delete <command-options> <breakpoint-id-list>"), + m_name_options(), + m_option_group(interpreter) + { + // Create the first variant for the first (and only) argument for this command. + CommandArgumentEntry arg1; + CommandArgumentData id_arg; + id_arg.arg_type = eArgTypeBreakpointID; + id_arg.arg_repetition = eArgRepeatOptional; + arg1.push_back(id_arg); + m_arguments.push_back (arg1); + + m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectBreakpointNameDelete () {} + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + if (!m_name_options.m_name.OptionWasSet()) + { + result.SetError("No name option provided."); + return false; + } + + Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); + + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or breakpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Mutex::Locker locker; + target->GetBreakpointList().GetListMutex(locker); + + const BreakpointList &breakpoints = target->GetBreakpointList(); + + size_t num_breakpoints = breakpoints.GetSize(); + if (num_breakpoints == 0) + { + result.SetError("No breakpoints, cannot delete names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // Particular breakpoint selected; disable that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + if (valid_bp_ids.GetSize() == 0) + { + result.SetError("No breakpoints specified, cannot delete names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + size_t num_valid_ids = valid_bp_ids.GetSize(); + for (size_t index = 0; index < num_valid_ids; index++) + { + lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); + BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); + bp_sp->RemoveName(m_name_options.m_name.GetCurrentValue()); + } + } + + return true; + } + +private: + BreakpointNameOptionGroup m_name_options; + OptionGroupOptions m_option_group; +}; + +class CommandObjectBreakpointNameList : public CommandObjectParsed +{ +public: + CommandObjectBreakpointNameList (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "list", + "List either the names for a breakpoint or the breakpoints for a given name.", + "breakpoint name list <command-options>"), + m_name_options(), + m_option_group(interpreter) + { + m_option_group.Append (&m_name_options); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectBreakpointNameList () {} + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); + + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or breakpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (m_name_options.m_name.OptionWasSet()) + { + const char *name = m_name_options.m_name.GetCurrentValue(); + Mutex::Locker locker; + target->GetBreakpointList().GetListMutex(locker); + + BreakpointList &breakpoints = target->GetBreakpointList(); + for (BreakpointSP bp_sp : breakpoints.Breakpoints()) + { + if (bp_sp->MatchesName(name)) + { + StreamString s; + bp_sp->GetDescription(&s, eDescriptionLevelBrief); + s.EOL(); + result.AppendMessage(s.GetData()); + } + } + + } + else if (m_name_options.m_breakpoint.OptionWasSet()) + { + BreakpointSP bp_sp = target->GetBreakpointList().FindBreakpointByID(m_name_options.m_breakpoint.GetCurrentValue()); + if (bp_sp) + { + std::vector<std::string> names; + bp_sp->GetNames (names); + result.AppendMessage ("Names:"); + for (auto name : names) + result.AppendMessageWithFormat (" %s\n", name.c_str()); + } + else + { + result.AppendErrorWithFormat ("Could not find breakpoint %" PRId64 ".\n", + m_name_options.m_breakpoint.GetCurrentValue()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + result.SetError ("Must specify -N or -B option to list."); + result.SetStatus (eReturnStatusFailed); + return false; + } + return true; + } + +private: + BreakpointNameOptionGroup m_name_options; + OptionGroupOptions m_option_group; +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBreakpoint +//------------------------------------------------------------------------- +class CommandObjectBreakpointName : public CommandObjectMultiword +{ +public: + CommandObjectBreakpointName (CommandInterpreter &interpreter) : + CommandObjectMultiword(interpreter, + "name", + "A set of commands to manage name tags for breakpoints", + "breakpoint name <command> [<command-options>]") + { + CommandObjectSP add_command_object (new CommandObjectBreakpointNameAdd (interpreter)); + CommandObjectSP delete_command_object (new CommandObjectBreakpointNameDelete (interpreter)); + CommandObjectSP list_command_object (new CommandObjectBreakpointNameList (interpreter)); + + LoadSubCommand ("add", add_command_object); + LoadSubCommand ("delete", delete_command_object); + LoadSubCommand ("list", list_command_object); + + } + + virtual + ~CommandObjectBreakpointName () + { + } + +}; + //------------------------------------------------------------------------- // CommandObjectMultiwordBreakpoint @@ -1769,6 +2300,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter)); CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter)); CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter)); + CommandObjectSP name_command_object (new CommandObjectBreakpointName(interpreter)); list_command_object->SetCommandName ("breakpoint list"); enable_command_object->SetCommandName("breakpoint enable"); @@ -1778,6 +2310,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter set_command_object->SetCommandName("breakpoint set"); command_command_object->SetCommandName ("breakpoint command"); modify_command_object->SetCommandName ("breakpoint modify"); + name_command_object->SetCommandName ("breakpoint name"); LoadSubCommand ("list", list_command_object); LoadSubCommand ("enable", enable_command_object); @@ -1787,6 +2320,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter LoadSubCommand ("set", set_command_object); LoadSubCommand ("command", command_command_object); LoadSubCommand ("modify", modify_command_object); + LoadSubCommand ("name", name_command_object); } CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint () @@ -1794,13 +2328,17 @@ CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint () } void -CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, - BreakpointIDList *valid_ids) +CommandObjectMultiwordBreakpoint::VerifyIDs (Args &args, + Target *target, + bool allow_locations, + CommandReturnObject &result, + BreakpointIDList *valid_ids) { // args can be strings representing 1). integers (for breakpoint ids) // 2). the full breakpoint & location canonical representation // 3). the word "to" or a hyphen, representing a range (in which case there // had *better* be an entry both before & after of one of the first two types. + // 4). A breakpoint name // If args is empty, we will use the last created breakpoint (if there is one.) Args temp_args; @@ -1824,7 +2362,7 @@ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *targe // the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for // all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS. - BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args); + BreakpointIDList::FindAndReplaceIDRanges (args, target, allow_locations, result, temp_args); // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList: diff --git a/source/Commands/CommandObjectBreakpoint.h b/source/Commands/CommandObjectBreakpoint.h index 2d674b2..3fdd2a5 100644 --- a/source/Commands/CommandObjectBreakpoint.h +++ b/source/Commands/CommandObjectBreakpoint.h @@ -38,8 +38,20 @@ public: ~CommandObjectMultiwordBreakpoint (); static void - VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids); + VerifyBreakpointOrLocationIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids) + { + VerifyIDs (args, target, true, result, valid_ids); + } + static void + VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids) + { + VerifyIDs (args, target, false, result, valid_ids); + } + +private: + static void + VerifyIDs (Args &args, Target *target, bool allow_locations, CommandReturnObject &result, BreakpointIDList *valid_ids); }; } // namespace lldb_private diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp index fdb87d1..8f8404b 100644 --- a/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/source/Commands/CommandObjectBreakpointCommand.cpp @@ -307,17 +307,16 @@ one command per line.\n" ); result.SetImmediateOutputStream (output_stream); result.SetImmediateErrorStream (error_stream); - bool stop_on_continue = true; - bool echo_commands = false; - bool print_results = true; - - debugger.GetCommandInterpreter().HandleCommands (commands, + CommandInterpreterRunOptions options; + options.SetStopOnContinue(true); + options.SetStopOnError (data->stop_on_error); + options.SetEchoCommands (true); + options.SetPrintResults (true); + options.SetAddToHistory (false); + + debugger.GetCommandInterpreter().HandleCommands (commands, &exe_ctx, - stop_on_continue, - data->stop_on_error, - echo_commands, - print_results, - eLazyBoolNo, + options, result); result.GetImmediateOutputStream()->Flush(); result.GetImmediateErrorStream()->Flush(); @@ -390,6 +389,10 @@ one command per line.\n" ); } break; + case 'D': + m_use_dummy = true; + break; + default: break; } @@ -406,6 +409,7 @@ one command per line.\n" ); m_stop_on_error = true; m_one_liner.clear(); m_function_name.clear(); + m_use_dummy = false; } const OptionDefinition* @@ -429,13 +433,14 @@ one command per line.\n" ); std::string m_one_liner; bool m_stop_on_error; std::string m_function_name; + bool m_use_dummy; }; protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); if (target == NULL) { @@ -462,7 +467,7 @@ protected: } BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); m_bp_options_vec.clear(); @@ -581,6 +586,9 @@ CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."}, + { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -595,7 +603,8 @@ public: CommandObjectParsed (interpreter, "delete", "Delete the set of commands from a breakpoint.", - NULL) + NULL), + m_options (interpreter) { CommandArgumentEntry arg; CommandArgumentData bp_id_arg; @@ -615,11 +624,70 @@ public: virtual ~CommandObjectBreakpointCommandDelete () {} + virtual Options * + GetOptions () + { + return &m_options; + } + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter), + m_use_dummy (false) + { + } + + 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 'D': + m_use_dummy = true; + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; + } + + void + OptionParsingStarting () + { + m_use_dummy = 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_use_dummy; + }; + protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); if (target == NULL) { @@ -646,7 +714,7 @@ protected: } BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -680,8 +748,20 @@ protected: } return result.Succeeded(); } +private: + CommandOptions m_options; +}; + +OptionDefinition +CommandObjectBreakpointCommandDelete::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Delete commands from Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; + //------------------------------------------------------------------------- // CommandObjectBreakpointCommandList //------------------------------------------------------------------------- @@ -744,7 +824,7 @@ protected: } BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp index 7d9bb7d..f98eac0 100644 --- a/source/Commands/CommandObjectCommands.cpp +++ b/source/Commands/CommandObjectCommands.cpp @@ -366,7 +366,7 @@ protected: // Instance variables to hold the values for command options. OptionValueBoolean m_stop_on_error; - OptionValueBoolean m_silent_run; + OptionValueBoolean m_silent_run; OptionValueBoolean m_stop_on_continue; }; @@ -387,14 +387,15 @@ protected: m_options.m_stop_on_continue.OptionWasSet()) { // Use user set settings - LazyBool print_command = m_options.m_silent_run.GetCurrentValue() ? eLazyBoolNo : eLazyBoolYes; + CommandInterpreterRunOptions options; + options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue()); + options.SetStopOnError (m_options.m_stop_on_error.GetCurrentValue()); + options.SetEchoCommands (!m_options.m_silent_run.GetCurrentValue()); + options.SetPrintResults (!m_options.m_silent_run.GetCurrentValue()); + m_interpreter.HandleCommandsFromFile (cmd_file, exe_ctx, - m_options.m_stop_on_continue.GetCurrentValue() ? eLazyBoolYes : eLazyBoolNo, // Stop on continue - m_options.m_stop_on_error.GetCurrentValue() ? eLazyBoolYes : eLazyBoolNo, // Stop on error - print_command, // Echo command - print_command, // Print command output - eLazyBoolCalculate, // Add to history + options, result); } @@ -402,13 +403,10 @@ protected: { // No options were set, inherit any settings from nested "command source" commands, // or set to sane default settings... + CommandInterpreterRunOptions options; m_interpreter.HandleCommandsFromFile (cmd_file, exe_ctx, - eLazyBoolCalculate, // Stop on continue - eLazyBoolCalculate, // Stop on error - eLazyBoolCalculate, // Echo command - eLazyBoolCalculate, // Print command output - eLazyBoolCalculate, // Add to history + options, result); } @@ -830,8 +828,16 @@ protected: { if (m_interpreter.CommandExists (command_name)) { - result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", - command_name); + if (cmd_obj->IsRemovable()) + { + result.AppendErrorWithFormat ("'%s' is not an alias, it is a debugger command which can be removed using the 'command delete' command.\n", + command_name); + } + else + { + result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", + command_name); + } result.SetStatus (eReturnStatusFailed); } else @@ -868,6 +874,77 @@ protected: } }; +#pragma mark CommandObjectCommandsDelete +//------------------------------------------------------------------------- +// CommandObjectCommandsDelete +//------------------------------------------------------------------------- + +class CommandObjectCommandsDelete : public CommandObjectParsed +{ +public: + CommandObjectCommandsDelete (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "command delete", + "Allow the user to delete user-defined regular expression, python or multi-word commands.", + NULL) + { + CommandArgumentEntry arg; + CommandArgumentData alias_arg; + + // Define the first (and only) variant of this arg. + alias_arg.arg_type = eArgTypeCommandName; + alias_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (alias_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + ~CommandObjectCommandsDelete() + { + } + +protected: + bool + DoExecute (Args& args, CommandReturnObject &result) + { + CommandObject::CommandMap::iterator pos; + + if (args.GetArgumentCount() != 0) + { + const char *command_name = args.GetArgumentAtIndex(0); + if (m_interpreter.CommandExists (command_name)) + { + if (m_interpreter.RemoveCommand (command_name)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("must call '%s' with one or more valid user defined regular expression, python or multi-word command names", GetCommandName ()); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); + } +}; + //------------------------------------------------------------------------- // CommandObjectCommandsAddRegex //------------------------------------------------------------------------- @@ -875,7 +952,7 @@ protected: class CommandObjectCommandsAddRegex : public CommandObjectParsed, - public IOHandlerDelegate + public IOHandlerDelegateMultiline { public: CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) : @@ -883,7 +960,7 @@ public: "command regex", "Allow the user to create a regular expression command.", "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), - IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), + IOHandlerDelegateMultiline ("", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { SetHelpLong( @@ -920,8 +997,8 @@ public: protected: - virtual void - IOHandlerActivated (IOHandler &io_handler) + void + IOHandlerActivated (IOHandler &io_handler) override { StreamFileSP output_sp(io_handler.GetOutputStreamFile()); if (output_sp) @@ -931,8 +1008,8 @@ protected: } } - virtual void - IOHandlerInputComplete (IOHandler &io_handler, std::string &data) + void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override { io_handler.SetIsDone(true); if (m_regex_cmd_ap.get()) @@ -944,7 +1021,6 @@ protected: bool check_only = false; for (size_t i=0; i<num_lines; ++i) { - printf ("regex[%zu] = %s\n", i, lines[i].c_str()); llvm::StringRef bytes_strref (lines[i]); Error error = AppendRegexSubstitution (bytes_strref, check_only); if (error.Fail()) @@ -964,54 +1040,9 @@ protected: } } } - - virtual LineStatus - IOHandlerLinesUpdated (IOHandler &io_handler, - StringList &lines, - uint32_t line_idx, - Error &error) - { - if (line_idx == UINT32_MAX) - { - // Return true to indicate we are done getting lines (this - // is a "fake" line - the real terminating blank line was - // removed during a previous call with the code below) - error.Clear(); - return LineStatus::Done; - } - else - { - const size_t num_lines = lines.GetSize(); - if (line_idx + 1 == num_lines) - { - // The last line was edited, if this line is empty, then we are done - // getting our multiple lines. - if (lines[line_idx].empty()) - { - // Remove the last empty line from "lines" so it doesn't appear - // in our final expression and return true to indicate we are done - // getting lines - lines.PopBack(); - return LineStatus::Done; - } - } - // Check the current line to make sure it is formatted correctly - bool check_only = true; - llvm::StringRef regex_sed(lines[line_idx]); - error = AppendRegexSubstitution (regex_sed, check_only); - if (error.Fail()) - { - return LineStatus::Error; - } - else - { - return LineStatus::Success; - } - } - } bool - DoExecute (Args& command, CommandReturnObject &result) + DoExecute (Args& command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) @@ -1027,16 +1058,22 @@ protected: name, m_options.GetHelp (), m_options.GetSyntax (), - 10)); + 10, + 0, + true)); if (argc == 1) { Debugger &debugger = m_interpreter.GetDebugger(); + bool color_prompt = debugger.GetUseColor(); const bool multiple_lines = true; // Get multiple lines IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + IOHandler::Type::Other, "lldb-regex", // Name of input reader for history - "\033[K> ", // Prompt and clear line + "> ", // Prompt + NULL, // Continuation prompt multiple_lines, + color_prompt, 0, // Don't show line numbers *this)); @@ -1110,21 +1147,25 @@ protected: if (second_separator_char_pos == std::string::npos) { - error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'", + error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s' in '%.*s'", separator_char, (int)(regex_sed.size() - first_separator_char_pos - 1), - regex_sed.data() + (first_separator_char_pos + 1)); - return error; + regex_sed.data() + (first_separator_char_pos + 1), + (int)regex_sed.size(), + regex_sed.data()); + return error; } const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1); if (third_separator_char_pos == std::string::npos) { - error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'", + error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s' in '%.*s'", separator_char, (int)(regex_sed.size() - second_separator_char_pos - 1), - regex_sed.data() + (second_separator_char_pos + 1)); + regex_sed.data() + (second_separator_char_pos + 1), + (int)regex_sed.size(), + regex_sed.data()); return error; } @@ -1262,8 +1303,8 @@ private: std::string m_syntax; }; - virtual Options * - GetOptions () + Options * + GetOptions () override { return &m_options; } @@ -1292,15 +1333,24 @@ public: CommandObjectPythonFunction (CommandInterpreter &interpreter, std::string name, std::string funct, + std::string help, ScriptedCommandSynchronicity synch) : CommandObjectRaw (interpreter, name.c_str(), - (std::string("Run Python function ") + funct).c_str(), + NULL, NULL), m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) { + if (!help.empty()) + SetHelp(help.c_str()); + else + { + StreamString stream; + stream.Printf("For more information run 'help %s'",name.c_str()); + SetHelp(stream.GetData()); + } } virtual @@ -1357,7 +1407,8 @@ protected: raw_command_line, m_synchro, result, - error) == false) + error, + m_exe_ctx) == false) { result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); @@ -1617,7 +1668,12 @@ protected: switch (short_option) { case 'f': - m_funct_name = std::string(option_arg); + if (option_arg) + m_funct_name.assign(option_arg); + break; + case 'h': + if (option_arg) + m_short_help.assign(option_arg); break; case 's': m_synchronicity = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); @@ -1635,7 +1691,8 @@ protected: void OptionParsingStarting () { - m_funct_name = ""; + m_funct_name.clear(); + m_short_help.clear(); m_synchronicity = eScriptedCommandSynchronicitySynchronous; } @@ -1652,6 +1709,7 @@ protected: // Instance variables to hold the values for command options. std::string m_funct_name; + std::string m_short_help; ScriptedCommandSynchronicity m_synchronicity; }; @@ -1695,6 +1753,7 @@ protected: CommandObjectSP command_obj_sp(new CommandObjectPythonFunction (m_interpreter, m_cmd_name, funct_name_str.c_str(), + m_short_help, m_synchronicity)); if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true)) @@ -1748,8 +1807,9 @@ protected: return false; } - // Store the command name and synchronicity in case we get multi-line input + // Store the options in case we get multi-line input m_cmd_name = command.GetArgumentAtIndex(0); + m_short_help.assign(m_options.m_short_help); m_synchronicity = m_options.m_synchronicity; if (m_options.m_funct_name.empty()) @@ -1764,6 +1824,7 @@ protected: CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, m_cmd_name, m_options.m_funct_name, + m_options.m_short_help, m_synchronicity)); if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { @@ -1782,6 +1843,7 @@ protected: CommandOptions m_options; std::string m_cmd_name; + std::string m_short_help; ScriptedCommandSynchronicity m_synchronicity; }; @@ -1797,6 +1859,7 @@ OptionDefinition CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."}, + { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeHelpText, "The help text to display for this command."}, { LLDB_OPT_SET_1, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1949,11 +2012,11 @@ public: "A set of commands for managing or customizing script commands.", "command script <subcommand> [<subcommand-options>]") { - LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter))); - LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter))); - LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter))); + LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter))); + LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter))); + LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter))); - LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter))); + LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter))); } ~CommandObjectMultiwordCommandsScript () @@ -1978,9 +2041,10 @@ CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpret LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); + LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsDelete (interpreter))); LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); - LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter))); - LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter))); + LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter))); + LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter))); } CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp index 079c62d..b4c559c 100644 --- a/source/Commands/CommandObjectExpression.cpp +++ b/source/Commands/CommandObjectExpression.cpp @@ -281,7 +281,7 @@ CommandObjectExpression::EvaluateExpression Target *target = exe_ctx.GetTargetPtr(); if (!target) - target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get(); + target = GetDummyTarget(); if (target) { @@ -425,11 +425,15 @@ CommandObjectExpression::GetMultilineExpression () m_expr_line_count = 0; Debugger &debugger = GetCommandInterpreter().GetDebugger(); + bool color_prompt = debugger.GetUseColor(); const bool multiple_lines = true; // Get multiple lines IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + IOHandler::Type::Expression, "lldb-expr", // Name of input reader for history NULL, // No prompt + NULL, // Continuation prompt multiple_lines, + color_prompt, 1, // Show line numbers starting at 1 *this)); diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp index bfbb296..6c06ec8 100644 --- a/source/Commands/CommandObjectMemory.cpp +++ b/source/Commands/CommandObjectMemory.cpp @@ -33,8 +33,10 @@ #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Symbol/TypeList.h" +#include "lldb/Target/MemoryHistory.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; @@ -612,7 +614,16 @@ protected: } size_t item_count = m_format_options.GetCountValue().GetCurrentValue(); - size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue(); + + // TODO For non-8-bit byte addressable architectures this needs to be + // revisited to fully support all lldb's range of formatting options. + // Furthermore code memory reads (for those architectures) will not + // be correctly formatted even w/o formatting options. + size_t item_byte_size = + target->GetArchitecture().GetDataByteSize() > 1 ? + target->GetArchitecture().GetDataByteSize() : + m_format_options.GetByteSizeValue().GetCurrentValue(); + const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue(); if (total_byte_size == 0) @@ -659,7 +670,7 @@ protected: total_byte_size = end_addr - addr; item_count = total_byte_size / item_byte_size; } - + uint32_t max_unforced_size = target->GetMaximumMemReadSize(); if (total_byte_size > max_unforced_size && !m_memory_options.m_force) @@ -856,7 +867,8 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); DataExtractor data (data_sp, target->GetArchitecture().GetByteOrder(), - target->GetArchitecture().GetAddressByteSize()); + target->GetArchitecture().GetAddressByteSize(), + target->GetArchitecture().GetDataByteSize()); Format format = m_format_options.GetFormat(); if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) ) @@ -890,7 +902,7 @@ protected: format, item_byte_size, item_count, - num_per_line, + num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0, @@ -1078,7 +1090,7 @@ protected: lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error); if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) { - result.AppendError("invalid low address"); + result.AppendError("invalid high address"); return false; } @@ -1667,6 +1679,96 @@ protected: OptionGroupWriteMemory m_memory_options; }; +//---------------------------------------------------------------------- +// Get malloc/free history of a memory address. +//---------------------------------------------------------------------- +class CommandObjectMemoryHistory : public CommandObjectParsed +{ +public: + + CommandObjectMemoryHistory (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "memory history", + "Prints out the recorded stack traces for allocation/deallocation of a memory address.", + NULL, + eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched) + { + CommandArgumentEntry arg1; + CommandArgumentData addr_arg; + + // Define the first (and only) variant of this arg. + addr_arg.arg_type = eArgTypeAddress; + addr_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg1.push_back (addr_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg1); + } + + virtual + ~CommandObjectMemoryHistory () + { + } + + virtual const char *GetRepeatCommand (Args ¤t_command_args, uint32_t index) + { + return m_cmd_name.c_str(); + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + + if (argc == 0 || argc > 1) + { + result.AppendErrorWithFormat ("%s takes an address expression", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Error error; + lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx, + command.GetArgumentAtIndex(0), + LLDB_INVALID_ADDRESS, + &error); + + if (addr == LLDB_INVALID_ADDRESS) + { + result.AppendError("invalid address expression"); + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Stream *output_stream = &result.GetOutputStream(); + + const ProcessSP &process_sp = m_exe_ctx.GetProcessSP(); + const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(process_sp); + + if (! memory_history.get()) + { + result.AppendError("no available memory history provider"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + HistoryThreads thread_list = memory_history->GetHistoryThreads(addr); + + for (auto thread : thread_list) { + thread->GetStatus(*output_stream, 0, UINT32_MAX, 0); + } + + result.SetStatus(eReturnStatusSuccessFinishResult); + + return true; + } + +}; + //------------------------------------------------------------------------- // CommandObjectMemory @@ -1681,6 +1783,7 @@ CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter))); LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); + LoadSubCommand ("history", CommandObjectSP (new CommandObjectMemoryHistory (interpreter))); } CommandObjectMemory::~CommandObjectMemory () diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp index 9998dbd..d176d52 100644 --- a/source/Commands/CommandObjectPlatform.cpp +++ b/source/Commands/CommandObjectPlatform.cpp @@ -302,7 +302,7 @@ protected: Stream &ostrm = result.GetOutputStream(); ostrm.Printf("Available platforms:\n"); - PlatformSP host_platform_sp (Platform::GetDefaultPlatform()); + PlatformSP host_platform_sp (Platform::GetHostPlatform()); ostrm.Printf ("%s: %s\n", host_platform_sp->GetPluginName().GetCString(), host_platform_sp->GetDescription()); @@ -1347,7 +1347,6 @@ protected: ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info, debugger, target, - debugger.GetListener(), error)); if (process_sp && process_sp->IsAlive()) { @@ -1933,7 +1932,7 @@ public: { Error err; ProcessSP remote_process_sp = - platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, m_interpreter.GetDebugger().GetListener(), err); + platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, err); if (err.Fail()) { result.AppendError(err.AsCString()); diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp index 6536c6e..ec7b478 100644 --- a/source/Commands/CommandObjectProcess.cpp +++ b/source/Commands/CommandObjectProcess.cpp @@ -258,8 +258,9 @@ protected: // Save the arguments for subsequent runs in the current target. target->SetRunArguments (launch_args); } - - Error error = target->Launch(debugger.GetListener(), m_options.launch_info); + + StreamString stream; + Error error = target->Launch(m_options.launch_info, &stream); if (error.Success()) { @@ -267,6 +268,9 @@ protected: ProcessSP process_sp (target->GetProcessSP()); if (process_sp) { + const char *data = stream.GetData(); + if (data && strlen(data) > 0) + result.AppendMessage(stream.GetData()); result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(), exe_module_sp->GetFileSpec().GetPath().c_str(), archname); result.SetStatus (eReturnStatusSuccessFinishResult); result.SetDidChangeProcessState (true); @@ -564,15 +568,18 @@ protected: if (error.Success()) { result.SetStatus (eReturnStatusSuccessContinuingNoResult); - StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get()); + StreamString stream; + StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get(), &stream); process->RestoreProcessEvents(); result.SetDidChangeProcessState (true); + if (stream.GetData()) + result.AppendMessage(stream.GetData()); + if (state == eStateStopped) { - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -791,7 +798,12 @@ protected: } } - Error error(process->Resume()); + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); if (error.Success()) { @@ -803,10 +815,11 @@ protected: result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID()); if (synchronous_execution) { - state = process->WaitForProcessToStop (NULL); + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp index 6b1b6aa..8fb03e6 100644 --- a/source/Commands/CommandObjectSource.cpp +++ b/source/Commands/CommandObjectSource.cpp @@ -421,7 +421,7 @@ protected: { const bool show_inlines = true; m_breakpoint_locations.Reset (start_file, 0, show_inlines); - SearchFilter target_search_filter (m_exe_ctx.GetTargetSP()); + SearchFilterForUnconstrainedSearches target_search_filter (m_exe_ctx.GetTargetSP()); target_search_filter.Search (m_breakpoint_locations); } @@ -682,19 +682,21 @@ protected: m_breakpoint_locations.Clear(); const bool show_inlines = true; m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); - SearchFilter target_search_filter (target->shared_from_this()); + SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this()); target_search_filter.Search (m_breakpoint_locations); } bool show_fullpaths = true; bool show_module = true; bool show_inlined_frames = true; + const bool show_function_arguments = true; sc.DumpStopContext(&result.GetOutputStream(), m_exe_ctx.GetBestExecutionContextScope(), sc.line_entry.range.GetBaseAddress(), show_fullpaths, show_module, - show_inlined_frames); + show_inlined_frames, + show_function_arguments); result.GetOutputStream().EOL(); if (m_options.num_lines == 0) @@ -741,7 +743,7 @@ protected: { const bool show_inlines = true; m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines); - SearchFilter target_search_filter (target->shared_from_this()); + SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this()); target_search_filter.Search (m_breakpoint_locations); } } @@ -844,7 +846,7 @@ protected: { const bool show_inlines = true; m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines); - SearchFilter target_search_filter (target->shared_from_this()); + SearchFilterForUnconstrainedSearches target_search_filter (target->shared_from_this()); target_search_filter.Search (m_breakpoint_locations); } else diff --git a/source/Commands/CommandObjectSyntax.cpp b/source/Commands/CommandObjectSyntax.cpp index d2021ea..5093c3b 100644 --- a/source/Commands/CommandObjectSyntax.cpp +++ b/source/Commands/CommandObjectSyntax.cpp @@ -69,12 +69,18 @@ CommandObjectSyntax::DoExecute (Args& command, CommandReturnObject &result) { std::string sub_command = command.GetArgumentAtIndex (i); if (!cmd_obj->IsMultiwordObject()) + { all_okay = false; + break; + } else { cmd_obj = cmd_obj->GetSubcommandObject(sub_command.c_str()); if (!cmd_obj) + { all_okay = false; + break; + } } } diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp index 024f7b5..0d9ffda 100644 --- a/source/Commands/CommandObjectTarget.cpp +++ b/source/Commands/CommandObjectTarget.cpp @@ -39,6 +39,7 @@ #include "lldb/Interpreter/OptionGroupPlatform.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionGroupUUID.h" +#include "lldb/Interpreter/OptionGroupString.h" #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/FuncUnwinders.h" @@ -2844,7 +2845,7 @@ public: "Set the load addresses for one or more sections in a target module.", "target modules load [--file <module> --uuid <uuid>] <sect-name> <address> [<sect-name> <address> ....]"), m_option_group (interpreter), - m_file_option (LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeFilename, "Fullpath or basename for module to load."), + m_file_option (LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeName, "Fullpath or basename for module to load.", ""), m_slide_option(LLDB_OPT_SET_1, false, "slide", 's', 0, eArgTypeOffset, "Set the load address for all sections to be the virtual address in the file plus the offset.", 0) { m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); @@ -2884,7 +2885,26 @@ protected: if (m_file_option.GetOptionValue().OptionWasSet()) { search_using_module_spec = true; - module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue(); + const char *arg_cstr = m_file_option.GetOptionValue().GetCurrentValue(); + const bool use_global_module_list = true; + ModuleList module_list; + const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, use_global_module_list); + if (num_matches == 1) + { + module_spec.GetFileSpec() = module_list.GetModuleAtIndex(0)->GetFileSpec(); + } + else if (num_matches > 1 ) + { + search_using_module_spec = false; + result.AppendErrorWithFormat ("more than 1 module matched by name '%s'\n", arg_cstr); + result.SetStatus (eReturnStatusFailed); + } + else + { + search_using_module_spec = false; + result.AppendErrorWithFormat ("no object file for module '%s'\n", arg_cstr); + result.SetStatus (eReturnStatusFailed); + } } if (m_uuid_option_group.GetOptionValue().OptionWasSet()) @@ -3070,7 +3090,7 @@ protected: OptionGroupOptions m_option_group; OptionGroupUUID m_uuid_option_group; - OptionGroupFile m_file_option; + OptionGroupString m_file_option; OptionGroupUInt64 m_slide_option; }; @@ -3724,45 +3744,85 @@ protected: if (func_unwinders_sp.get() == NULL) continue; - Address first_non_prologue_insn (func_unwinders_sp->GetFirstNonPrologueInsn(*target)); - if (first_non_prologue_insn.IsValid()) - { - result.GetOutputStream().Printf("First non-prologue instruction is at address 0x%" PRIx64 " or offset %" PRId64 " into the function.\n", first_non_prologue_insn.GetLoadAddress(target), first_non_prologue_insn.GetLoadAddress(target) - start_addr); - result.GetOutputStream().Printf ("\n"); - } + result.GetOutputStream().Printf("UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread.get(), -1); if (non_callsite_unwind_plan.get()) { - result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); - non_callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); - result.GetOutputStream().Printf ("\n"); + result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan is '%s'\n", non_callsite_unwind_plan->GetSourceName().AsCString()); } - - UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(-1); + UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(*target, -1); if (callsite_unwind_plan.get()) { - result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); - callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); - result.GetOutputStream().Printf ("\n"); + result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan is '%s'\n", callsite_unwind_plan->GetSourceName().AsCString()); + } + UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get()); + if (fast_unwind_plan.get()) + { + result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString()); } - UnwindPlanSP arch_default_unwind_plan = func_unwinders_sp->GetUnwindPlanArchitectureDefault(*thread.get()); - if (arch_default_unwind_plan.get()) + result.GetOutputStream().Printf("\n"); + + UnwindPlanSP assembly_sp = func_unwinders_sp->GetAssemblyUnwindPlan(*target, *thread.get(), 0); + if (assembly_sp) { - result.GetOutputStream().Printf("Architecture default UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); - arch_default_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); - result.GetOutputStream().Printf ("\n"); + result.GetOutputStream().Printf("Assembly language inspection UnwindPlan:\n"); + assembly_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); } + - UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get()); - if (fast_unwind_plan.get()) + UnwindPlanSP ehframe_sp = func_unwinders_sp->GetEHFrameUnwindPlan(*target, 0); + if (ehframe_sp) { - result.GetOutputStream().Printf("Fast UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); + result.GetOutputStream().Printf("eh_frame UnwindPlan:\n"); + ehframe_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); + } + + UnwindPlanSP ehframe_augmented_sp = func_unwinders_sp->GetEHFrameAugmentedUnwindPlan(*target, *thread.get(), 0); + if (ehframe_augmented_sp) + { + result.GetOutputStream().Printf("eh_frame augmented UnwindPlan:\n"); + ehframe_augmented_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); + } + + UnwindPlanSP compact_unwind_sp = func_unwinders_sp->GetCompactUnwindUnwindPlan(*target, 0); + if (compact_unwind_sp) + { + result.GetOutputStream().Printf("Compact unwind UnwindPlan:\n"); + compact_unwind_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); + } + + if (fast_unwind_plan) + { + result.GetOutputStream().Printf("Fast UnwindPlan:\n"); fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); - result.GetOutputStream().Printf ("\n"); + result.GetOutputStream().Printf("\n"); } + ABISP abi_sp = process->GetABI(); + if (abi_sp) + { + UnwindPlan arch_default(lldb::eRegisterKindGeneric); + if (abi_sp->CreateDefaultUnwindPlan (arch_default)) + { + result.GetOutputStream().Printf("Arch default UnwindPlan:\n"); + arch_default.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); + } + + UnwindPlan arch_entry(lldb::eRegisterKindGeneric); + if (abi_sp->CreateFunctionEntryUnwindPlan (arch_entry)) + { + result.GetOutputStream().Printf("Arch default at entry point UnwindPlan:\n"); + arch_entry.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); + } + } result.GetOutputStream().Printf ("\n"); } @@ -4999,7 +5059,7 @@ protected: { m_stop_hook_sp.reset(); - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (target) { Target::StopHookSP new_hook_sp = target->CreateStopHook(); @@ -5151,7 +5211,7 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (target) { // FIXME: see if we can use the breakpoint id style parser? @@ -5227,7 +5287,7 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (target) { // FIXME: see if we can use the breakpoint id style parser? @@ -5297,7 +5357,7 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + Target *target = GetSelectedOrDummyTarget(); if (!target) { result.AppendError ("invalid target\n"); diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp index e7a8652..bace4e5 100644 --- a/source/Commands/CommandObjectThread.cpp +++ b/source/Commands/CommandObjectThread.cpp @@ -46,7 +46,108 @@ using namespace lldb_private; // CommandObjectThreadBacktrace //------------------------------------------------------------------------- -class CommandObjectThreadBacktrace : public CommandObjectParsed +class CommandObjectIterateOverThreads : public CommandObjectParsed +{ +public: + CommandObjectIterateOverThreads (CommandInterpreter &interpreter, + const char *name, + const char *help, + const char *syntax, + uint32_t flags) : + CommandObjectParsed (interpreter, name, help, syntax, flags) + { + } + + virtual ~CommandObjectIterateOverThreads() {} + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + result.SetStatus (m_success_return); + + if (command.GetArgumentCount() == 0) + { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (!HandleOneThread (*thread, result)) + return false; + } + else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) + { + Process *process = m_exe_ctx.GetProcessPtr(); + uint32_t idx = 0; + for (ThreadSP thread_sp : process->Threads()) + { + if (idx != 0 && m_add_return) + result.AppendMessage(""); + + if (!HandleOneThread(*(thread_sp.get()), result)) + return false; + ++idx; + } + } + else + { + const size_t num_args = command.GetArgumentCount(); + Process *process = m_exe_ctx.GetProcessPtr(); + Mutex::Locker locker (process->GetThreadList().GetMutex()); + std::vector<ThreadSP> thread_sps; + + for (size_t i = 0; i < num_args; i++) + { + bool success; + + uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); + if (!success) + { + result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); + + if (!thread_sps[i]) + { + result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + } + + for (uint32_t i = 0; i < num_args; i++) + { + if (!HandleOneThread (*(thread_sps[i].get()), result)) + return false; + + if (i < num_args - 1 && m_add_return) + result.AppendMessage(""); + } + } + return result.Succeeded(); + } + +protected: + + // Override this to do whatever you need to do for one thread. + // + // If you return false, the iteration will stop, otherwise it will proceed. + // The result is set to m_success_return (defaults to eReturnStatusSuccessFinishResult) before the iteration, + // so you only need to set the return status in HandleOneThread if you want to indicate an error. + // If m_add_return is true, a blank line will be inserted between each of the listings (except the last one.) + + virtual bool + HandleOneThread (Thread &thread, CommandReturnObject &result) = 0; + + ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; + bool m_add_return = true; + +}; + +//------------------------------------------------------------------------- +// CommandObjectThreadBacktrace +//------------------------------------------------------------------------- + +class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { public: @@ -134,7 +235,7 @@ public: }; CommandObjectThreadBacktrace (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, + CommandObjectIterateOverThreads (interpreter, "thread backtrace", "Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.", NULL, @@ -145,18 +246,6 @@ public: eFlagProcessMustBePaused ), m_options(interpreter) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - // Define the first (and only) variant of this arg. - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); } ~CommandObjectThreadBacktrace() @@ -197,106 +286,28 @@ protected: } virtual bool - DoExecute (Args& command, CommandReturnObject &result) - { - result.SetStatus (eReturnStatusSuccessFinishResult); + HandleOneThread (Thread &thread, CommandReturnObject &result) + { Stream &strm = result.GetOutputStream(); // Don't show source context when doing backtraces. const uint32_t num_frames_with_source = 0; - if (command.GetArgumentCount() == 0) - { - Thread *thread = m_exe_ctx.GetThreadPtr(); - // Thread::GetStatus() returns the number of frames shown. - if (thread->GetStatus (strm, + + if (!thread.GetStatus (strm, m_options.m_start, m_options.m_count, num_frames_with_source)) - { - result.SetStatus (eReturnStatusSuccessFinishResult); - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread, result); - } - } - } - else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) { - Process *process = m_exe_ctx.GetProcessPtr(); - uint32_t idx = 0; - for (ThreadSP thread_sp : process->Threads()) - { - if (idx != 0) - result.AppendMessage(""); - - if (!thread_sp->GetStatus (strm, - m_options.m_start, - m_options.m_count, - num_frames_with_source)) - { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", idx); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread_sp.get(), result); - } - - ++idx; - } + result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", thread.GetIndexID()); + result.SetStatus (eReturnStatusFailed); + return false; } - else + if (m_options.m_extended_backtrace) { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - std::vector<ThreadSP> thread_sps; - - for (size_t i = 0; i < num_args; i++) - { - bool success; - - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); - if (!success) - { - result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); - - if (!thread_sps[i]) - { - result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - } - - for (uint32_t i = 0; i < num_args; i++) - { - if (!thread_sps[i]->GetStatus (strm, - m_options.m_start, - m_options.m_count, - num_frames_with_source)) - { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread_sps[i].get(), result); - } - - if (i < num_args - 1) - result.AppendMessage(""); - } + DoExtendedBacktrace (&thread, result); } - return result.Succeeded(); + + return true; } CommandOptions m_options; @@ -379,6 +390,12 @@ public: break; } break; + case 'C': + { + m_class_name.clear(); + m_class_name.assign(option_arg); + } + break; case 'm': { OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; @@ -416,6 +433,7 @@ public: m_run_mode = eOnlyDuringStepping; m_avoid_regexp.clear(); m_step_in_target.clear(); + m_class_name.clear(); m_step_count = 1; } @@ -435,7 +453,8 @@ public: RunMode m_run_mode; std::string m_avoid_regexp; std::string m_step_in_target; - int32_t m_step_count; + std::string m_class_name; + uint32_t m_step_count; }; CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter, @@ -520,6 +539,22 @@ protected: } } + if (m_step_type == eStepTypeScripted) + { + if (m_options.m_class_name.empty()) + { + result.AppendErrorWithFormat ("empty class name for scripted step."); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists(m_options.m_class_name.c_str())) + { + result.AppendErrorWithFormat ("class for scripted step: \"%s\" does not exist.", m_options.m_class_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + const bool abort_other_plans = false; const lldb::RunMode stop_other_threads = m_options.m_run_mode; @@ -530,7 +565,7 @@ protected: bool_stop_other_threads = false; else if (m_options.m_run_mode == eOnlyDuringStepping) { - if (m_step_type == eStepTypeOut) + if (m_step_type == eStepTypeOut || m_step_type == eStepTypeScripted) bool_stop_other_threads = false; else bool_stop_other_threads = true; @@ -599,6 +634,12 @@ protected: thread->GetSelectedFrameIndex(), m_options.m_step_out_avoid_no_debug); } + else if (m_step_type == eStepTypeScripted) + { + new_plan_sp = thread->QueueThreadPlanForStepScripted (abort_other_plans, + m_options.m_class_name.c_str(), + bool_stop_other_threads); + } else { result.AppendError ("step type is not supported"); @@ -622,8 +663,15 @@ protected: } } + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); + + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); // There is a race condition where this thread will return up the call stack to the main command handler // and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has @@ -632,17 +680,12 @@ protected: if (synchronous_execution) { - StateType state = process->WaitForProcessToStop (NULL); - - //EventSP event_sp; - //StateType state = process->WaitForStateChangedEvents (NULL, event_sp); - //while (! StateIsStoppedState (state)) - // { - // state = process->WaitForStateChangedEvents (NULL, event_sp); - // } + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -686,10 +729,11 @@ CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."}, { LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."}, -{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."}, -{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."}, -{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."}, -{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."}, +{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."}, +{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."}, +{ LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."}, +{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."}, +{ LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -860,17 +904,25 @@ public: } } + + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); + // We should not be holding the thread list lock when we do this. - Error error (process->Resume()); if (error.Success()) { result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID()); if (synchronous_execution) { - state = process->WaitForProcessToStop (NULL); + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -1191,17 +1243,27 @@ protected: } + + process->GetThreadList().SetSelectedThreadByID (m_options.m_thread_idx); - Error error (process->Resume ()); + + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); + if (error.Success()) { result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID()); if (synchronous_execution) { - StateType state = process->WaitForProcessToStop (NULL); + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -1358,32 +1420,22 @@ protected: // CommandObjectThreadInfo //------------------------------------------------------------------------- -class CommandObjectThreadInfo : public CommandObjectParsed +class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { public: CommandObjectThreadInfo (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "thread info", - "Show an extended summary of information about thread(s) in a process.", - "thread info", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused), + CommandObjectIterateOverThreads (interpreter, + "thread info", + "Show an extended summary of information about thread(s) in a process.", + "thread info", + eFlagRequiresProcess | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused), m_options (interpreter) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); + m_add_return = false; } class CommandOptions : public Options @@ -1399,7 +1451,8 @@ public: void OptionParsingStarting () { - m_json = false; + m_json_thread = false; + m_json_stopinfo = false; } virtual @@ -1416,10 +1469,14 @@ public: switch (short_option) { case 'j': - m_json = true; + m_json_thread = true; + break; + + case 's': + m_json_stopinfo = true; break; - default: + default: return Error("invalid short option character '%c'", short_option); } @@ -1432,7 +1489,8 @@ public: return g_option_table; } - bool m_json; + bool m_json_thread; + bool m_json_stopinfo; static OptionDefinition g_option_table[]; }; @@ -1451,81 +1509,16 @@ public: } virtual bool - DoExecute (Args& command, CommandReturnObject &result) + HandleOneThread (Thread &thread, CommandReturnObject &result) { - result.SetStatus (eReturnStatusSuccessFinishResult); Stream &strm = result.GetOutputStream(); - - if (command.GetArgumentCount() == 0) - { - Thread *thread = m_exe_ctx.GetThreadPtr(); - if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.SetStatus (eReturnStatusSuccessFinishResult); - } - } - else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) - { - Process *process = m_exe_ctx.GetProcessPtr(); - uint32_t idx = 0; - for (ThreadSP thread_sp : process->Threads()) - { - if (idx != 0) - result.AppendMessage(""); - if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx); - result.SetStatus (eReturnStatusFailed); - return false; - } - ++idx; - } - } - else + if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json_thread, m_options.m_json_stopinfo)) { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - std::vector<ThreadSP> thread_sps; - - for (size_t i = 0; i < num_args; i++) - { - bool success; - - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); - if (!success) - { - result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); - - if (!thread_sps[i]) - { - result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - } - - for (uint32_t i = 0; i < num_args; i++) - { - if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - if (i < num_args - 1) - result.AppendMessage(""); - } - + result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID()); + result.SetStatus (eReturnStatusFailed); + return false; } - return result.Succeeded(); + return true; } CommandOptions m_options; @@ -1536,6 +1529,7 @@ OptionDefinition CommandObjectThreadInfo::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "json",'j', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the thread info in JSON format."}, + { LLDB_OPT_SET_ALL, false, "stop-info",'s', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the extended stop info in JSON format."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1958,6 +1952,228 @@ CommandObjectThreadJump::CommandOptions::g_option_table[] = }; //------------------------------------------------------------------------- +// Next are the subcommands of CommandObjectMultiwordThreadPlan +//------------------------------------------------------------------------- + + +//------------------------------------------------------------------------- +// CommandObjectThreadPlanList +//------------------------------------------------------------------------- +class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options(interpreter) + { + // Keep default values of all options in one place: OptionParsingStarting () + OptionParsingStarting (); + } + + 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 'i': + { + m_internal = true; + } + break; + case 'v': + { + m_verbose = true; + } + break; + default: + error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); + break; + + } + return error; + } + + void + OptionParsingStarting () + { + m_verbose = false; + m_internal = 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_verbose; + bool m_internal; + }; + + CommandObjectThreadPlanList (CommandInterpreter &interpreter) : + CommandObjectIterateOverThreads (interpreter, + "thread plan list", + "Show thread plans for one or more threads. If no threads are specified, show the " + "currently selected thread. Use the thread-index \"all\" to see all threads.", + NULL, + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ), + m_options(interpreter) + { + } + + ~CommandObjectThreadPlanList () + { + } + + virtual Options * + GetOptions () + { + return &m_options; + } + +protected: + virtual bool + HandleOneThread (Thread &thread, CommandReturnObject &result) + { + Stream &strm = result.GetOutputStream(); + DescriptionLevel desc_level = eDescriptionLevelFull; + if (m_options.m_verbose) + desc_level = eDescriptionLevelVerbose; + + thread.DumpThreadPlans (&strm, desc_level, m_options.m_internal, true); + return true; + } + CommandOptions m_options; +}; + +OptionDefinition +CommandObjectThreadPlanList::CommandOptions::g_option_table[] = +{ +{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display more information about the thread plans"}, +{ LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display internal as well as user thread plans"}, +{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + +class CommandObjectThreadPlanDiscard : public CommandObjectParsed +{ +public: + CommandObjectThreadPlanDiscard (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "thread plan discard", + "Discards thread plans up to and including the plan passed as the command argument." + "Only user visible plans can be discarded, use the index from \"thread plan list\"" + " without the \"-i\" argument.", + NULL, + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ) + { + CommandArgumentEntry arg; + CommandArgumentData plan_index_arg; + + // Define the first (and only) variant of this arg. + plan_index_arg.arg_type = eArgTypeUnsignedInteger; + plan_index_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (plan_index_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + virtual ~CommandObjectThreadPlanDiscard () {} + + bool + DoExecute (Args& args, CommandReturnObject &result) + { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (args.GetArgumentCount() != 1) + { + result.AppendErrorWithFormat("Too many arguments, expected one - the thread plan index - but got %zu.", + args.GetArgumentCount()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + bool success; + uint32_t thread_plan_idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); + if (!success) + { + result.AppendErrorWithFormat("Invalid thread index: \"%s\" - should be unsigned int.", + args.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (thread_plan_idx == 0) + { + result.AppendErrorWithFormat("You wouldn't really want me to discard the base thread plan."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) + { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + else + { + result.AppendErrorWithFormat("Could not find User thread plan with index %s.", + args.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + } +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordThreadPlan +//------------------------------------------------------------------------- + +class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "plan", + "A set of subcommands for accessing the thread plans controlling execution control on one or more threads.", + "thread plan <subcommand> [<subcommand objects]") + { + LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadPlanList (interpreter))); + LoadSubCommand ("discard", CommandObjectSP (new CommandObjectThreadPlanDiscard (interpreter))); + } + + virtual ~CommandObjectMultiwordThreadPlan () {} + + +}; + +//------------------------------------------------------------------------- // CommandObjectMultiwordThread //------------------------------------------------------------------------- @@ -2014,6 +2230,16 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter & NULL, eStepTypeTraceOver, eStepScopeInstruction))); + + LoadSubCommand ("step-scripted", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ( + interpreter, + "thread step-scripted", + "Step as instructed by the script class passed in the -C option.", + NULL, + eStepTypeScripted, + eStepScopeSource))); + + LoadSubCommand ("plan", CommandObjectSP (new CommandObjectMultiwordThreadPlan(interpreter))); } CommandObjectMultiwordThread::~CommandObjectMultiwordThread () diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp index 640fd6d..3a4c60c 100644 --- a/source/Commands/CommandObjectType.cpp +++ b/source/Commands/CommandObjectType.cpp @@ -16,6 +16,7 @@ #include <ctype.h> // C++ Includes +#include <functional> #include "llvm/ADT/StringRef.h" @@ -31,6 +32,11 @@ #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; @@ -2465,22 +2471,7 @@ protected: if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0) { - // we want to make sure to enable "system" last and "default" first - DataVisualization::Categories::Enable(ConstString("default"), TypeCategoryMap::First); - uint32_t num_categories = DataVisualization::Categories::GetCount(); - for (uint32_t i = 0; i < num_categories; i++) - { - lldb::TypeCategoryImplSP category_sp = DataVisualization::Categories::GetCategoryAtIndex(i); - if (category_sp) - { - if ( ::strcmp(category_sp->GetName(), "system") == 0 || - ::strcmp(category_sp->GetName(), "default") == 0 ) - continue; - else - DataVisualization::Categories::Enable(category_sp, TypeCategoryMap::Default); - } - } - DataVisualization::Categories::Enable(ConstString("system"), TypeCategoryMap::Last); + DataVisualization::Categories::EnableStar(); } else { @@ -2630,14 +2621,7 @@ protected: if (argc == 1 && strcmp(command.GetArgumentAtIndex(0),"*") == 0) { - uint32_t num_categories = DataVisualization::Categories::GetCount(); - for (uint32_t i = 0; i < num_categories; i++) - { - lldb::TypeCategoryImplSP category_sp = DataVisualization::Categories::GetCategoryAtIndex(i); - // no need to check if the category is enabled - disabling a disabled category has no effect - if (category_sp) - DataVisualization::Categories::Disable(category_sp); - } + DataVisualization::Categories::DisableStar(); } else { @@ -4253,6 +4237,84 @@ CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] = { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; +template <typename FormatterType> +class CommandObjectFormatterInfo : public CommandObjectRaw +{ +public: + typedef std::function<typename FormatterType::SharedPointer(ValueObject&)> DiscoveryFunction; + CommandObjectFormatterInfo (CommandInterpreter &interpreter, + const char* formatter_name, + DiscoveryFunction discovery_func) : + CommandObjectRaw(interpreter, + nullptr, + nullptr, + nullptr, + eFlagRequiresFrame), + 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 <expr>", 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("<unknown>"), + 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("<unknown>"), + 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: @@ -4266,6 +4328,11 @@ public: LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFormatClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFormatDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFormatList (interpreter))); + LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo<TypeFormatImpl>(interpreter, + "format", + [](ValueObject& valobj) -> TypeFormatImpl::SharedPointer { + return valobj.GetValueFormat(); + }))); } @@ -4289,6 +4356,11 @@ public: LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter))); + LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo<SyntheticChildren>(interpreter, + "synthetic", + [](ValueObject& valobj) -> SyntheticChildren::SharedPointer { + return valobj.GetSyntheticChildren(); + }))); } @@ -4354,6 +4426,11 @@ public: LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter))); LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter))); LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter))); + LoadSubCommand ("info", CommandObjectSP (new CommandObjectFormatterInfo<TypeSummaryImpl>(interpreter, + "summary", + [](ValueObject& valobj) -> TypeSummaryImpl::SharedPointer { + return valobj.GetSummaryFormat(); + }))); } diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp index f46db7a..275ee92 100644 --- a/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/source/Commands/CommandObjectWatchpointCommand.cpp @@ -279,17 +279,16 @@ but do NOT enter more than one command per line. \n" ); result.SetImmediateOutputStream (output_stream); result.SetImmediateErrorStream (error_stream); - bool stop_on_continue = true; - bool echo_commands = false; - bool print_results = true; + CommandInterpreterRunOptions options; + options.SetStopOnContinue (true); + options.SetStopOnError (data->stop_on_error); + options.SetEchoCommands (false); + options.SetPrintResults (true); + options.SetAddToHistory (false); debugger.GetCommandInterpreter().HandleCommands (commands, &exe_ctx, - stop_on_continue, - data->stop_on_error, - echo_commands, - print_results, - eLazyBoolNo, + options, result); result.GetImmediateOutputStream()->Flush(); result.GetImmediateErrorStream()->Flush(); |