Skip to content

Commit fac9c09

Browse files
committed
[lldb] Support specifying a language for breakpoint conditions
LLDB breakpoint conditions take an expression that's evaluated using the language of the code where the breakpoint is located. Users have asked to have an option to tell it to evaluate the expression in a specific language. This is feature is especially helpful for Swift, for example for a condition based on the value in memory at an offset from a register. Such a condition is pretty difficult to write in Swift, but easy in C. This PR adds a new argument (-Y) to specify the language of the condition expression. We can't reuse the current -L option, since you might want to break on only Swift symbols, but run a C expression there as per the example above. rdar://146119507
1 parent 0032148 commit fac9c09

File tree

14 files changed

+156
-96
lines changed

14 files changed

+156
-96
lines changed

lldb/include/lldb/Breakpoint/Breakpoint.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -397,16 +397,12 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
397397
/// Set the breakpoint's condition.
398398
///
399399
/// \param[in] condition
400-
/// The condition expression to evaluate when the breakpoint is hit.
401-
/// Pass in nullptr to clear the condition.
402-
void SetCondition(const char *condition);
400+
/// The condition to evaluate when the breakpoint is hit.
401+
/// Pass in an empty condition to clear the condition.
402+
void SetCondition(StopCondition condition);
403403

404-
/// Return a pointer to the text of the condition expression.
405-
///
406-
/// \return
407-
/// A pointer to the condition expression text, or nullptr if no
408-
// condition has been set.
409-
const char *GetConditionText() const;
404+
/// Return the breakpoint condition.
405+
const StopCondition &GetCondition() const;
410406

411407
// The next section are various utility functions.
412408

lldb/include/lldb/Breakpoint/BreakpointLocation.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,10 @@ class BreakpointLocation
129129
///
130130
/// \param[in] condition
131131
/// The condition expression to evaluate when the breakpoint is hit.
132-
void SetCondition(const char *condition);
132+
void SetCondition(StopCondition condition);
133133

134-
/// Return a pointer to the text of the condition expression.
135-
///
136-
/// \return
137-
/// A pointer to the condition expression text, or nullptr if no
138-
// condition has been set.
139-
const char *GetConditionText(size_t *hash = nullptr) const;
134+
/// Return the breakpoint condition.
135+
const StopCondition &GetCondition() const;
140136

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

lldb/include/lldb/Breakpoint/BreakpointOptions.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <memory>
1313
#include <string>
1414

15+
#include "lldb/Breakpoint/StopCondition.h"
1516
#include "lldb/Utility/Baton.h"
1617
#include "lldb/Utility/Flags.h"
1718
#include "lldb/Utility/StringList.h"
@@ -245,18 +246,15 @@ friend class Breakpoint;
245246
const Baton *GetBaton() const;
246247

247248
// Condition
248-
/// Set the breakpoint option's condition.
249+
/// Set the breakpoint stop condition.
249250
///
250251
/// \param[in] condition
251-
/// The condition expression to evaluate when the breakpoint is hit.
252-
void SetCondition(const char *condition);
252+
/// The condition to evaluate when the breakpoint is hit.
253+
void SetCondition(StopCondition condition);
253254

254-
/// Return a pointer to the text of the condition expression.
255-
///
256-
/// \return
257-
/// A pointer to the condition expression text, or nullptr if no
258-
// condition has been set.
259-
const char *GetConditionText(size_t *hash = nullptr) const;
255+
/// Return the breakpoint condition.
256+
const StopCondition &GetCondition() const;
257+
StopCondition &GetCondition();
260258

261259
// Enabled/Ignore Count
262260

