1 //===-- Watchpoint.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Breakpoint/Watchpoint.h"
11 #include "lldb/Breakpoint/StoppointCallbackContext.h"
12 #include "lldb/Core/Value.h"
13 #include "lldb/Core/ValueObject.h"
14 #include "lldb/Core/ValueObjectMemory.h"
15 #include "lldb/Expression/UserExpression.h"
16 #include "lldb/Symbol/TypeSystem.h"
17 #include "lldb/Target/Process.h"
18 #include "lldb/Target/Target.h"
19 #include "lldb/Target/ThreadSpec.h"
20 #include "lldb/Utility/LLDBLog.h"
21 #include "lldb/Utility/Log.h"
22 #include "lldb/Utility/Stream.h"
25 using namespace lldb_private
;
27 Watchpoint::Watchpoint(Target
&target
, lldb::addr_t addr
, uint32_t size
,
28 const CompilerType
*type
, bool hardware
)
29 : StoppointSite(0, addr
, size
, hardware
), m_target(target
),
30 m_enabled(false), m_is_hardware(hardware
), m_is_watch_variable(false),
31 m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0),
32 m_watch_write(0), m_watch_modify(0), m_ignore_count(0),
33 m_being_created(true) {
35 if (type
&& type
->IsValid())
38 // If we don't have a known type, then we force it to unsigned int of the
40 auto type_system_or_err
=
41 target
.GetScratchTypeSystemForLanguage(eLanguageTypeC
);
42 if (auto err
= type_system_or_err
.takeError()) {
43 LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints
), std::move(err
),
44 "Failed to set type: {0}");
46 if (auto ts
= *type_system_or_err
)
48 ts
->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint
, 8 * size
);
50 LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints
), std::move(err
),
51 "Failed to set type: Typesystem is no longer live: {0}");
55 // Set the initial value of the watched variable:
56 if (m_target
.GetProcessSP()) {
57 ExecutionContext exe_ctx
;
58 m_target
.GetProcessSP()->CalculateExecutionContext(exe_ctx
);
59 CaptureWatchedValue(exe_ctx
);
61 m_being_created
= false;
64 Watchpoint::~Watchpoint() = default;
66 // This function is used when "baton" doesn't need to be freed
67 void Watchpoint::SetCallback(WatchpointHitCallback callback
, void *baton
,
68 bool is_synchronous
) {
69 // The default "Baton" class will keep a copy of "baton" and won't free or
70 // delete it when it goes out of scope.
71 m_options
.SetCallback(callback
, std::make_shared
<UntypedBaton
>(baton
),
74 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged
);
77 // This function is used when a baton needs to be freed and therefore is
78 // contained in a "Baton" subclass.
79 void Watchpoint::SetCallback(WatchpointHitCallback callback
,
80 const BatonSP
&callback_baton_sp
,
81 bool is_synchronous
) {
82 m_options
.SetCallback(callback
, callback_baton_sp
, is_synchronous
);
83 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged
);
86 bool Watchpoint::SetupVariableWatchpointDisabler(StackFrameSP frame_sp
) const {
90 ThreadSP thread_sp
= frame_sp
->GetThread();
94 uint32_t return_frame_index
=
95 thread_sp
->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame
) + 1;
96 if (return_frame_index
>= LLDB_INVALID_FRAME_ID
)
99 StackFrameSP
return_frame_sp(
100 thread_sp
->GetStackFrameAtIndex(return_frame_index
));
101 if (!return_frame_sp
)
104 ExecutionContext
exe_ctx(return_frame_sp
);
105 TargetSP target_sp
= exe_ctx
.GetTargetSP();
109 Address
return_address(return_frame_sp
->GetFrameCodeAddress());
110 lldb::addr_t return_addr
= return_address
.GetLoadAddress(target_sp
.get());
111 if (return_addr
== LLDB_INVALID_ADDRESS
)
114 BreakpointSP bp_sp
= target_sp
->CreateBreakpoint(
115 return_addr
, /*internal=*/true, /*request_hardware=*/false);
116 if (!bp_sp
|| !bp_sp
->HasResolvedLocations())
119 auto wvc_up
= std::make_unique
<WatchpointVariableContext
>(GetID(), exe_ctx
);
120 auto baton_sp
= std::make_shared
<WatchpointVariableBaton
>(std::move(wvc_up
));
121 bp_sp
->SetCallback(VariableWatchpointDisabler
, baton_sp
);
122 bp_sp
->SetOneShot(true);
123 bp_sp
->SetBreakpointKind("variable watchpoint disabler");
127 bool Watchpoint::VariableWatchpointDisabler(void *baton
,
128 StoppointCallbackContext
*context
,
130 user_id_t break_loc_id
) {
131 assert(baton
&& "null baton");
132 if (!baton
|| !context
)
135 Log
*log
= GetLog(LLDBLog::Watchpoints
);
137 WatchpointVariableContext
*wvc
=
138 static_cast<WatchpointVariableContext
*>(baton
);
140 LLDB_LOGF(log
, "called by breakpoint %" PRIu64
".%" PRIu64
, break_id
,
143 if (wvc
->watch_id
== LLDB_INVALID_WATCH_ID
)
146 TargetSP target_sp
= context
->exe_ctx_ref
.GetTargetSP();
150 ProcessSP process_sp
= target_sp
->GetProcessSP();
154 WatchpointSP watch_sp
=
155 target_sp
->GetWatchpointList().FindByID(wvc
->watch_id
);
159 if (wvc
->exe_ctx
== context
->exe_ctx_ref
) {
161 "callback for watchpoint %" PRId32
162 " matched internal breakpoint execution context",
164 process_sp
->DisableWatchpoint(watch_sp
.get());
168 "callback for watchpoint %" PRId32
169 " didn't match internal breakpoint execution context",
174 void Watchpoint::ClearCallback() {
175 m_options
.ClearCallback();
176 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged
);
179 void Watchpoint::SetDeclInfo(const std::string
&str
) { m_decl_str
= str
; }
181 std::string
Watchpoint::GetWatchSpec() { return m_watch_spec_str
; }
183 void Watchpoint::SetWatchSpec(const std::string
&str
) {
184 m_watch_spec_str
= str
;
187 bool Watchpoint::IsHardware() const {
188 lldbassert(m_is_hardware
|| !HardwareRequired());
189 return m_is_hardware
;
192 bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable
; }
194 void Watchpoint::SetWatchVariable(bool val
) { m_is_watch_variable
= val
; }
196 bool Watchpoint::CaptureWatchedValue(const ExecutionContext
&exe_ctx
) {
197 ConstString
g_watch_name("$__lldb__watch_value");
198 m_old_value_sp
= m_new_value_sp
;
199 Address
watch_address(GetLoadAddress());
200 if (!m_type
.IsValid()) {
201 // Don't know how to report new & old values, since we couldn't make a
202 // scalar type for this watchpoint. This works around an assert in
203 // ValueObjectMemory::Create.
204 // FIXME: This should not happen, but if it does in some case we care about,
205 // we can go grab the value raw and print it as unsigned.
208 m_new_value_sp
= ValueObjectMemory::Create(
209 exe_ctx
.GetBestExecutionContextScope(), g_watch_name
.GetStringRef(),
210 watch_address
, m_type
);
211 m_new_value_sp
= m_new_value_sp
->CreateConstantValue(g_watch_name
);
212 return (m_new_value_sp
&& m_new_value_sp
->GetError().Success());
215 bool Watchpoint::WatchedValueReportable(const ExecutionContext
&exe_ctx
) {
216 if (!m_watch_modify
|| m_watch_read
)
218 if (!m_type
.IsValid())
221 ConstString
g_watch_name("$__lldb__watch_value");
222 Address
watch_address(GetLoadAddress());
223 ValueObjectSP newest_valueobj_sp
= ValueObjectMemory::Create(
224 exe_ctx
.GetBestExecutionContextScope(), g_watch_name
.GetStringRef(),
225 watch_address
, m_type
);
226 newest_valueobj_sp
= newest_valueobj_sp
->CreateConstantValue(g_watch_name
);
229 DataExtractor new_data
;
230 DataExtractor old_data
;
232 newest_valueobj_sp
->GetData(new_data
, error
);
235 m_new_value_sp
->GetData(old_data
, error
);
239 if (new_data
.GetByteSize() != old_data
.GetByteSize() ||
240 new_data
.GetByteSize() == 0)
243 if (memcmp(new_data
.GetDataStart(), old_data
.GetDataStart(),
244 old_data
.GetByteSize()) == 0)
245 return false; // Value has not changed, user requested modify watchpoint
250 // RETURNS - true if we should stop at this breakpoint, false if we
253 bool Watchpoint::ShouldStop(StoppointCallbackContext
*context
) {
254 m_hit_counter
.Increment();
259 void Watchpoint::GetDescription(Stream
*s
, lldb::DescriptionLevel level
) {
260 DumpWithLevel(s
, level
);
263 void Watchpoint::Dump(Stream
*s
) const {
264 DumpWithLevel(s
, lldb::eDescriptionLevelBrief
);
267 // If prefix is nullptr, we display the watch id and ignore the prefix
269 void Watchpoint::DumpSnapshots(Stream
*s
, const char *prefix
) const {
271 s
->Printf("\nWatchpoint %u hit:", GetID());
275 if (m_old_value_sp
) {
276 const char *old_value_cstr
= m_old_value_sp
->GetValueAsCString();
277 if (old_value_cstr
&& old_value_cstr
[0])
278 s
->Printf("\n%sold value: %s", prefix
, old_value_cstr
);
280 const char *old_summary_cstr
= m_old_value_sp
->GetSummaryAsCString();
281 if (old_summary_cstr
&& old_summary_cstr
[0])
282 s
->Printf("\n%sold value: %s", prefix
, old_summary_cstr
);
286 if (m_new_value_sp
) {
287 const char *new_value_cstr
= m_new_value_sp
->GetValueAsCString();
288 if (new_value_cstr
&& new_value_cstr
[0])
289 s
->Printf("\n%snew value: %s", prefix
, new_value_cstr
);
291 const char *new_summary_cstr
= m_new_value_sp
->GetSummaryAsCString();
292 if (new_summary_cstr
&& new_summary_cstr
[0])
293 s
->Printf("\n%snew value: %s", prefix
, new_summary_cstr
);
298 void Watchpoint::DumpWithLevel(Stream
*s
,
299 lldb::DescriptionLevel description_level
) const {
303 assert(description_level
>= lldb::eDescriptionLevelBrief
&&
304 description_level
<= lldb::eDescriptionLevelVerbose
);
306 s
->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
307 " size = %u state = %s type = %s%s%s",
308 GetID(), GetLoadAddress(), m_byte_size
,
309 IsEnabled() ? "enabled" : "disabled", m_watch_read
? "r" : "",
310 m_watch_write
? "w" : "", m_watch_modify
? "m" : "");
312 if (description_level
>= lldb::eDescriptionLevelFull
) {
313 if (!m_decl_str
.empty())
314 s
->Printf("\n declare @ '%s'", m_decl_str
.c_str());
315 if (!m_watch_spec_str
.empty())
316 s
->Printf("\n watchpoint spec = '%s'", m_watch_spec_str
.c_str());
318 // Dump the snapshots we have taken.
319 DumpSnapshots(s
, " ");
321 if (GetConditionText())
322 s
->Printf("\n condition = '%s'", GetConditionText());
323 m_options
.GetCallbackDescription(s
, description_level
);
326 if (description_level
>= lldb::eDescriptionLevelVerbose
) {
327 s
->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
328 GetHardwareIndex(), GetHitCount(), GetIgnoreCount());
332 bool Watchpoint::IsEnabled() const { return m_enabled
; }
334 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
335 // temporarily disable the watchpoint in order to perform possible watchpoint
336 // actions without triggering further watchpoint events. After the temporary
337 // disabled watchpoint is enabled, we then turn off the ephemeral mode.
339 void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral
= true; }
341 void Watchpoint::TurnOffEphemeralMode() {
342 m_is_ephemeral
= false;
343 // Leaving ephemeral mode, reset the m_disabled_count!
344 m_disabled_count
= 0;
347 bool Watchpoint::IsDisabledDuringEphemeralMode() {
348 return m_disabled_count
> 1 && m_is_ephemeral
;
351 void Watchpoint::SetEnabled(bool enabled
, bool notify
) {
354 SetHardwareIndex(LLDB_INVALID_INDEX32
);
358 // Don't clear the snapshots for now.
359 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while
360 // performing watchpoint actions.
362 bool changed
= enabled
!= m_enabled
;
364 if (notify
&& !m_is_ephemeral
&& changed
)
365 SendWatchpointChangedEvent(enabled
? eWatchpointEventTypeEnabled
366 : eWatchpointEventTypeDisabled
);
369 void Watchpoint::SetWatchpointType(uint32_t type
, bool notify
) {
370 int old_watch_read
= m_watch_read
;
371 int old_watch_write
= m_watch_write
;
372 int old_watch_modify
= m_watch_modify
;
373 m_watch_read
= (type
& LLDB_WATCH_TYPE_READ
) != 0;
374 m_watch_write
= (type
& LLDB_WATCH_TYPE_WRITE
) != 0;
375 m_watch_modify
= (type
& LLDB_WATCH_TYPE_MODIFY
) != 0;
377 (old_watch_read
!= m_watch_read
|| old_watch_write
!= m_watch_write
||
378 old_watch_modify
!= m_watch_modify
))
379 SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged
);
382 bool Watchpoint::WatchpointRead() const { return m_watch_read
!= 0; }
384 bool Watchpoint::WatchpointWrite() const { return m_watch_write
!= 0; }
386 bool Watchpoint::WatchpointModify() const { return m_watch_modify
!= 0; }
388 uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count
; }
390 void Watchpoint::SetIgnoreCount(uint32_t n
) {
391 bool changed
= m_ignore_count
!= n
;
394 SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged
);
397 bool Watchpoint::InvokeCallback(StoppointCallbackContext
*context
) {
398 return m_options
.InvokeCallback(context
, GetID());
401 void Watchpoint::SetCondition(const char *condition
) {
402 if (condition
== nullptr || condition
[0] == '\0') {
404 m_condition_up
.reset();
406 // Pass nullptr for expr_prefix (no translation-unit level definitions).
408 m_condition_up
.reset(m_target
.GetUserExpressionForLanguage(
409 condition
, llvm::StringRef(), lldb::eLanguageTypeUnknown
,
410 UserExpression::eResultTypeAny
, EvaluateExpressionOptions(), nullptr,
413 // FIXME: Log something...
414 m_condition_up
.reset();
417 SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged
);
420 const char *Watchpoint::GetConditionText() const {
422 return m_condition_up
->GetUserText();
427 void Watchpoint::SendWatchpointChangedEvent(
428 lldb::WatchpointEventType eventKind
) {
429 if (!m_being_created
&&
430 GetTarget().EventTypeHasListeners(
431 Target::eBroadcastBitWatchpointChanged
)) {
432 WatchpointEventData
*data
=
433 new Watchpoint::WatchpointEventData(eventKind
, shared_from_this());
434 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged
, data
);
438 void Watchpoint::SendWatchpointChangedEvent(WatchpointEventData
*data
) {
442 if (!m_being_created
&&
443 GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged
))
444 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged
, data
);
449 Watchpoint::WatchpointEventData::WatchpointEventData(
450 WatchpointEventType sub_type
, const WatchpointSP
&new_watchpoint_sp
)
451 : m_watchpoint_event(sub_type
), m_new_watchpoint_sp(new_watchpoint_sp
) {}
453 Watchpoint::WatchpointEventData::~WatchpointEventData() = default;
455 llvm::StringRef
Watchpoint::WatchpointEventData::GetFlavorString() {
456 return "Watchpoint::WatchpointEventData";
459 llvm::StringRef
Watchpoint::WatchpointEventData::GetFlavor() const {
460 return WatchpointEventData::GetFlavorString();
463 WatchpointSP
&Watchpoint::WatchpointEventData::GetWatchpoint() {
464 return m_new_watchpoint_sp
;
468 Watchpoint::WatchpointEventData::GetWatchpointEventType() const {
469 return m_watchpoint_event
;
472 void Watchpoint::WatchpointEventData::Dump(Stream
*s
) const {}
474 const Watchpoint::WatchpointEventData
*
475 Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event
*event
) {
477 const EventData
*event_data
= event
->GetData();
479 event_data
->GetFlavor() == WatchpointEventData::GetFlavorString())
480 return static_cast<const WatchpointEventData
*>(event
->GetData());
486 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
487 const EventSP
&event_sp
) {
488 const WatchpointEventData
*data
= GetEventDataFromEvent(event_sp
.get());
491 return eWatchpointEventTypeInvalidType
;
493 return data
->GetWatchpointEventType();
496 WatchpointSP
Watchpoint::WatchpointEventData::GetWatchpointFromEvent(
497 const EventSP
&event_sp
) {
500 const WatchpointEventData
*data
= GetEventDataFromEvent(event_sp
.get());
502 wp_sp
= data
->m_new_watchpoint_sp
;