1 //===-- Watchpoint.cpp ----------------------------------------------------===// 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 #include "lldb/Breakpoint/Watchpoint.h" 10 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" 23 24 using namespace lldb; 25 using namespace lldb_private; 26 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_ignore_count(0), m_being_created(true) { 33 34 if (type && type->IsValid()) 35 m_type = *type; 36 else { 37 // If we don't have a known type, then we force it to unsigned int of the 38 // right size. 39 auto type_system_or_err = 40 target.GetScratchTypeSystemForLanguage(eLanguageTypeC); 41 if (auto err = type_system_or_err.takeError()) { 42 LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err), 43 "Failed to set type: {0}"); 44 } else { 45 if (auto ts = *type_system_or_err) 46 m_type = 47 ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size); 48 else 49 LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err), 50 "Failed to set type: Typesystem is no longer live: {0}"); 51 } 52 } 53 54 // Set the initial value of the watched variable: 55 if (m_target.GetProcessSP()) { 56 ExecutionContext exe_ctx; 57 m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx); 58 CaptureWatchedValue(exe_ctx); 59 } 60 m_being_created = false; 61 } 62 63 Watchpoint::~Watchpoint() = default; 64 65 // This function is used when "baton" doesn't need to be freed 66 void Watchpoint::SetCallback(WatchpointHitCallback callback, void *baton, 67 bool is_synchronous) { 68 // The default "Baton" class will keep a copy of "baton" and won't free or 69 // delete it when it goes goes out of scope. 70 m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton), 71 is_synchronous); 72 73 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged); 74 } 75 76 // This function is used when a baton needs to be freed and therefore is 77 // contained in a "Baton" subclass. 78 void Watchpoint::SetCallback(WatchpointHitCallback callback, 79 const BatonSP &callback_baton_sp, 80 bool is_synchronous) { 81 m_options.SetCallback(callback, callback_baton_sp, is_synchronous); 82 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged); 83 } 84 85 bool Watchpoint::SetupVariableWatchpointDisabler(StackFrameSP frame_sp) const { 86 if (!frame_sp) 87 return false; 88 89 ThreadSP thread_sp = frame_sp->GetThread(); 90 if (!thread_sp) 91 return false; 92 93 uint32_t return_frame_index = 94 thread_sp->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame) + 1; 95 if (return_frame_index >= LLDB_INVALID_FRAME_ID) 96 return false; 97 98 StackFrameSP return_frame_sp( 99 thread_sp->GetStackFrameAtIndex(return_frame_index)); 100 if (!return_frame_sp) 101 return false; 102 103 ExecutionContext exe_ctx(return_frame_sp); 104 TargetSP target_sp = exe_ctx.GetTargetSP(); 105 if (!target_sp) 106 return false; 107 108 Address return_address(return_frame_sp->GetFrameCodeAddress()); 109 lldb::addr_t return_addr = return_address.GetLoadAddress(target_sp.get()); 110 if (return_addr == LLDB_INVALID_ADDRESS) 111 return false; 112 113 BreakpointSP bp_sp = target_sp->CreateBreakpoint( 114 return_addr, /*internal=*/true, /*request_hardware=*/false); 115 if (!bp_sp || !bp_sp->HasResolvedLocations()) 116 return false; 117 118 auto wvc_up = std::make_unique<WatchpointVariableContext>(GetID(), exe_ctx); 119 auto baton_sp = std::make_shared<WatchpointVariableBaton>(std::move(wvc_up)); 120 bp_sp->SetCallback(VariableWatchpointDisabler, baton_sp); 121 bp_sp->SetOneShot(true); 122 bp_sp->SetBreakpointKind("variable watchpoint disabler"); 123 return true; 124 } 125 126 bool Watchpoint::VariableWatchpointDisabler(void *baton, 127 StoppointCallbackContext *context, 128 user_id_t break_id, 129 user_id_t break_loc_id) { 130 assert(baton && "null baton"); 131 if (!baton || !context) 132 return false; 133 134 Log *log = GetLog(LLDBLog::Watchpoints); 135 136 WatchpointVariableContext *wvc = 137 static_cast<WatchpointVariableContext *>(baton); 138 139 LLDB_LOGF(log, "called by breakpoint %" PRIu64 ".%" PRIu64, break_id, 140 break_loc_id); 141 142 if (wvc->watch_id == LLDB_INVALID_WATCH_ID) 143 return false; 144 145 TargetSP target_sp = context->exe_ctx_ref.GetTargetSP(); 146 if (!target_sp) 147 return false; 148 149 ProcessSP process_sp = target_sp->GetProcessSP(); 150 if (!process_sp) 151 return false; 152 153 WatchpointSP watch_sp = 154 target_sp->GetWatchpointList().FindByID(wvc->watch_id); 155 if (!watch_sp) 156 return false; 157 158 if (wvc->exe_ctx == context->exe_ctx_ref) { 159 LLDB_LOGF(log, 160 "callback for watchpoint %" PRId32 161 " matched internal breakpoint execution context", 162 watch_sp->GetID()); 163 process_sp->DisableWatchpoint(watch_sp.get()); 164 return false; 165 } 166 LLDB_LOGF(log, 167 "callback for watchpoint %" PRId32 168 " didn't match internal breakpoint execution context", 169 watch_sp->GetID()); 170 return false; 171 } 172 173 void Watchpoint::ClearCallback() { 174 m_options.ClearCallback(); 175 SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged); 176 } 177 178 void Watchpoint::SetDeclInfo(const std::string &str) { m_decl_str = str; } 179 180 std::string Watchpoint::GetWatchSpec() { return m_watch_spec_str; } 181 182 void Watchpoint::SetWatchSpec(const std::string &str) { 183 m_watch_spec_str = str; 184 } 185 186 bool Watchpoint::IsHardware() const { 187 lldbassert(m_is_hardware || !HardwareRequired()); 188 return m_is_hardware; 189 } 190 191 bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; } 192 193 void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; } 194 195 bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) { 196 ConstString watch_name("$__lldb__watch_value"); 197 m_old_value_sp = m_new_value_sp; 198 Address watch_address(GetLoadAddress()); 199 if (!m_type.IsValid()) { 200 // Don't know how to report new & old values, since we couldn't make a 201 // scalar type for this watchpoint. This works around an assert in 202 // ValueObjectMemory::Create. 203 // FIXME: This should not happen, but if it does in some case we care about, 204 // we can go grab the value raw and print it as unsigned. 205 return false; 206 } 207 m_new_value_sp = ValueObjectMemory::Create( 208 exe_ctx.GetBestExecutionContextScope(), watch_name.GetStringRef(), 209 watch_address, m_type); 210 m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name); 211 return (m_new_value_sp && m_new_value_sp->GetError().Success()); 212 } 213 214 // RETURNS - true if we should stop at this breakpoint, false if we 215 // should continue. 216 217 bool Watchpoint::ShouldStop(StoppointCallbackContext *context) { 218 m_hit_counter.Increment(); 219 220 return IsEnabled(); 221 } 222 223 void Watchpoint::GetDescription(Stream *s, lldb::DescriptionLevel level) { 224 DumpWithLevel(s, level); 225 } 226 227 void Watchpoint::Dump(Stream *s) const { 228 DumpWithLevel(s, lldb::eDescriptionLevelBrief); 229 } 230 231 // If prefix is nullptr, we display the watch id and ignore the prefix 232 // altogether. 233 void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const { 234 if (!prefix) { 235 s->Printf("\nWatchpoint %u hit:", GetID()); 236 prefix = ""; 237 } 238 239 if (m_old_value_sp) { 240 const char *old_value_cstr = m_old_value_sp->GetValueAsCString(); 241 if (old_value_cstr && old_value_cstr[0]) 242 s->Printf("\n%sold value: %s", prefix, old_value_cstr); 243 else { 244 const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString(); 245 if (old_summary_cstr && old_summary_cstr[0]) 246 s->Printf("\n%sold value: %s", prefix, old_summary_cstr); 247 } 248 } 249 250 if (m_new_value_sp) { 251 const char *new_value_cstr = m_new_value_sp->GetValueAsCString(); 252 if (new_value_cstr && new_value_cstr[0]) 253 s->Printf("\n%snew value: %s", prefix, new_value_cstr); 254 else { 255 const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString(); 256 if (new_summary_cstr && new_summary_cstr[0]) 257 s->Printf("\n%snew value: %s", prefix, new_summary_cstr); 258 } 259 } 260 } 261 262 void Watchpoint::DumpWithLevel(Stream *s, 263 lldb::DescriptionLevel description_level) const { 264 if (s == nullptr) 265 return; 266 267 assert(description_level >= lldb::eDescriptionLevelBrief && 268 description_level <= lldb::eDescriptionLevelVerbose); 269 270 s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 271 " size = %u state = %s type = %s%s", 272 GetID(), GetLoadAddress(), m_byte_size, 273 IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "", 274 m_watch_write ? "w" : ""); 275 276 if (description_level >= lldb::eDescriptionLevelFull) { 277 if (!m_decl_str.empty()) 278 s->Printf("\n declare @ '%s'", m_decl_str.c_str()); 279 if (!m_watch_spec_str.empty()) 280 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str()); 281 282 // Dump the snapshots we have taken. 283 DumpSnapshots(s, " "); 284 285 if (GetConditionText()) 286 s->Printf("\n condition = '%s'", GetConditionText()); 287 m_options.GetCallbackDescription(s, description_level); 288 } 289 290 if (description_level >= lldb::eDescriptionLevelVerbose) { 291 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u", 292 GetHardwareIndex(), GetHitCount(), GetIgnoreCount()); 293 } 294 } 295 296 bool Watchpoint::IsEnabled() const { return m_enabled; } 297 298 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before 299 // temporarily disable the watchpoint in order to perform possible watchpoint 300 // actions without triggering further watchpoint events. After the temporary 301 // disabled watchpoint is enabled, we then turn off the ephemeral mode. 302 303 void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral = true; } 304 305 void Watchpoint::TurnOffEphemeralMode() { 306 m_is_ephemeral = false; 307 // Leaving ephemeral mode, reset the m_disabled_count! 308 m_disabled_count = 0; 309 } 310 311 bool Watchpoint::IsDisabledDuringEphemeralMode() { 312 return m_disabled_count > 1 && m_is_ephemeral; 313 } 314 315 void Watchpoint::SetEnabled(bool enabled, bool notify) { 316 if (!enabled) { 317 if (!m_is_ephemeral) 318 SetHardwareIndex(LLDB_INVALID_INDEX32); 319 else 320 ++m_disabled_count; 321 322 // Don't clear the snapshots for now. 323 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while 324 // performing watchpoint actions. 325 } 326 bool changed = enabled != m_enabled; 327 m_enabled = enabled; 328 if (notify && !m_is_ephemeral && changed) 329 SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled 330 : eWatchpointEventTypeDisabled); 331 } 332 333 void Watchpoint::SetWatchpointType(uint32_t type, bool notify) { 334 int old_watch_read = m_watch_read; 335 int old_watch_write = m_watch_write; 336 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0; 337 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0; 338 if (notify && 339 (old_watch_read != m_watch_read || old_watch_write != m_watch_write)) 340 SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged); 341 } 342 343 bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; } 344 345 bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; } 346 347 uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; } 348 349 void Watchpoint::SetIgnoreCount(uint32_t n) { 350 bool changed = m_ignore_count != n; 351 m_ignore_count = n; 352 if (changed) 353 SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged); 354 } 355 356 bool Watchpoint::InvokeCallback(StoppointCallbackContext *context) { 357 return m_options.InvokeCallback(context, GetID()); 358 } 359 360 void Watchpoint::SetCondition(const char *condition) { 361 if (condition == nullptr || condition[0] == '\0') { 362 if (m_condition_up) 363 m_condition_up.reset(); 364 } else { 365 // Pass nullptr for expr_prefix (no translation-unit level definitions). 366 Status error; 367 m_condition_up.reset(m_target.GetUserExpressionForLanguage( 368 condition, llvm::StringRef(), lldb::eLanguageTypeUnknown, 369 UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr, 370 error)); 371 if (error.Fail()) { 372 // FIXME: Log something... 373 m_condition_up.reset(); 374 } 375 } 376 SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged); 377 } 378 379 const char *Watchpoint::GetConditionText() const { 380 if (m_condition_up) 381 return m_condition_up->GetUserText(); 382 else 383 return nullptr; 384 } 385 386 void Watchpoint::SendWatchpointChangedEvent( 387 lldb::WatchpointEventType eventKind) { 388 if (!m_being_created && 389 GetTarget().EventTypeHasListeners( 390 Target::eBroadcastBitWatchpointChanged)) { 391 WatchpointEventData *data = 392 new Watchpoint::WatchpointEventData(eventKind, shared_from_this()); 393 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data); 394 } 395 } 396 397 void Watchpoint::SendWatchpointChangedEvent(WatchpointEventData *data) { 398 if (data == nullptr) 399 return; 400 401 if (!m_being_created && 402 GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 403 GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data); 404 else 405 delete data; 406 } 407 408 Watchpoint::WatchpointEventData::WatchpointEventData( 409 WatchpointEventType sub_type, const WatchpointSP &new_watchpoint_sp) 410 : m_watchpoint_event(sub_type), m_new_watchpoint_sp(new_watchpoint_sp) {} 411 412 Watchpoint::WatchpointEventData::~WatchpointEventData() = default; 413 414 llvm::StringRef Watchpoint::WatchpointEventData::GetFlavorString() { 415 return "Watchpoint::WatchpointEventData"; 416 } 417 418 llvm::StringRef Watchpoint::WatchpointEventData::GetFlavor() const { 419 return WatchpointEventData::GetFlavorString(); 420 } 421 422 WatchpointSP &Watchpoint::WatchpointEventData::GetWatchpoint() { 423 return m_new_watchpoint_sp; 424 } 425 426 WatchpointEventType 427 Watchpoint::WatchpointEventData::GetWatchpointEventType() const { 428 return m_watchpoint_event; 429 } 430 431 void Watchpoint::WatchpointEventData::Dump(Stream *s) const {} 432 433 const Watchpoint::WatchpointEventData * 434 Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event *event) { 435 if (event) { 436 const EventData *event_data = event->GetData(); 437 if (event_data && 438 event_data->GetFlavor() == WatchpointEventData::GetFlavorString()) 439 return static_cast<const WatchpointEventData *>(event->GetData()); 440 } 441 return nullptr; 442 } 443 444 WatchpointEventType 445 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent( 446 const EventSP &event_sp) { 447 const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get()); 448 449 if (data == nullptr) 450 return eWatchpointEventTypeInvalidType; 451 else 452 return data->GetWatchpointEventType(); 453 } 454 455 WatchpointSP Watchpoint::WatchpointEventData::GetWatchpointFromEvent( 456 const EventSP &event_sp) { 457 WatchpointSP wp_sp; 458 459 const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get()); 460 if (data) 461 wp_sp = data->m_new_watchpoint_sp; 462 463 return wp_sp; 464 } 465