Skip to content

[lldb] Support specifying a language for breakpoint conditions #147603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions lldb/include/lldb/Breakpoint/Breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,16 +397,12 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
/// 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.

Expand Down
10 changes: 3 additions & 7 deletions lldb/include/lldb/Breakpoint/BreakpointLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,10 @@ class BreakpointLocation
///
/// \param[in] condition
/// The condition expression to evaluate when the breakpoint is hit.
void SetCondition(const char *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(size_t *hash = nullptr) const;
/// Return the breakpoint condition.
const StopCondition &GetCondition() const;

bool ConditionSaysStop(ExecutionContext &exe_ctx, Status &error);

Expand Down
20 changes: 8 additions & 12 deletions lldb/include/lldb/Breakpoint/BreakpointOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -245,18 +246,15 @@ friend class Breakpoint;
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

Expand Down Expand Up @@ -390,9 +388,7 @@ friend class Breakpoint;
/// 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.
Expand Down
55 changes: 55 additions & 0 deletions lldb/include/lldb/Breakpoint/StopCondition.h
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions lldb/source/API/SBBreakpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand All @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions lldb/source/API/SBBreakpointLocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand All @@ -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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this code was like this before but why do we construct an intermediate ConstString here? Should we remove it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use ConstString at the SB API level to make sure the pointers we had out point into the string pool and remain valid. That way clients don't have to worry about their lifetime which is really an implementation detail.

}

void SBBreakpointLocation::SetAutoContinue(bool auto_continue) {
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/API/SBBreakpointName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions lldb/source/Breakpoint/Breakpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,13 +433,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
Expand Down
37 changes: 19 additions & 18 deletions lldb/source/Breakpoint/BreakpointLocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,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,
Expand All @@ -218,10 +217,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;
}
Expand All @@ -230,19 +228,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());
Expand All @@ -261,7 +262,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
Expand Down
Loading
Loading