@@ -390,9 +388,7 @@ friend class Breakpoint;
390388
/// Thread for which this breakpoint will stop.
391389
std::unique_ptr<ThreadSpec> m_thread_spec_up;
392390
/// The condition to test.
393-
std::string m_condition_text;
394-
/// Its hash, so that locations know when the condition is updated.
395-
size_t m_condition_text_hash;
391+
StopCondition m_condition;
396392
/// If set, inject breakpoint condition into process.
397393
bool m_inject_condition;
398394
/// If set, auto-continue from breakpoint.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_BREAKPOINT_STOPCONDITION_H
10+
#define LLDB_BREAKPOINT_STOPCONDITION_H
11+
12+
#include "lldb/lldb-private.h"
13+
14+
namespace lldb_private {
15+
16+
class StopCondition {
17+
public:
18+
StopCondition(std::string text = "",
19+
lldb::LanguageType language = lldb::eLanguageTypeUnknown)
20+
: m_language(language) {
21+
SetText(text);
22+
}
23+
24+
operator bool() const { return !m_text.empty(); }
25+
26+
const std::string &GetText() const { return m_text; }
27+
28+
void SetText(std::string text) {
29+
static std::hash<std::string> hasher;
30+
m_text = std::move(text);
31+
m_hash = hasher(text);
32+
}
33+
34+
size_t GetHash() const { return m_hash; }
35+
36+
lldb::LanguageType GetLanguage() const { return m_language; }
37+
38+
void SetLanguage(lldb::LanguageType language) { m_language = language; }
39+
40+
private:
41+
/// The condition to test.
42+
std::string m_text;
43+
44+
/// Its hash, so that locations know when the condition is updated.
45+
size_t m_hash = 0;
46+
47+
/// The language for this condition.
48+
lldb::LanguageType m_language = lldb::eLanguageTypeUnknown;
49+
};
50+
51+
} // namespace lldb_private
52+
53+
#endif // LLDB_BREAKPOINT_STOPCONDITION_H

lldb/source/API/SBBreakpoint.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ void SBBreakpoint::SetCondition(const char *condition) {
275275
if (bkpt_sp) {
276276
std::lock_guard<std::recursive_mutex> guard(
277277
bkpt_sp->GetTarget().GetAPIMutex());
278-
bkpt_sp->SetCondition(condition);
278+
bkpt_sp->SetCondition(StopCondition(condition));
279279
}
280280
}
281281

@@ -288,7 +288,7 @@ const char *SBBreakpoint::GetCondition() {
288288

289289
std::lock_guard<std::recursive_mutex> guard(
290290
bkpt_sp->GetTarget().GetAPIMutex());
291-
return ConstString(bkpt_sp->GetConditionText()).GetCString();
291+
return ConstString(bkpt_sp->GetCondition().GetText()).GetCString();
292292
}
293293

