From ca36cd16e4aa987a566a03d5f3fe3e87b3d21803 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 5 Oct 2012 19:16:31 +0000 Subject: [PATCH] Add one-shot breakpoints (-o option to "break set") and a tbreak alias for our gdb friends. llvm-svn: 165328 --- lldb/include/lldb/API/SBBreakpoint.h | 6 + lldb/include/lldb/Breakpoint/Breakpoint.h | 14 ++ lldb/include/lldb/Breakpoint/BreakpointOptions.h | 44 ++++- lldb/scripts/Python/interface/SBBreakpoint.i | 6 + lldb/source/API/SBBreakpoint.cpp | 27 +++ lldb/source/Breakpoint/Breakpoint.cpp | 12 ++ lldb/source/Breakpoint/BreakpointOptions.cpp | 35 +--- lldb/source/Commands/CommandObjectBreakpoint.cpp | 208 +++++++++++++-------- lldb/source/Interpreter/CommandInterpreter.cpp | 71 ++++++- lldb/source/Target/StopInfo.cpp | 48 ++++- .../abbreviation/TestAbbreviations.py | 1 + 11 files changed, 339 insertions(+), 133 deletions(-) diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index aa0a2e4..87aada6 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -64,6 +64,12 @@ public: bool IsEnabled (); + void + SetOneShot (bool one_shot); + + bool + IsOneShot () const; + bool IsInternal (); diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index 16a6ec8..66bea54 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -356,6 +356,20 @@ public: //------------------------------------------------------------------ + /// If \a one_shot is \b true, breakpoint will be deleted on first hit. + //------------------------------------------------------------------ + void + SetOneShot (bool one_shot); + + //------------------------------------------------------------------ + /// Check the OneShot state. + /// @return + /// \b true if the breakpoint is one shot, \b false otherwise. + //------------------------------------------------------------------ + bool + IsOneShot () const; + + //------------------------------------------------------------------ /// Set the valid thread to be checked when the breakpoint is hit. /// @param[in] thread_id /// If this thread hits the breakpoint, we stop, otherwise not. diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h index 510249a..b4ccfac 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointOptions.h +++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h @@ -67,7 +67,8 @@ public: void *baton, bool enabled = true, int32_t ignore = 0, - lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID, + bool one_shot = false); virtual ~BreakpointOptions(); @@ -195,13 +196,39 @@ public: /// \b true if the breakpoint is enabled, \b false if disabled. //------------------------------------------------------------------ bool - IsEnabled () const; + IsEnabled () const + { + return m_enabled; + } + + //------------------------------------------------------------------ + /// If \a enable is \b true, enable the breakpoint, if \b false disable it. + //------------------------------------------------------------------ + void + SetEnabled (bool enabled) + { + m_enabled = enabled; + } + + //------------------------------------------------------------------ + /// Check the One-shot state. + /// @return + /// \b true if the breakpoint is one-shot, \b false otherwise. + //------------------------------------------------------------------ + bool + IsOneShot () const + { + return m_one_shot; + } //------------------------------------------------------------------ /// If \a enable is \b true, enable the breakpoint, if \b false disable it. //------------------------------------------------------------------ void - SetEnabled (bool enabled); + SetOneShot (bool one_shot) + { + m_one_shot = one_shot; + } //------------------------------------------------------------------ /// Set the breakpoint to ignore the next \a count breakpoint hits. @@ -210,7 +237,10 @@ public: //------------------------------------------------------------------ void - SetIgnoreCount (uint32_t n); + SetIgnoreCount (uint32_t n) + { + m_ignore_count = n; + } //------------------------------------------------------------------ /// Return the current Ignore Count. @@ -218,7 +248,10 @@ public: /// The number of breakpoint hits to be ignored. //------------------------------------------------------------------ uint32_t - GetIgnoreCount () const; + GetIgnoreCount () const + { + return m_ignore_count; + } //------------------------------------------------------------------ /// Return the current thread spec for this option. This will return NULL if the no thread @@ -314,6 +347,7 @@ private: lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback bool m_callback_is_synchronous; bool m_enabled; + bool m_one_shot; uint32_t m_ignore_count; // Number of times to ignore this breakpoint std::auto_ptr m_thread_spec_ap; // Thread for which this breakpoint will take std::auto_ptr m_condition_ap; // The condition to test. diff --git a/lldb/scripts/Python/interface/SBBreakpoint.i b/lldb/scripts/Python/interface/SBBreakpoint.i index 414936f..cf566d2 100644 --- a/lldb/scripts/Python/interface/SBBreakpoint.i +++ b/lldb/scripts/Python/interface/SBBreakpoint.i @@ -119,6 +119,12 @@ public: bool IsEnabled (); + void + SetOneShot (bool one_shot); + + bool + IsOneShot (); + bool IsInternal (); diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 8be6704..b0b1e2a 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -234,6 +234,33 @@ SBBreakpoint::IsEnabled () return false; } +void +SBBreakpoint::SetOneShot (bool one_shot) +{ + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::SetOneShot (one_shot=%i)", m_opaque_sp.get(), one_shot); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + m_opaque_sp->SetOneShot (one_shot); + } +} + +bool +SBBreakpoint::IsOneShot () const +{ + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + return m_opaque_sp->IsOneShot(); + } + else + return false; +} + bool SBBreakpoint::IsInternal () { diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index e90a827..0fbf9a7 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -189,6 +189,18 @@ Breakpoint::GetHitCount () const return m_locations.GetHitCount(); } +bool +Breakpoint::IsOneShot () const +{ + return m_options.IsOneShot(); +} + +void +Breakpoint::SetOneShot (bool one_shot) +{ + m_options.SetOneShot (one_shot); +} + void Breakpoint::SetThreadID (lldb::tid_t thread_id) { diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index 5de137b..60679c9 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -39,6 +39,7 @@ BreakpointOptions::BreakpointOptions() : m_callback_baton_sp (), m_callback_is_synchronous (false), m_enabled (true), + m_one_shot (false), m_ignore_count (0), m_thread_spec_ap (NULL), m_condition_ap() @@ -53,6 +54,7 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions& rhs) : m_callback_baton_sp (rhs.m_callback_baton_sp), m_callback_is_synchronous (rhs.m_callback_is_synchronous), m_enabled (rhs.m_enabled), + m_one_shot (rhs.m_one_shot), m_ignore_count (rhs.m_ignore_count), m_thread_spec_ap (NULL), m_condition_ap (NULL) @@ -73,6 +75,7 @@ BreakpointOptions::operator=(const BreakpointOptions& rhs) m_callback_baton_sp = rhs.m_callback_baton_sp; m_callback_is_synchronous = rhs.m_callback_is_synchronous; m_enabled = rhs.m_enabled; + m_one_shot = rhs.m_one_shot; m_ignore_count = rhs.m_ignore_count; if (rhs.m_thread_spec_ap.get() != NULL) m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get())); @@ -179,33 +182,6 @@ BreakpointOptions::GetConditionText () const return NULL; } -//------------------------------------------------------------------ -// Enabled/Ignore Count -//------------------------------------------------------------------ -bool -BreakpointOptions::IsEnabled () const -{ - return m_enabled; -} - -void -BreakpointOptions::SetEnabled (bool enabled) -{ - m_enabled = enabled; -} - -uint32_t -BreakpointOptions::GetIgnoreCount () const -{ - return m_ignore_count; -} - -void -BreakpointOptions::SetIgnoreCount (uint32_t n) -{ - m_ignore_count = n; -} - const ThreadSpec * BreakpointOptions::GetThreadSpecNoCreate () const { @@ -234,7 +210,7 @@ BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) cons // Figure out if there are any options not at their default value, and only print // anything if there are: - if (m_ignore_count != 0 || !m_enabled || (GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ())) + if (m_ignore_count != 0 || !m_enabled || m_one_shot || (GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ())) { if (level == lldb::eDescriptionLevelVerbose) { @@ -252,6 +228,9 @@ BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) cons s->Printf("ignore: %d ", m_ignore_count); s->Printf("%sabled ", m_enabled ? "en" : "dis"); + if (m_one_shot) + s->Printf ("one-shot "); + if (m_thread_spec_ap.get()) m_thread_spec_ap->GetDescription (s, level); else if (level == eDescriptionLevelBrief) diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 0bc02d8..7c673f7 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -105,7 +105,8 @@ public: m_catch_bp (false), m_throw_bp (true), m_language (eLanguageTypeUnknown), - m_skip_prologue (eLazyBoolCalculate) + m_skip_prologue (eLazyBoolCalculate), + m_one_shot (false) { } @@ -130,6 +131,11 @@ public: error.SetErrorStringWithFormat ("invalid address string '%s'", option_arg); break; + case 'b': + m_func_names.push_back (option_arg); + m_func_name_type_mask |= eFunctionNameTypeBase; + break; + case 'C': m_column = Args::StringToUInt32 (option_arg, 0); break; @@ -138,59 +144,116 @@ public: m_condition.assign(option_arg); break; + case 'E': + { + LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg); + + switch (language) + { + case eLanguageTypeC89: + case eLanguageTypeC: + case eLanguageTypeC99: + m_language = eLanguageTypeC; + break; + case eLanguageTypeC_plus_plus: + m_language = eLanguageTypeC_plus_plus; + break; + case eLanguageTypeObjC: + m_language = eLanguageTypeObjC; + break; + case eLanguageTypeObjC_plus_plus: + error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c"); + break; + case eLanguageTypeUnknown: + error.SetErrorStringWithFormat ("Unknown language type: '%s' for exception breakpoint", option_arg); + break; + default: + error.SetErrorStringWithFormat ("Unsupported language type: '%s' for exception breakpoint", option_arg); + } + } + break; + case 'f': m_filenames.AppendIfUnique (FileSpec(option_arg, false)); break; - case 'l': - m_line_num = Args::StringToUInt32 (option_arg, 0); + case 'F': + m_func_names.push_back (option_arg); + m_func_name_type_mask |= eFunctionNameTypeFull; break; - case 'b': - m_func_names.push_back (option_arg); - m_func_name_type_mask |= eFunctionNameTypeBase; + case 'h': + { + bool success; + m_catch_bp = Args::StringToBoolean (option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat ("Invalid boolean value for on-catch option: '%s'", option_arg); + } + + case 'i': + { + m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + if (m_ignore_count == UINT32_MAX) + error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); break; + } - case 'n': - m_func_names.push_back (option_arg); - m_func_name_type_mask |= eFunctionNameTypeAuto; + case 'K': + { + bool success; + bool value; + value = Args::StringToBoolean (option_arg, true, &success); + if (value) + m_skip_prologue = eLazyBoolYes; + else + m_skip_prologue = eLazyBoolNo; + + if (!success) + error.SetErrorStringWithFormat ("Invalid boolean value for skip prologue option: '%s'", option_arg); + } + break; + + case 'l': + m_line_num = Args::StringToUInt32 (option_arg, 0); break; - case 'F': + case 'M': m_func_names.push_back (option_arg); - m_func_name_type_mask |= eFunctionNameTypeFull; + m_func_name_type_mask |= eFunctionNameTypeMethod; break; - case 'S': + case 'n': m_func_names.push_back (option_arg); - m_func_name_type_mask |= eFunctionNameTypeSelector; + m_func_name_type_mask |= eFunctionNameTypeAuto; break; - case 'M': - m_func_names.push_back (option_arg); - m_func_name_type_mask |= eFunctionNameTypeMethod; + case 'o': + m_one_shot = true; break; case 'p': m_source_text_regexp.assign (option_arg); break; + case 'q': + m_queue_name.assign (option_arg); + break; + case 'r': m_func_regexp.assign (option_arg); break; case 's': - { - m_modules.AppendIfUnique (FileSpec (option_arg, false)); - break; - } - case 'i': { - m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); - if (m_ignore_count == UINT32_MAX) - error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); + m_modules.AppendIfUnique (FileSpec (option_arg, false)); + break; } - break; + + case 'S': + m_func_names.push_back (option_arg); + m_func_name_type_mask |= eFunctionNameTypeSelector; + break; + case 't' : { m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); @@ -198,48 +261,11 @@ public: error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg); } break; + case 'T': m_thread_name.assign (option_arg); break; - case 'q': - m_queue_name.assign (option_arg); - break; - case 'x': - { - m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0); - if (m_thread_id == UINT32_MAX) - error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); - - } - break; - case 'E': - { - LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg); - switch (language) - { - case eLanguageTypeC89: - case eLanguageTypeC: - case eLanguageTypeC99: - m_language = eLanguageTypeC; - break; - case eLanguageTypeC_plus_plus: - m_language = eLanguageTypeC_plus_plus; - break; - case eLanguageTypeObjC: - m_language = eLanguageTypeObjC; - break; - case eLanguageTypeObjC_plus_plus: - error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c"); - break; - case eLanguageTypeUnknown: - error.SetErrorStringWithFormat ("Unknown language type: '%s' for exception breakpoint", option_arg); - break; - default: - error.SetErrorStringWithFormat ("Unsupported language type: '%s' for exception breakpoint", option_arg); - } - } - break; case 'w': { bool success; @@ -248,27 +274,16 @@ public: error.SetErrorStringWithFormat ("Invalid boolean value for on-throw option: '%s'", option_arg); } break; - case 'h': - { - bool success; - m_catch_bp = Args::StringToBoolean (option_arg, true, &success); - if (!success) - error.SetErrorStringWithFormat ("Invalid boolean value for on-catch option: '%s'", option_arg); - } - case 'K': + + case 'x': { - bool success; - bool value; - value = Args::StringToBoolean (option_arg, true, &success); - if (value) - m_skip_prologue = eLazyBoolYes; - else - m_skip_prologue = eLazyBoolNo; - - if (!success) - error.SetErrorStringWithFormat ("Invalid boolean value for skip prologue option: '%s'", option_arg); + m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + if (m_thread_id == UINT32_MAX) + error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); + } break; + default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -298,6 +313,7 @@ public: m_throw_bp = true; m_language = eLanguageTypeUnknown; m_skip_prologue = eLazyBoolCalculate; + m_one_shot = false; } const OptionDefinition* @@ -331,6 +347,7 @@ public: bool m_throw_bp; lldb::LanguageType m_language; LazyBool m_skip_prologue; + bool m_one_shot; }; @@ -511,6 +528,8 @@ protected: if (!m_options.m_condition.empty()) bp->GetOptions()->SetCondition(m_options.m_condition.c_str()); + + bp->SetOneShot (m_options.m_one_shot); } if (bp) @@ -591,6 +610,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, + { LLDB_OPT_SET_ALL, false, "one-shot", 'o', no_argument, NULL, 0, eArgTypeNone, + "The breakpoint is deleted the first time it stop causes a stop." }, + { LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."}, @@ -707,11 +729,13 @@ public: m_thread_name(), m_queue_name(), m_condition (), + m_one_shot (false), m_enable_passed (false), m_enable_value (false), m_name_passed (false), m_queue_passed (false), - m_condition_passed (false) + m_condition_passed (false), + m_one_shot_passed (false) { } @@ -748,6 +772,19 @@ public: error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); } break; + case 'o': + { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) + { + m_one_shot_passed = true; + m_one_shot = value; + } + else + error.SetErrorStringWithFormat("invalid boolean value '%s' passed for -o option", option_arg); + } + break; case 't' : { if (option_arg[0] == '\0') @@ -814,10 +851,12 @@ public: m_thread_name.clear(); m_queue_name.clear(); m_condition.clear(); + m_one_shot = false; m_enable_passed = false; m_queue_passed = false; m_name_passed = false; m_condition_passed = false; + m_one_shot_passed = false; } const OptionDefinition* @@ -841,11 +880,13 @@ public: std::string m_thread_name; std::string m_queue_name; std::string m_condition; + bool m_one_shot; bool m_enable_passed; bool m_enable_value; bool m_name_passed; bool m_queue_passed; bool m_condition_passed; + bool m_one_shot_passed; }; @@ -944,6 +985,7 @@ OptionDefinition CommandObjectBreakpointModify::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, +{ LLDB_OPT_SET_ALL, false, "one-shot", 'o', required_argument, NULL, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." }, { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose indeX matches this argument."}, { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument."}, { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument."}, @@ -951,7 +993,7 @@ CommandObjectBreakpointModify::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."}, { LLDB_OPT_SET_1, false, "enable", 'e', no_argument, NULL, 0, eArgTypeNone, "Enable the breakpoint."}, { LLDB_OPT_SET_2, false, "disable", 'd', no_argument, NULL, 0, eArgTypeNone, "Disable the breakpoint."}, -{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL } +{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL } }; //------------------------------------------------------------------------- diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index c387c3d..6db59ac 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -156,6 +156,14 @@ CommandInterpreter::Initialize () if (cmd_obj_sp) AddAlias ("b", cmd_obj_sp); + cmd_obj_sp = GetCommandSPExact ("_regexp-tbreak",false); + if (cmd_obj_sp) + AddAlias ("tbreak", cmd_obj_sp); + + cmd_obj_sp = GetCommandSPExact ("thread backtrace", false); + if (cmd_obj_sp) + AddAlias ("bt", cmd_obj_sp); + cmd_obj_sp = GetCommandSPExact ("thread step-inst", false); if (cmd_obj_sp) { @@ -196,6 +204,12 @@ CommandInterpreter::Initialize () AddAlias ("f", cmd_obj_sp); } + cmd_obj_sp = GetCommandSPExact ("thread select", false); + if (cmd_obj_sp) + { + AddAlias ("t", cmd_obj_sp); + } + cmd_obj_sp = GetCommandSPExact ("source list", false); if (cmd_obj_sp) { @@ -366,21 +380,34 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["version"] = CommandObjectSP (new CommandObjectVersion (*this)); m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this)); + const char *break_regexes[][2] = {{"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2"}, + {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"}, + {"^(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"}, + {"^[\"']?([-+]\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"}, + {"^(-.*)$", "breakpoint set %1"}, + {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'"}, + {"^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'"}}; + + size_t num_regexes = sizeof break_regexes/sizeof(char *[2]); + std::auto_ptr break_regex_cmd_ap(new CommandObjectRegexCommand (*this, "_regexp-break", "Set a breakpoint using a regular expression to specify the location, where is in decimal and
is in hex.", "_regexp-break [:]\n_regexp-break []\n_regexp-break [
]\n_regexp-break <...>", 2)); + if (break_regex_cmd_ap.get()) { - if (break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2") && - break_regex_cmd_ap->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1") && - break_regex_cmd_ap->AddRegexCommand("^(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1") && - break_regex_cmd_ap->AddRegexCommand("^[\"']?([-+]\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'") && - break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full") && - break_regex_cmd_ap->AddRegexCommand("^(-.*)$", "breakpoint set %1") && - break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'") && - break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'")) + bool success = true; + for (size_t i = 0; i < num_regexes; i++) + { + success = break_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], break_regexes[i][1]); + if (!success) + break; + } + success = break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full"); + + if (success) { CommandObjectSP break_regex_cmd_sp(break_regex_cmd_ap.release()); m_command_dict[break_regex_cmd_sp->GetCommandName ()] = break_regex_cmd_sp; @@ -388,6 +415,34 @@ CommandInterpreter::LoadCommandDictionary () } std::auto_ptr + tbreak_regex_cmd_ap(new CommandObjectRegexCommand (*this, + "_regexp-tbreak", + "Set a one shot breakpoint using a regular expression to specify the location, where is in decimal and
is in hex.", + "_regexp-tbreak [:]\n_regexp-break []\n_regexp-break [
]\n_regexp-break <...>", 2)); + + if (tbreak_regex_cmd_ap.get()) + { + bool success = true; + for (size_t i = 0; i < num_regexes; i++) + { + // If you add a resultant command string longer than 1024 characters be sure to increase the size of this buffer. + char buffer[1024]; + int num_printed = snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o"); + assert (num_printed < 1024); + success = tbreak_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], buffer); + if (!success) + break; + } + success = tbreak_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full"); + + if (success) + { + CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_ap.release()); + m_command_dict[tbreak_regex_cmd_sp->GetCommandName ()] = tbreak_regex_cmd_sp; + } + } + + std::auto_ptr attach_regex_cmd_ap(new CommandObjectRegexCommand (*this, "_regexp-attach", "Attach to a process id if in decimal, otherwise treat the argument as a process name to attach to.", diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 26c2cf5..c5c9c70 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -99,13 +99,11 @@ public: m_should_stop (false), m_should_stop_is_valid (false), m_should_perform_action (true), - m_address (LLDB_INVALID_ADDRESS) + m_address (LLDB_INVALID_ADDRESS), + m_break_id(LLDB_INVALID_BREAK_ID), + m_was_one_shot (false) { - BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value)); - if (bp_site_sp) - { - m_address = bp_site_sp->GetLoadAddress(); - } + StoreBPInfo(); } StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) : @@ -114,12 +112,28 @@ public: m_should_stop (should_stop), m_should_stop_is_valid (true), m_should_perform_action (true), - m_address (LLDB_INVALID_ADDRESS) + m_address (LLDB_INVALID_ADDRESS), + m_break_id(LLDB_INVALID_BREAK_ID), + m_was_one_shot (false) + { + StoreBPInfo(); + } + + void StoreBPInfo () { BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (m_value)); if (bp_site_sp) { - m_address = bp_site_sp->GetLoadAddress(); + if (bp_site_sp->GetNumberOfOwners() == 1) + { + BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0); + if (bp_loc_sp) + { + m_break_id = bp_loc_sp->GetBreakpoint().GetID(); + m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot(); + } + } + m_address = bp_site_sp->GetLoadAddress(); } } @@ -298,6 +312,12 @@ public: if (callback_says_stop) m_should_stop = true; + + // If we are going to stop for this breakpoint, then remove the breakpoint. + if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot()) + { + m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID()); + } // Also make sure that the callback hasn't continued the target. // If it did, when we'll set m_should_start to false and get out of here. @@ -362,10 +382,18 @@ public: else { StreamString strm; - if (m_address == LLDB_INVALID_ADDRESS) + if (m_break_id != LLDB_INVALID_BREAK_ID) + { + if (m_was_one_shot) + strm.Printf ("one-shot breakpoint %d", m_break_id); + else + strm.Printf ("breakpoint %d which has been deleted.", m_break_id); + } + else if (m_address == LLDB_INVALID_ADDRESS) strm.Printf("breakpoint site %lli which has been deleted - unknown address", m_value); else strm.Printf("breakpoint site %lli which has been deleted - was at 0x%llx", m_value, m_address); + m_description.swap (strm.GetString()); } } @@ -381,6 +409,8 @@ private: lldb::addr_t m_address; // We use this to capture the breakpoint site address when we create the StopInfo, // in case somebody deletes it between the time the StopInfo is made and the // description is asked for. + lldb::break_id_t m_break_id; + bool m_was_one_shot; }; diff --git a/lldb/test/functionalities/abbreviation/TestAbbreviations.py b/lldb/test/functionalities/abbreviation/TestAbbreviations.py index 9eeeb80..e79aa8e 100644 --- a/lldb/test/functionalities/abbreviation/TestAbbreviations.py +++ b/lldb/test/functionalities/abbreviation/TestAbbreviations.py @@ -36,6 +36,7 @@ class AbbreviationsTestCase(TestBase): startstr = "The following is a list of built-in, permanent debugger commands:") # Several matching commands: list them and error out. + self.runCmd("command unalias t") self.expect("t", COMMAND_FAILED_AS_EXPECTED, error = True, substrs = ["Ambiguous command 't'. Possible matches:", -- 2.7.4