aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Breakpoint/Breakpoint.h14
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointLocation.h12
-rw-r--r--lldb/include/lldb/Breakpoint/BreakpointOptions.h20
-rw-r--r--lldb/include/lldb/Breakpoint/StopCondition.h55
-rw-r--r--lldb/source/API/SBBreakpoint.cpp4
-rw-r--r--lldb/source/API/SBBreakpointLocation.cpp4
-rw-r--r--lldb/source/API/SBBreakpointName.cpp5
-rw-r--r--lldb/source/Breakpoint/Breakpoint.cpp8
-rw-r--r--lldb/source/Breakpoint/BreakpointLocation.cpp37
-rw-r--r--lldb/source/Breakpoint/BreakpointOptions.cpp52
-rw-r--r--lldb/source/Commands/CommandObjectBreakpoint.cpp17
-rw-r--r--lldb/source/Commands/Options.td6
-rw-r--r--lldb/source/Target/StopInfo.cpp4
-rw-r--r--lldb/test/API/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py29
-rw-r--r--lldb/test/Shell/Breakpoint/condition-lang.test5
15 files changed, 176 insertions, 96 deletions
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h
index b200a1e..26a5e90 100644
--- a/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -397,16 +397,12 @@ public:
/// Set the breakpoint's condition.
///
/// \param[in] condition
- /// The condition expression to evaluate when the breakpoint is hit.
- /// Pass in nullptr to clear the condition.
- void SetCondition(const char *condition);
+ /// The condition to evaluate when the breakpoint is hit.
+ /// Pass in an empty condition to clear the condition.
+ void SetCondition(StopCondition condition);
- /// Return a pointer to the text of the condition expression.
- ///
- /// \return
- /// A pointer to the condition expression text, or nullptr if no
- // condition has been set.
- const char *GetConditionText() const;
+ /// Return the breakpoint condition.
+ const StopCondition &GetCondition() const;
// The next section are various utility functions.
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
index ce3a21f..ab2e5e1 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -128,15 +128,11 @@ public:
/// Set the breakpoint location's condition.
///
/// \param[in] condition
- /// The condition expression to evaluate when the breakpoint is hit.
- void SetCondition(const char *condition);
+ /// The condition to evaluate when the breakpoint is hit.
+ void SetCondition(StopCondition condition);
- /// Return a pointer to the text of the condition expression.
- ///
- /// \return
- /// A pointer to the condition expression text, or nullptr if no
- // condition has been set.
- const char *GetConditionText(size_t *hash = nullptr) const;
+ /// Return the breakpoint condition.
+ const StopCondition &GetCondition() const;
bool ConditionSaysStop(ExecutionContext &exe_ctx, Status &error);
diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h
index 7bf5457..2f73473 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointOptions.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h
@@ -12,6 +12,7 @@
#include <memory>
#include <string>
+#include "lldb/Breakpoint/StopCondition.h"
#include "lldb/Utility/Baton.h"
#include "lldb/Utility/Flags.h"
#include "lldb/Utility/StringList.h"
@@ -245,18 +246,15 @@ public:
const Baton *GetBaton() const;
// Condition
- /// Set the breakpoint option's condition.
+ /// Set the breakpoint stop condition.
///
/// \param[in] condition
- /// The condition expression to evaluate when the breakpoint is hit.
- void SetCondition(const char *condition);
+ /// The condition to evaluate when the breakpoint is hit.
+ void SetCondition(StopCondition condition);
- /// Return a pointer to the text of the condition expression.
- ///
- /// \return
- /// A pointer to the condition expression text, or nullptr if no
- // condition has been set.
- const char *GetConditionText(size_t *hash = nullptr) const;
+ /// Return the breakpoint condition.
+ const StopCondition &GetCondition() const;
+ StopCondition &GetCondition();
// Enabled/Ignore Count
@@ -390,9 +388,7 @@ private:
/// Thread for which this breakpoint will stop.
std::unique_ptr<ThreadSpec> m_thread_spec_up;
/// The condition to test.
- std::string m_condition_text;
- /// Its hash, so that locations know when the condition is updated.
- size_t m_condition_text_hash;
+ StopCondition m_condition;
/// If set, inject breakpoint condition into process.
bool m_inject_condition;
/// If set, auto-continue from breakpoint.
diff --git a/lldb/include/lldb/Breakpoint/StopCondition.h b/lldb/include/lldb/Breakpoint/StopCondition.h
new file mode 100644
index 0000000..485a615
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/StopCondition.h
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_BREAKPOINT_STOPCONDITION_H
+#define LLDB_BREAKPOINT_STOPCONDITION_H
+
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+class StopCondition {
+public:
+ StopCondition() = default;
+ StopCondition(std::string text,
+ lldb::LanguageType language = lldb::eLanguageTypeUnknown)
+ : m_language(language) {
+ SetText(std::move(text));
+ }
+
+ explicit operator bool() const { return !m_text.empty(); }
+
+ llvm::StringRef GetText() const { return m_text; }
+
+ void SetText(std::string text) {
+ static std::hash<std::string> hasher;
+ m_text = std::move(text);
+ m_hash = hasher(text);
+ }
+
+ size_t GetHash() const { return m_hash; }
+
+ lldb::LanguageType GetLanguage() const { return m_language; }
+
+ void SetLanguage(lldb::LanguageType language) { m_language = language; }
+
+private:
+ /// The condition to test.
+ std::string m_text;
+
+ /// Its hash, so that locations know when the condition is updated.
+ size_t m_hash = 0;
+
+ /// The language for this condition.
+ lldb::LanguageType m_language = lldb::eLanguageTypeUnknown;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_BREAKPOINT_STOPCONDITION_H
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index 397afc1..07c0a2e 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -275,7 +275,7 @@ void SBBreakpoint::SetCondition(const char *condition) {
if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
bkpt_sp->GetTarget().GetAPIMutex());
- bkpt_sp->SetCondition(condition);
+ bkpt_sp->SetCondition(StopCondition(condition));
}
}
@@ -288,7 +288,7 @@ const char *SBBreakpoint::GetCondition() {
std::lock_guard<std::recursive_mutex> guard(
bkpt_sp->GetTarget().GetAPIMutex());
- return ConstString(bkpt_sp->GetConditionText()).GetCString();
+ return ConstString(bkpt_sp->GetCondition().GetText()).GetCString();
}
void SBBreakpoint::SetAutoContinue(bool auto_continue) {
diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp
index 479354a..e786435 100644
--- a/lldb/source/API/SBBreakpointLocation.cpp
+++ b/lldb/source/API/SBBreakpointLocation.cpp
@@ -160,7 +160,7 @@ void SBBreakpointLocation::SetCondition(const char *condition) {
if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
loc_sp->GetTarget().GetAPIMutex());
- loc_sp->SetCondition(condition);
+ loc_sp->SetCondition(StopCondition(condition));
}
}
@@ -173,7 +173,7 @@ const char *SBBreakpointLocation::GetCondition() {
std::lock_guard<std::recursive_mutex> guard(
loc_sp->GetTarget().GetAPIMutex());
- return ConstString(loc_sp->GetConditionText()).GetCString();
+ return ConstString(loc_sp->GetCondition().GetText()).GetCString();
}
void SBBreakpointLocation::SetAutoContinue(bool auto_continue) {
diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp
index 831260d..0b588c3 100644
--- a/lldb/source/API/SBBreakpointName.cpp
+++ b/lldb/source/API/SBBreakpointName.cpp
@@ -303,7 +303,7 @@ void SBBreakpointName::SetCondition(const char *condition) {
std::lock_guard<std::recursive_mutex> guard(
m_impl_up->GetTarget()->GetAPIMutex());
- bp_name->GetOptions().SetCondition(condition);
+ bp_name->GetOptions().SetCondition(StopCondition(condition));
UpdateName(*bp_name);
}
@@ -317,7 +317,8 @@ const char *SBBreakpointName::GetCondition() {
std::lock_guard<std::recursive_mutex> guard(
m_impl_up->GetTarget()->GetAPIMutex());
- return ConstString(bp_name->GetOptions().GetConditionText()).GetCString();
+ return ConstString(bp_name->GetOptions().GetCondition().GetText())
+ .GetCString();
}
void SBBreakpointName::SetAutoContinue(bool auto_continue) {
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp
index ec27a7d..d757bc4 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -440,13 +440,13 @@ const char *Breakpoint::GetQueueName() const {
return m_options.GetThreadSpecNoCreate()->GetQueueName();
}
-void Breakpoint::SetCondition(const char *condition) {
- m_options.SetCondition(condition);
+void Breakpoint::SetCondition(StopCondition condition) {
+ m_options.SetCondition(std::move(condition));
SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged);
}
-const char *Breakpoint::GetConditionText() const {
- return m_options.GetConditionText();
+const StopCondition &Breakpoint::GetCondition() const {
+ return m_options.GetCondition();
}
// This function is used when "baton" doesn't need to be freed
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 7ac9c8f..443d4f5 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -203,14 +203,13 @@ void BreakpointLocation::ClearCallback() {
GetLocationOptions().ClearCallback();
}
-void BreakpointLocation::SetCondition(const char *condition) {
- GetLocationOptions().SetCondition(condition);
+void BreakpointLocation::SetCondition(StopCondition condition) {
+ GetLocationOptions().SetCondition(std::move(condition));
SendBreakpointLocationChangedEvent(eBreakpointEventTypeConditionChanged);
}
-const char *BreakpointLocation::GetConditionText(size_t *hash) const {
- return GetOptionsSpecifyingKind(BreakpointOptions::eCondition)
- .GetConditionText(hash);
+const StopCondition &BreakpointLocation::GetCondition() const {
+ return GetOptionsSpecifyingKind(BreakpointOptions::eCondition).GetCondition();
}
bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
@@ -219,10 +218,9 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
std::lock_guard<std::mutex> guard(m_condition_mutex);
- size_t condition_hash;
- const char *condition_text = GetConditionText(&condition_hash);
+ StopCondition condition = GetCondition();
- if (!condition_text) {
+ if (!condition) {
m_user_expression_sp.reset();
return false;
}
@@ -231,19 +229,22 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
DiagnosticManager diagnostics;
- if (condition_hash != m_condition_hash || !m_user_expression_sp ||
+ if (condition.GetHash() != m_condition_hash || !m_user_expression_sp ||
!m_user_expression_sp->IsParseCacheable() ||
!m_user_expression_sp->MatchesContext(exe_ctx)) {
- LanguageType language = eLanguageTypeUnknown;
- // See if we can figure out the language from the frame, otherwise use the
- // default language:
- CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit();
- if (comp_unit)
- language = comp_unit->GetLanguage();
+ LanguageType language = condition.GetLanguage();
+ if (language == lldb::eLanguageTypeUnknown) {
+ // See if we can figure out the language from the frame, otherwise use the
+ // default language:
+ if (CompileUnit *comp_unit =
+ m_address.CalculateSymbolContextCompileUnit())
+ language = comp_unit->GetLanguage();
+ }
m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
- condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
- EvaluateExpressionOptions(), nullptr, error));
+ condition.GetText(), llvm::StringRef(), language,
+ Expression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
+ error));
if (error.Fail()) {
LLDB_LOGF(log, "Error getting condition expression: %s.",
error.AsCString());
@@ -262,7 +263,7 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
return true;
}
- m_condition_hash = condition_hash;
+ m_condition_hash = condition.GetHash();
}
// We need to make sure the user sees any parse errors in their condition, so
diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp
index 08e48c4..b0b794f 100644
--- a/lldb/source/Breakpoint/BreakpointOptions.cpp
+++ b/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -106,8 +106,8 @@ const char *BreakpointOptions::g_option_names[(
BreakpointOptions::BreakpointOptions(bool all_flags_set)
: m_callback(nullptr), m_baton_is_command_baton(false),
m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false),
- m_ignore_count(0), m_condition_text_hash(0), m_inject_condition(false),
- m_auto_continue(false), m_set_flags(0) {
+ m_ignore_count(0), m_inject_condition(false), m_auto_continue(false),
+ m_set_flags(0) {
if (all_flags_set)
m_set_flags.Set(~((Flags::ValueType)0));
}
@@ -117,11 +117,11 @@ BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
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_hash(0),
+ m_one_shot(one_shot), m_ignore_count(ignore), m_condition(condition),
m_inject_condition(false), m_auto_continue(auto_continue) {
m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eAutoContinue);
if (condition && *condition != '\0') {
- SetCondition(condition);
+ SetCondition(StopCondition(condition));
}
}
@@ -135,8 +135,7 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
if (rhs.m_thread_spec_up != nullptr)
m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
- m_condition_text = rhs.m_condition_text;
- m_condition_text_hash = rhs.m_condition_text_hash;
+ m_condition = rhs.m_condition;
}
// BreakpointOptions assignment operator
@@ -151,8 +150,7 @@ operator=(const BreakpointOptions &rhs) {
m_ignore_count = rhs.m_ignore_count;
if (rhs.m_thread_spec_up != nullptr)
m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
- m_condition_text = rhs.m_condition_text;
- m_condition_text_hash = rhs.m_condition_text_hash;
+ m_condition = rhs.m_condition;
m_inject_condition = rhs.m_inject_condition;
m_auto_continue = rhs.m_auto_continue;
m_set_flags = rhs.m_set_flags;
@@ -187,13 +185,11 @@ void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
if (incoming.m_set_flags.Test(eCondition))
{
// If we're copying over an empty condition, mark it as unset.
- if (incoming.m_condition_text.empty()) {
- m_condition_text.clear();
- m_condition_text_hash = 0;
+ if (!incoming.m_condition) {
+ m_condition = StopCondition();
m_set_flags.Clear(eCondition);
} else {
- m_condition_text = incoming.m_condition_text;
- m_condition_text_hash = incoming.m_condition_text_hash;
+ m_condition = incoming.m_condition;
m_set_flags.Set(eCondition);
}
}
@@ -363,7 +359,7 @@ StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
m_ignore_count);
if (m_set_flags.Test(eCondition))
options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
- m_condition_text);
+ m_condition.GetText());
if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
auto cmd_baton =
@@ -464,29 +460,21 @@ bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
return true;
}
-void BreakpointOptions::SetCondition(const char *condition) {
- if (!condition || condition[0] == '\0') {
- condition = "";
+void BreakpointOptions::SetCondition(StopCondition condition) {
+ if (!condition)
m_set_flags.Clear(eCondition);
- }
else
m_set_flags.Set(eCondition);
- m_condition_text.assign(condition);
- std::hash<std::string> hasher;
- m_condition_text_hash = hasher(m_condition_text);
+ m_condition = std::move(condition);
}
-const char *BreakpointOptions::GetConditionText(size_t *hash) const {
- if (!m_condition_text.empty()) {
- if (hash)
- *hash = m_condition_text_hash;
-
- return m_condition_text.c_str();
- }
- return nullptr;
+const StopCondition &BreakpointOptions::GetCondition() const {
+ return m_condition;
}
+StopCondition &BreakpointOptions::GetCondition() { return m_condition; }
+
const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
return m_thread_spec_up.get();
}
@@ -555,10 +543,10 @@ void BreakpointOptions::GetDescription(Stream *s,
s->GetIndentLevel());
}
}
- if (!m_condition_text.empty()) {
+ if (m_condition) {
if (level != eDescriptionLevelBrief) {
s->EOL();
- s->Printf("Condition: %s\n", m_condition_text.c_str());
+ s->Printf("Condition: %s\n", m_condition.GetText().data());
}
}
}
@@ -652,5 +640,5 @@ void BreakpointOptions::Clear()
m_baton_is_command_baton = false;
m_callback_is_synchronous = false;
m_enabled = false;
- m_condition_text.clear();
+ m_condition = StopCondition();
}
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 2440a7e..38ec375 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -72,7 +72,7 @@ public:
case 'c':
// Normally an empty breakpoint condition marks is as unset. But we need
// to say it was passed in.
- m_bp_opts.SetCondition(option_arg.str().c_str());
+ m_bp_opts.GetCondition().SetText(option_arg.str());
m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
break;
case 'C':
@@ -154,6 +154,21 @@ public:
m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
}
} break;
+ case 'Y': {
+ LanguageType language = Language::GetLanguageTypeFromString(option_arg);
+
+ LanguageSet languages_for_expressions =
+ Language::GetLanguagesSupportingTypeSystemsForExpressions();
+ if (language == eLanguageTypeUnknown)
+ error = Status::FromError(CreateOptionParsingError(
+ option_arg, short_option, long_option, "invalid language"));
+ else if (!languages_for_expressions[language])
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ "no expression support for language"));
+ else
+ m_bp_opts.GetCondition().SetLanguage(language);
+ } break;
default:
llvm_unreachable("Unimplemented option");
}
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index e543566..acb7410 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -95,6 +95,12 @@ let Command = "breakpoint modify" in {
def breakpoint_modify_condition : Option<"condition", "c">, Group<1>,
Arg<"Expression">, Desc<"The breakpoint stops only if this condition "
"expression evaluates to true.">;
+ def breakpoint_modify_condition_language
+ : Option<"condition-language", "Y">,
+ Group<1>,
+ Arg<"Language">,
+ Desc<"Specifies the Language to use when executing the breakpoint's "
+ "condition expression.">;
def breakpoint_modify_auto_continue : Option<"auto-continue", "G">, Group<1>,
Arg<"Boolean">,
Desc<"The breakpoint will auto-continue after running its commands.">;
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 3160446..19f89b8 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -465,7 +465,7 @@ protected:
// should stop, then we'll run the callback for the breakpoint. If
// the callback says we shouldn't stop that will win.
- if (bp_loc_sp->GetConditionText() == nullptr)
+ if (!bp_loc_sp->GetCondition())
actually_hit_any_locations = true;
else {
Status condition_error;
@@ -484,7 +484,7 @@ protected:
strm << "stopped due to an error evaluating condition of "
"breakpoint ";
bp_loc_sp->GetDescription(&strm, eDescriptionLevelBrief);
- strm << ": \"" << bp_loc_sp->GetConditionText() << "\"\n";
+ strm << ": \"" << bp_loc_sp->GetCondition().GetText() << "\"\n";
strm << err_str;
Debugger::ReportError(
diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py b/lldb/test/API/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
index 4e7a8cc..a4c9c49 100644
--- a/lldb/test/API/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
+++ b/lldb/test/API/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
@@ -19,6 +19,16 @@ class BreakpointConditionsTestCase(TestBase):
self.build()
self.breakpoint_conditions(inline=True)
+ def test_breakpoint_condition_and_run_command_language(self):
+ """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'."""
+ self.build()
+ self.breakpoint_conditions(cpp=True)
+
+ def test_breakpoint_condition_inline_and_run_command_language(self):
+ """Exercise breakpoint condition inline with 'breakpoint set'."""
+ self.build()
+ self.breakpoint_conditions(inline=True, cpp=True)
+
@add_test_categories(["pyapi"])
def test_breakpoint_condition_and_python_api(self):
"""Use Python APIs to set breakpoint conditions."""
@@ -42,17 +52,24 @@ class BreakpointConditionsTestCase(TestBase):
"main.c", "// Find the line number of c's parent call here."
)
- def breakpoint_conditions(self, inline=False):
+ def breakpoint_conditions(self, inline=False, cpp=False):
"""Exercise breakpoint condition with 'breakpoint modify -c <expr> id'."""
exe = self.getBuildArtifact("a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+ if cpp:
+ condition = "&val != nullptr && val == 3"
+ cmd_args = " -c '{}' -Y c++".format(condition)
+ else:
+ condition = "val == 3"
+ cmd_args = "-c '{}'".format(condition)
+
if inline:
# Create a breakpoint by function name 'c' and set the condition.
lldbutil.run_break_set_by_symbol(
self,
"c",
- extra_options="-c 'val == 3'",
+ extra_options=cmd_args,
num_expected_locations=1,
sym_exact=True,
)
@@ -63,7 +80,7 @@ class BreakpointConditionsTestCase(TestBase):
)
# And set a condition on the breakpoint to stop on when 'val == 3'.
- self.runCmd("breakpoint modify -c 'val == 3' 1")
+ self.runCmd("breakpoint modify " + cmd_args + " 1")
# Now run the program.
self.runCmd("run", RUN_SUCCEEDED)
@@ -82,7 +99,11 @@ class BreakpointConditionsTestCase(TestBase):
self.expect(
"breakpoint list -f",
BREAKPOINT_HIT_ONCE,
- substrs=["resolved = 1", "Condition: val == 3", "hit count = 1"],
+ substrs=[
+ "resolved = 1",
+ "Condition: {}".format(condition),
+ "hit count = 1",
+ ],
)
# The frame #0 should correspond to main.c:36, the executable statement
diff --git a/lldb/test/Shell/Breakpoint/condition-lang.test b/lldb/test/Shell/Breakpoint/condition-lang.test
new file mode 100644
index 0000000..9a64bf4f
--- /dev/null
+++ b/lldb/test/Shell/Breakpoint/condition-lang.test
@@ -0,0 +1,5 @@
+RUN: not %lldb -b -o 'break set -n foo -c bar -Y bogus' 2>&1 | FileCheck %s --check-prefix INVALID
+INVALID: error: Invalid value ('bogus') for -Y (condition-language): invalid language
+
+RUN: not %lldb -b -o 'break set -n foo -c bar -Y python' 2>&1 | FileCheck %s --check-prefix NOEXPRSUPPORT
+NOEXPRSUPPORT: error: Invalid value ('python') for -Y (condition-language): no expression support for language