294294
void SBBreakpoint::SetAutoContinue(bool auto_continue) {

lldb/source/API/SBBreakpointLocation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void SBBreakpointLocation::SetCondition(const char *condition) {
160160
if (loc_sp) {
161161
std::lock_guard<std::recursive_mutex> guard(
162162
loc_sp->GetTarget().GetAPIMutex());
163-
loc_sp->SetCondition(condition);
163+
loc_sp->SetCondition(StopCondition(condition));
164164
}
165165
}
166166

@@ -173,7 +173,7 @@ const char *SBBreakpointLocation::GetCondition() {
173173

174174
std::lock_guard<std::recursive_mutex> guard(
175175
loc_sp->GetTarget().GetAPIMutex());
176-
return ConstString(loc_sp->GetConditionText()).GetCString();
176+
return ConstString(loc_sp->GetCondition().GetText()).GetCString();
177177
}
178178

179179
void SBBreakpointLocation::SetAutoContinue(bool auto_continue) {

lldb/source/API/SBBreakpointName.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ void SBBreakpointName::SetCondition(const char *condition) {
303303
std::lock_guard<std::recursive_mutex> guard(
304304
m_impl_up->GetTarget()->GetAPIMutex());
305305

306-
bp_name->GetOptions().SetCondition(condition);
306+
bp_name->GetOptions().SetCondition(StopCondition(condition));
307307
UpdateName(*bp_name);
308308
}
309309

@@ -317,7 +317,8 @@ const char *SBBreakpointName::GetCondition() {
317317
std::lock_guard<std::recursive_mutex> guard(
318318
m_impl_up->GetTarget()->GetAPIMutex());
319319

320-
return ConstString(bp_name->GetOptions().GetConditionText()).GetCString();
320+
return ConstString(bp_name->GetOptions().GetCondition().GetText())
321+
.GetCString();
321322
}
322323

323324
void SBBreakpointName::SetAutoContinue(bool auto_continue) {

lldb/source/Breakpoint/Breakpoint.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -433,13 +433,13 @@ const char *Breakpoint::GetQueueName() const {
433433
return m_options.GetThreadSpecNoCreate()->GetQueueName();
434434
}
435435

436-
void Breakpoint::SetCondition(const char *condition) {
437-
m_options.SetCondition(condition);
436+
void Breakpoint::SetCondition(StopCondition condition) {
437+
m_options.SetCondition(std::move(condition));
438438
SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged);
439439
}
440440

441-
const char *Breakpoint::GetConditionText() const {
442-
return m_options.GetConditionText();
441+
const StopCondition &Breakpoint::GetCondition() const {
442+
return m_options.GetCondition();
443443
}
444444

445445
// This function is used when "baton" doesn't need to be freed

lldb/source/Breakpoint/BreakpointLocation.cpp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,13 @@ void BreakpointLocation::ClearCallback() {
202202
GetLocationOptions().ClearCallback();
203203
}
204204

205-
void BreakpointLocation::SetCondition(const char *condition) {
206-
GetLocationOptions().SetCondition(condition);
205+
void BreakpointLocation::SetCondition(StopCondition condition) {
206+
GetLocationOptions().SetCondition(std::move(condition));
207207
SendBreakpointLocationChangedEvent(eBreakpointEventTypeConditionChanged);
208208
}
209209

210-
const char *BreakpointLocation::GetConditionText(size_t *hash) const {
211-
return GetOptionsSpecifyingKind(BreakpointOptions::eCondition)
212-
.GetConditionText(hash);
210+
const StopCondition &BreakpointLocation::GetCondition() const {
211+
return GetOptionsSpecifyingKind(BreakpointOptions::eCondition).GetCondition();
213212
}
214213

215214
bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
@@ -218,10 +217,9 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
218217

219218
std::lock_guard<std::mutex> guard(m_condition_mutex);
220219

221-
size_t condition_hash;
222-
const char *condition_text = GetConditionText(&condition_hash);
220+
StopCondition condition = GetCondition();
223221

224-
if (!condition_text) {
222+
if (!condition) {
225223
m_user_expression_sp.reset();
226224
return false;
227225
}
@@ -230,19 +228,22 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
230228

231229
DiagnosticManager diagnostics;
232230

233-
if (condition_hash != m_condition_hash || !m_user_expression_sp ||
231+
if (condition.GetHash() != m_condition_hash || !m_user_expression_sp ||
234232
!m_user_expression_sp->IsParseCacheable() ||
235233
!m_user_expression_sp->MatchesContext(exe_ctx)) {
236-
LanguageType language = eLanguageTypeUnknown;
237-
// See if we can figure out the language from the frame, otherwise use the
238-
// default language:
239-
CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit();
240-
if (comp_unit)
241-
language = comp_unit->GetLanguage();
234+
LanguageType language = condition.GetLanguage();
235+
if (language == lldb::eLanguageTypeUnknown) {
236+
// See if we can figure out the language from the frame, otherwise use the
237+
// default language:
238+
if (CompileUnit *comp_unit =
239+
m_address.CalculateSymbolContextCompileUnit())
240+
language = comp_unit->GetLanguage();
241+
}
242242

243243
m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
244-
condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
245-
EvaluateExpressionOptions(), nullptr, error));
244+
condition.GetText(), llvm::StringRef(), language,
245+
Expression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
246+
error));
246247
if (error.Fail()) {
247248
LLDB_LOGF(log, "Error getting condition expression: %s.",
248249
error.AsCString());
@@ -261,7 +262,7 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
261262
return true;
262263
}
263264

264-
m_condition_hash = condition_hash;
265+
m_condition_hash = condition.GetHash();
265266
}
266267

267268
// We need to make sure the user sees any parse errors in their condition, so

0 commit comments

Comments
 (0)