summaryrefslogtreecommitdiffstats
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/SBBreakpoint.cpp19
-rw-r--r--lldb/source/API/SBBreakpointLocation.cpp19
-rw-r--r--lldb/source/Breakpoint/Breakpoint.cpp8
-rw-r--r--lldb/source/Breakpoint/BreakpointLocation.cpp13
-rw-r--r--lldb/source/Breakpoint/BreakpointOptions.cpp38
-rw-r--r--lldb/source/Commands/CommandObjectBreakpoint.cpp53
-rw-r--r--lldb/source/Target/StopInfo.cpp43
7 files changed, 173 insertions, 20 deletions
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index bf9603248d7..c7d6d6c5b18 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -264,6 +264,25 @@ const char *SBBreakpoint::GetCondition() {
return nullptr;
}
+void SBBreakpoint::SetAutoContinue(bool auto_continue) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->SetAutoContinue(auto_continue);
+ }
+}
+
+bool SBBreakpoint::GetAutoContinue() {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ bkpt_sp->GetTarget().GetAPIMutex());
+ return bkpt_sp->IsAutoContinue();
+ }
+ return nullptr;
+}
+
uint32_t SBBreakpoint::GetHitCount() const {
uint32_t count = 0;
BreakpointSP bkpt_sp = GetSP();
diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp
index f5e0b91483e..2678e1ea758 100644
--- a/lldb/source/API/SBBreakpointLocation.cpp
+++ b/lldb/source/API/SBBreakpointLocation.cpp
@@ -149,6 +149,25 @@ const char *SBBreakpointLocation::GetCondition() {
return NULL;
}
+void SBBreakpointLocation::SetAutoContinue(bool auto_continue) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetAutoContinue(auto_continue);
+ }
+}
+
+bool SBBreakpointLocation::GetAutoContinue() {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->IsAutoContinue();
+ }
+ return NULL;
+}
+
void SBBreakpointLocation::SetScriptCallbackFunction(
const char *callback_function_name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp
index 043e5e8f591..fd606aa83d6 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -348,6 +348,14 @@ void Breakpoint::SetOneShot(bool one_shot) {
m_options_up->SetOneShot(one_shot);
}
+bool Breakpoint::IsAutoContinue() const {
+ return m_options_up->IsAutoContinue();
+}
+
+void Breakpoint::SetAutoContinue(bool auto_continue) {
+ m_options_up->SetAutoContinue(auto_continue);
+}
+
void Breakpoint::SetThreadID(lldb::tid_t thread_id) {
if (m_options_up->GetThreadSpec()->GetTID() == thread_id)
return;
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 15865be3f9a..f59c334fe5c 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -93,6 +93,19 @@ void BreakpointLocation::SetEnabled(bool enabled) {
: eBreakpointEventTypeDisabled);
}
+bool BreakpointLocation::IsAutoContinue() const {
+ if (m_options_ap
+ && m_options_ap->IsOptionSet(BreakpointOptions::eAutoContinue))
+ return m_options_ap->IsAutoContinue();
+ else
+ return m_owner.IsAutoContinue();
+}
+
+void BreakpointLocation::SetAutoContinue(bool auto_continue) {
+ GetLocationOptions()->SetAutoContinue(auto_continue);
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeAutoContinueChanged);
+}
+
void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) {
if (thread_id != LLDB_INVALID_THREAD_ID)
GetLocationOptions()->SetThreadID(thread_id);
diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp
index 3e8d3dd41f3..7159688102d 100644
--- a/lldb/source/Breakpoint/BreakpointOptions.cpp
+++ b/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -114,7 +114,8 @@ BreakpointOptions::CommandData::CreateFromStructuredData(
const char *BreakpointOptions::g_option_names[(
size_t)BreakpointOptions::OptionNames::LastOptionName]{
- "ConditionText", "IgnoreCount", "EnabledState", "OneShotState"};
+ "ConditionText", "IgnoreCount",
+ "EnabledState", "OneShotState", "AutoContinue"};
bool BreakpointOptions::NullCallback(void *baton,
StoppointCallbackContext *context,
@@ -130,20 +131,22 @@ BreakpointOptions::BreakpointOptions(bool all_flags_set)
: m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(),
m_baton_is_command_baton(false), m_callback_is_synchronous(false),
m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_ap(),
- m_condition_text(), m_condition_text_hash(0),
+ m_condition_text(), m_condition_text_hash(0), m_auto_continue(false),
m_set_flags() {
if (all_flags_set)
m_set_flags.Set(~((Flags::ValueType) 0));
}
BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
- int32_t ignore, bool one_shot)
+ int32_t ignore, bool one_shot,
+ bool auto_continue)
: m_callback(nullptr), m_baton_is_command_baton(false),
m_callback_is_synchronous(false), m_enabled(enabled),
m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text(condition),
- m_condition_text_hash(0)
+ m_condition_text_hash(0), m_auto_continue(auto_continue)
{
- m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eCondition);
+ m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot
+ | eCondition | eAutoContinue);
}
//----------------------------------------------------------------------
@@ -155,6 +158,7 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
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(),
+ m_auto_continue(rhs.m_auto_continue),
m_set_flags(rhs.m_set_flags) {
if (rhs.m_thread_spec_ap.get() != nullptr)
m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
@@ -178,6 +182,7 @@ operator=(const BreakpointOptions &rhs) {
m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
m_condition_text = rhs.m_condition_text;
m_condition_text_hash = rhs.m_condition_text_hash;
+ m_auto_continue = rhs.m_auto_continue;
m_set_flags = rhs.m_set_flags;
return *this;
}
@@ -192,6 +197,7 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
Status &error) {
bool enabled = true;
bool one_shot = false;
+ bool auto_continue = false;
int32_t ignore_count = 0;
llvm::StringRef condition_ref("");
Flags set_options;
@@ -219,6 +225,17 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
set_options.Set(eOneShot);
}
+ key = GetKey(OptionNames::AutoContinue);
+ if (key) {
+ success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
+ if (!success) {
+ error.SetErrorStringWithFormat("%s key is not a boolean.",
+ GetKey(OptionNames::AutoContinue));
+ return nullptr;
+ }
+ set_options.Set(eAutoContinue);
+ }
+
key = GetKey(OptionNames::IgnoreCount);
if (key) {
success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
@@ -257,7 +274,8 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
}
auto bp_options = llvm::make_unique<BreakpointOptions>(
- condition_ref.str().c_str(), enabled, ignore_count, one_shot);
+ condition_ref.str().c_str(), enabled,
+ ignore_count, one_shot, auto_continue);
if (cmd_data_up.get()) {
if (cmd_data_up->interpreter == eScriptLanguageNone)
bp_options->SetCommandDataCallback(cmd_data_up);
@@ -315,6 +333,9 @@ StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
if (m_set_flags.Set(eOneShot))
options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
m_one_shot);
+ if (m_set_flags.Set(eAutoContinue))
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
+ m_auto_continue);
if (m_set_flags.Set(eIgnoreCount))
options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
m_ignore_count);
@@ -471,7 +492,7 @@ void BreakpointOptions::GetDescription(Stream *s,
// print
// anything if there are:
- if (m_ignore_count != 0 || !m_enabled || m_one_shot ||
+ if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
(GetThreadSpecNoCreate() != nullptr &&
GetThreadSpecNoCreate()->HasSpecification())) {
if (level == lldb::eDescriptionLevelVerbose) {
@@ -491,6 +512,9 @@ void BreakpointOptions::GetDescription(Stream *s,
if (m_one_shot)
s->Printf("one-shot ");
+ if (m_auto_continue)
+ s->Printf("auto-continue ");
+
if (m_thread_spec_ap.get())
m_thread_spec_ap->GetDescription(s, level);
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 266864d1a1f..d53e681514d 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -60,7 +60,9 @@ static OptionDefinition g_breakpoint_set_options[] = {
"multiple times to specify multiple shared libraries." },
{ LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." },
{ LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "The breakpoint is deleted the first time it causes a stop." },
+ { LLDB_OPT_SET_ALL, false, "auto-continue", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." },
{ LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true." },
+ { LLDB_OPT_SET_ALL, false, "command", 'd', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommand, "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." },
{ LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose indeX matches this argument." },
{ LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument." },
{ LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this "
@@ -208,6 +210,10 @@ public:
m_condition.assign(option_arg);
break;
+ case 'd':
+ m_commands.push_back(option_arg);
+ break;
+
case 'D':
m_use_dummy = true;
break;
@@ -255,6 +261,15 @@ public:
m_func_names.push_back(option_arg);
m_func_name_type_mask |= eFunctionNameTypeFull;
break;
+
+ case 'G' : {
+ bool success;
+ m_auto_continue = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat(
+ "Invalid boolean value for auto-continue option: '%s'",
+ option_arg.str().c_str());
+ } break;
case 'h': {
bool success;
@@ -445,6 +460,8 @@ public:
m_exception_extra_args.Clear();
m_move_to_nearest_code = eLazyBoolCalculate;
m_source_regex_func_names.clear();
+ m_commands.clear();
+ m_auto_continue = false;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -482,6 +499,8 @@ public:
Args m_exception_extra_args;
LazyBool m_move_to_nearest_code;
std::unordered_set<std::string> m_source_regex_func_names;
+ std::vector<std::string> m_commands;
+ bool m_auto_continue;
};
protected:
@@ -719,6 +738,18 @@ protected:
}
bp->SetOneShot(m_options.m_one_shot);
+ bp->SetAutoContinue(m_options.m_auto_continue);
+
+ if (!m_options.m_commands.empty())
+ {
+ auto cmd_data = llvm::make_unique<BreakpointOptions::CommandData>();
+
+ for (std::string &str : m_options.m_commands)
+ cmd_data->user_source.AppendString(str);
+
+ cmd_data->stop_on_error = true;
+ bp->GetOptions()->SetCommandDataCallback(cmd_data);
+ }
}
if (bp) {
@@ -802,6 +833,7 @@ static OptionDefinition g_breakpoint_modify_options[] = {
{ LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable the breakpoint." },
{ LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Disable the breakpoint." },
{ LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
+ { LLDB_OPT_SET_ALL, false, "auto-continue", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." },
// clang-format on
};
@@ -865,6 +897,17 @@ public:
m_enable_passed = true;
m_enable_value = true;
break;
+ case 'G': {
+ bool value, success;
+ value = Args::StringToBoolean(option_arg, false, &success);
+ if (success) {
+ m_auto_continue_passed = true;
+ m_auto_continue = value;
+ } else
+ error.SetErrorStringWithFormat(
+ "invalid boolean value '%s' passed for -G option",
+ option_arg.str().c_str());
+ } break;
case 'i':
if (option_arg.getAsInteger(0, m_ignore_count))
error.SetErrorStringWithFormat("invalid ignore count '%s'",
@@ -938,6 +981,8 @@ public:
m_condition_passed = false;
m_one_shot_passed = false;
m_use_dummy = false;
+ m_auto_continue = false;
+ m_auto_continue_passed = false;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -962,6 +1007,8 @@ public:
bool m_condition_passed;
bool m_one_shot_passed;
bool m_use_dummy;
+ bool m_auto_continue;
+ bool m_auto_continue_passed;
};
protected:
@@ -1013,6 +1060,9 @@ protected:
if (m_options.m_condition_passed)
location->SetCondition(m_options.m_condition.c_str());
+
+ if (m_options.m_auto_continue_passed)
+ location->SetAutoContinue(m_options.m_auto_continue);
}
} else {
if (m_options.m_thread_id_passed)
@@ -1035,6 +1085,9 @@ protected:
if (m_options.m_condition_passed)
bp->SetCondition(m_options.m_condition.c_str());
+
+ if (m_options.m_auto_continue_passed)
+ bp->SetAutoContinue(m_options.m_auto_continue);
}
}
}
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 6af5ce1b2eb..8dbcec9fa81 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -393,7 +393,10 @@ protected:
for (size_t j = 0; j < num_owners; j++) {
lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
-
+ StreamString loc_desc;
+ if (log) {
+ bp_loc_sp->GetDescription(&loc_desc, eDescriptionLevelBrief);
+ }
// If another action disabled this breakpoint or its location, then
// don't run the actions.
if (!bp_loc_sp->IsEnabled() ||
@@ -405,16 +408,16 @@ protected:
// this thread. Skip the ones that aren't:
if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) {
if (log) {
- StreamString s;
- bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
log->Printf("Breakpoint %s hit on thread 0x%llx but it was not "
"for this thread, continuing.",
- s.GetData(), static_cast<unsigned long long>(
+ loc_desc.GetData(), static_cast<unsigned long long>(
thread_sp->GetID()));
}
continue;
}
+ internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal();
+
// First run the precondition, but since the precondition is per
// breakpoint, only run it once
// per breakpoint.
@@ -458,11 +461,10 @@ protected:
error_sp->Flush();
} else {
if (log) {
- StreamString s;
- bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
log->Printf("Condition evaluated for breakpoint %s on thread "
"0x%llx conditon_says_stop: %i.",
- s.GetData(), static_cast<unsigned long long>(
+ loc_desc.GetData(),
+ static_cast<unsigned long long>(
thread_sp->GetID()),
condition_says_stop);
}
@@ -477,7 +479,26 @@ protected:
}
}
- bool callback_says_stop;
+ // Check the auto-continue bit on the location, do this before the
+ // callback since it may change this, but that would be for the
+ // NEXT hit. Note, you might think you could check auto-continue
+ // before the condition, and not evaluate the condition if it says
+ // to continue. But failing the condition means the breakpoint was
+ // effectively NOT HIT. So these two states are different.
+ bool auto_continue_says_stop = true;
+ if (bp_loc_sp->IsAutoContinue())
+ {
+ if (log)
+ log->Printf("Continuing breakpoint %s as AutoContinue was set.",
+ loc_desc.GetData());
+ // We want this stop reported, so you will know we auto-continued
+ // but only for external breakpoints:
+ if (!internal_breakpoint)
+ thread_sp->SetShouldReportStop(eVoteYes);
+ auto_continue_says_stop = false;
+ }
+
+ bool callback_says_stop = true;
// FIXME: For now the callbacks have to run in async mode - the
// first time we restart we need
@@ -493,11 +514,8 @@ protected:
debugger.SetAsyncExecution(old_async);
- if (callback_says_stop)
+ if (callback_says_stop && auto_continue_says_stop)
m_should_stop = true;
-
- if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal())
- internal_breakpoint = false;
// If we are going to stop for this breakpoint, then remove the
// breakpoint.
@@ -506,7 +524,6 @@ protected:
thread_sp->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.
OpenPOWER on IntegriCloud