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