Add one-shot breakpoints (-o option to "break set") and a tbreak alias for our gdb friends.

llvm-svn: 165328
This commit is contained in:
Jim Ingham 2012-10-05 19:16:31 +00:00
parent 874f43cadc
commit ca36cd16e4
11 changed files with 341 additions and 135 deletions

View File

@ -64,6 +64,12 @@ public:
bool
IsEnabled ();
void
SetOneShot (bool one_shot);
bool
IsOneShot () const;
bool
IsInternal ();

View File

@ -355,6 +355,20 @@ public:
GetHitCount () const;
//------------------------------------------------------------------
/// 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

View File

@ -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);
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
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<ThreadSpec> m_thread_spec_ap; // Thread for which this breakpoint will take
std::auto_ptr<ClangUserExpression> m_condition_ap; // The condition to test.

View File

@ -119,6 +119,12 @@ public:
bool
IsEnabled ();
void
SetOneShot (bool one_shot);
bool
IsOneShot ();
bool
IsInternal ();

View File

@ -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 ()
{

View File

@ -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)
{

View File

@ -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)

View File

@ -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,80 +144,6 @@ public:
m_condition.assign(option_arg);
break;
case 'f':
m_filenames.AppendIfUnique (FileSpec(option_arg, false));
break;
case 'l':
m_line_num = Args::StringToUInt32 (option_arg, 0);
break;
case 'b':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeBase;
break;
case 'n':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeAuto;
break;
case 'F':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeFull;
break;
case 'S':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeSelector;
break;
case 'M':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeMethod;
break;
case 'p':
m_source_text_regexp.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);
}
break;
case 't' :
{
m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
if (m_thread_id == LLDB_INVALID_THREAD_ID)
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);
@ -240,14 +172,16 @@ public:
}
}
break;
case 'w':
{
bool success;
m_throw_bp = Args::StringToBoolean (option_arg, true, &success);
if (!success)
error.SetErrorStringWithFormat ("Invalid boolean value for on-throw option: '%s'", option_arg);
}
break;
case 'f':
m_filenames.AppendIfUnique (FileSpec(option_arg, false));
break;
case 'F':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeFull;
break;
case 'h':
{
bool success;
@ -255,6 +189,15 @@ public:
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 'K':
{
bool success;
@ -269,6 +212,78 @@ public:
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 'M':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeMethod;
break;
case 'n':
m_func_names.push_back (option_arg);
m_func_name_type_mask |= eFunctionNameTypeAuto;
break;
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 '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);
if (m_thread_id == LLDB_INVALID_THREAD_ID)
error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
}
break;
case 'T':
m_thread_name.assign (option_arg);
break;
case 'w':
{
bool success;
m_throw_bp = Args::StringToBoolean (option_arg, true, &success);
if (!success)
error.SetErrorStringWithFormat ("Invalid boolean value for on-throw option: '%s'", 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;
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 }
};
//-------------------------------------------------------------------------

View File

@ -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,27 +380,68 @@ 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<CommandObjectRegexCommand>
break_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-break",
"Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.",
"_regexp-break [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\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;
}
}
std::auto_ptr<CommandObjectRegexCommand>
tbreak_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-tbreak",
"Set a one shot breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.",
"_regexp-tbreak [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\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<CommandObjectRegexCommand>
attach_regex_cmd_ap(new CommandObjectRegexCommand (*this,
"_regexp-attach",

View File

@ -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;
};

View File

@ -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:",