1 //===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "lldb/Breakpoint/Watchpoint.h" 15 16 #include "lldb/Breakpoint/StoppointCallbackContext.h" 17 #include "lldb/Core/Stream.h" 18 #include "lldb/Core/Value.h" 19 #include "lldb/Core/ValueObject.h" 20 #include "lldb/Core/ValueObjectMemory.h" 21 #include "lldb/Symbol/ClangASTContext.h" 22 #include "lldb/Target/Process.h" 23 #include "lldb/Target/Target.h" 24 #include "lldb/Target/ThreadSpec.h" 25 #include "lldb/Expression/UserExpression.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, uint32_t size, const CompilerType *type, bool hardware) : 31 StoppointLocation (0, addr, size, hardware), 32 m_target(target), 33 m_enabled(false), 34 m_is_hardware(hardware), 35 m_is_watch_variable(false), 36 m_is_ephemeral(false), 37 m_disabled_count(0), 38 m_watch_read(0), 39 m_watch_write(0), 40 m_watch_was_read(0), 41 m_watch_was_written(0), 42 m_ignore_count(0), 43 m_false_alarms(0), 44 m_decl_str(), 45 m_watch_spec_str(), 46 m_type(), 47 m_error(), 48 m_options (), 49 m_being_created(true) 50 { 51 if (type && type->IsValid()) 52 m_type = *type; 53 else 54 { 55 // If we don't have a known type, then we force it to unsigned int of the right size. 56 ClangASTContext *ast_context = target.GetScratchClangASTContext(); 57 m_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size); 58 } 59 60 // Set the initial value of the watched variable: 61 if (m_target.GetProcessSP()) 62 { 63 ExecutionContext exe_ctx; 64 m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx); 65 CaptureWatchedValue (exe_ctx); 66 } 67 m_being_created = false; 68 } 69 70 Watchpoint::~Watchpoint() = default; 71 72 // This function is used when "baton" doesn't need to be freed 73 void 74 Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous) 75 { 76 // The default "Baton" class will keep a copy of "baton" and won't free 77 // or delete it when it goes goes out of scope. 78 m_options.SetCallback(callback, BatonSP (new Baton(baton)), 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 86 Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous) 87 { 88 m_options.SetCallback(callback, callback_baton_sp, is_synchronous); 89 SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged); 90 } 91 92 void 93 Watchpoint::ClearCallback () 94 { 95 m_options.ClearCallback (); 96 SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged); 97 } 98 99 void 100 Watchpoint::SetDeclInfo (const std::string &str) 101 { 102 m_decl_str = str; 103 } 104 105 std::string 106 Watchpoint::GetWatchSpec() 107 { 108 return m_watch_spec_str; 109 } 110 111 void 112 Watchpoint::SetWatchSpec (const std::string &str) 113 { 114 m_watch_spec_str = str; 115 } 116 117 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware 118 // member field is more accurate. 119 bool 120 Watchpoint::IsHardware () const 121 { 122 return m_is_hardware; 123 } 124 125 bool 126 Watchpoint::IsWatchVariable() const 127 { 128 return m_is_watch_variable; 129 } 130 131 void 132 Watchpoint::SetWatchVariable(bool val) 133 { 134 m_is_watch_variable = val; 135 } 136 137 bool 138 Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx) 139 { 140 ConstString watch_name("$__lldb__watch_value"); 141 m_old_value_sp = m_new_value_sp; 142 Address watch_address(GetLoadAddress()); 143 if (!m_type.IsValid()) 144 { 145 // Don't know how to report new & old values, since we couldn't make a scalar type for this watchpoint. 146 // This works around an assert in ValueObjectMemory::Create. 147 // FIXME: This should not happen, but if it does in some case we care about, 148 // we can go grab the value raw and print it as unsigned. 149 return false; 150 } 151 m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type); 152 m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name); 153 return (m_new_value_sp && m_new_value_sp->GetError().Success()); 154 } 155 156 void 157 Watchpoint::IncrementFalseAlarmsAndReviseHitCount() 158 { 159 ++m_false_alarms; 160 if (m_false_alarms) 161 { 162 if (m_hit_count >= m_false_alarms) 163 { 164 m_hit_count -= m_false_alarms; 165 m_false_alarms = 0; 166 } 167 else 168 { 169 m_false_alarms -= m_hit_count; 170 m_hit_count = 0; 171 } 172 } 173 } 174 175 // RETURNS - true if we should stop at this breakpoint, false if we 176 // should continue. 177 178 bool 179 Watchpoint::ShouldStop (StoppointCallbackContext *context) 180 { 181 IncrementHitCount(); 182 183 if (!IsEnabled()) 184 return false; 185 186 if (GetHitCount() <= GetIgnoreCount()) 187 return false; 188 189 return true; 190 } 191 192 void 193 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level) 194 { 195 DumpWithLevel(s, level); 196 } 197 198 void 199 Watchpoint::Dump(Stream *s) const 200 { 201 DumpWithLevel(s, lldb::eDescriptionLevelBrief); 202 } 203 204 // If prefix is nullptr, we display the watch id and ignore the prefix altogether. 205 void 206 Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const 207 { 208 if (!prefix) 209 { 210 s->Printf("\nWatchpoint %u hit:", GetID()); 211 prefix = ""; 212 } 213 214 if (m_old_value_sp) 215 { 216 const char *old_value_cstr = m_old_value_sp->GetValueAsCString(); 217 if (old_value_cstr && old_value_cstr[0]) 218 s->Printf("\n%sold value: %s", prefix, old_value_cstr); 219 else 220 { 221 const char *old_summary_cstr = m_old_value_sp-> GetSummaryAsCString(); 222 if (old_summary_cstr && old_summary_cstr[0]) 223 s->Printf("\n%sold value: %s", prefix, old_summary_cstr); 224 } 225 } 226 227 if (m_new_value_sp) 228 { 229 const char *new_value_cstr = m_new_value_sp->GetValueAsCString(); 230 if (new_value_cstr && new_value_cstr[0]) 231 s->Printf("\n%snew value: %s", prefix, new_value_cstr); 232 else 233 { 234 const char *new_summary_cstr = m_new_value_sp-> GetSummaryAsCString(); 235 if (new_summary_cstr && new_summary_cstr[0]) 236 s->Printf("\n%snew value: %s", prefix, new_summary_cstr); 237 } 238 } 239 } 240 241 void 242 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const 243 { 244 if (s == nullptr) 245 return; 246 247 assert(description_level >= lldb::eDescriptionLevelBrief && 248 description_level <= lldb::eDescriptionLevelVerbose); 249 250 s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 " size = %u state = %s type = %s%s", 251 GetID(), 252 GetLoadAddress(), 253 m_byte_size, 254 IsEnabled() ? "enabled" : "disabled", 255 m_watch_read ? "r" : "", 256 m_watch_write ? "w" : ""); 257 258 if (description_level >= lldb::eDescriptionLevelFull) { 259 if (!m_decl_str.empty()) 260 s->Printf("\n declare @ '%s'", m_decl_str.c_str()); 261 if (!m_watch_spec_str.empty()) 262 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str()); 263 264 // Dump the snapshots we have taken. 265 DumpSnapshots(s, " "); 266 267 if (GetConditionText()) 268 s->Printf("\n condition = '%s'", GetConditionText()); 269 m_options.GetCallbackDescription(s, description_level); 270 } 271 272 if (description_level >= lldb::eDescriptionLevelVerbose) 273 { 274 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u", 275 GetHardwareIndex(), 276 GetHitCount(), 277 GetIgnoreCount()); 278 } 279 } 280 281 bool 282 Watchpoint::IsEnabled() const 283 { 284 return m_enabled; 285 } 286 287 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint 288 // in order to perform possible watchpoint actions without triggering further watchpoint events. 289 // After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode. 290 291 void 292 Watchpoint::TurnOnEphemeralMode() 293 { 294 m_is_ephemeral = true; 295 } 296 297 void 298 Watchpoint::TurnOffEphemeralMode() 299 { 300 m_is_ephemeral = false; 301 // Leaving ephemeral mode, reset the m_disabled_count! 302 m_disabled_count = 0; 303 } 304 305 bool 306 Watchpoint::IsDisabledDuringEphemeralMode() 307 { 308 return m_disabled_count > 1; 309 } 310 311 void 312 Watchpoint::SetEnabled(bool enabled, bool notify) 313 { 314 if (!enabled) 315 { 316 if (!m_is_ephemeral) 317 SetHardwareIndex(LLDB_INVALID_INDEX32); 318 else 319 ++m_disabled_count; 320 321 // Don't clear the snapshots for now. 322 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions. 323 } 324 bool changed = enabled != m_enabled; 325 m_enabled = enabled; 326 if (notify && !m_is_ephemeral && changed) 327 SendWatchpointChangedEvent (enabled ? eWatchpointEventTypeEnabled : eWatchpointEventTypeDisabled); 328 } 329 330 void 331 Watchpoint::SetWatchpointType (uint32_t type, bool notify) 332 { 333 int old_watch_read = m_watch_read; 334 int old_watch_write = m_watch_write; 335 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0; 336 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0; 337 if (notify && (old_watch_read != m_watch_read || old_watch_write != m_watch_write)) 338 SendWatchpointChangedEvent (eWatchpointEventTypeTypeChanged); 339 } 340 341 bool 342 Watchpoint::WatchpointRead () const 343 { 344 return m_watch_read != 0; 345 } 346 347 bool 348 Watchpoint::WatchpointWrite () const 349 { 350 return m_watch_write != 0; 351 } 352 353 uint32_t 354 Watchpoint::GetIgnoreCount () const 355 { 356 return m_ignore_count; 357 } 358 359 void 360 Watchpoint::SetIgnoreCount (uint32_t n) 361 { 362 bool changed = m_ignore_count != n; 363 m_ignore_count = n; 364 if (changed) 365 SendWatchpointChangedEvent (eWatchpointEventTypeIgnoreChanged); 366 } 367 368 bool 369 Watchpoint::InvokeCallback (StoppointCallbackContext *context) 370 { 371 return m_options.InvokeCallback (context, GetID()); 372 } 373 374 void 375 Watchpoint::SetCondition (const char *condition) 376 { 377 if (condition == nullptr || condition[0] == '\0') 378 { 379 if (m_condition_ap.get()) 380 m_condition_ap.reset(); 381 } 382 else 383 { 384 // Pass nullptr for expr_prefix (no translation-unit level definitions). 385 Error error; 386 m_condition_ap.reset(m_target.GetUserExpressionForLanguage(condition, 387 nullptr, 388 lldb::eLanguageTypeUnknown, 389 UserExpression::eResultTypeAny, 390 error)); 391 if (error.Fail()) 392 { 393 // FIXME: Log something... 394 m_condition_ap.reset(); 395 } 396 } 397 SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged); 398 } 399 400 const char * 401 Watchpoint::GetConditionText () const 402 { 403 if (m_condition_ap.get()) 404 return m_condition_ap->GetUserText(); 405 else 406 return nullptr; 407 } 408 409 void 410 Watchpoint::SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind) 411 { 412 if (!m_being_created 413 && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 414 { 415 WatchpointEventData *data = new Watchpoint::WatchpointEventData (eventKind, shared_from_this()); 416 GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data); 417 } 418 } 419 420 void 421 Watchpoint::SendWatchpointChangedEvent (WatchpointEventData *data) 422 { 423 if (data == nullptr) 424 return; 425 426 if (!m_being_created 427 && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 428 GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data); 429 else 430 delete data; 431 } 432 433 Watchpoint::WatchpointEventData::WatchpointEventData (WatchpointEventType sub_type, 434 const WatchpointSP &new_watchpoint_sp) : 435 EventData (), 436 m_watchpoint_event (sub_type), 437 m_new_watchpoint_sp (new_watchpoint_sp) 438 { 439 } 440 441 Watchpoint::WatchpointEventData::~WatchpointEventData() = default; 442 443 const ConstString & 444 Watchpoint::WatchpointEventData::GetFlavorString () 445 { 446 static ConstString g_flavor ("Watchpoint::WatchpointEventData"); 447 return g_flavor; 448 } 449 450 const ConstString & 451 Watchpoint::WatchpointEventData::GetFlavor () const 452 { 453 return WatchpointEventData::GetFlavorString (); 454 } 455 456 WatchpointSP & 457 Watchpoint::WatchpointEventData::GetWatchpoint () 458 { 459 return m_new_watchpoint_sp; 460 } 461 462 WatchpointEventType 463 Watchpoint::WatchpointEventData::GetWatchpointEventType () const 464 { 465 return m_watchpoint_event; 466 } 467 468 void 469 Watchpoint::WatchpointEventData::Dump (Stream *s) const 470 { 471 } 472 473 const Watchpoint::WatchpointEventData * 474 Watchpoint::WatchpointEventData::GetEventDataFromEvent (const Event *event) 475 { 476 if (event) 477 { 478 const EventData *event_data = event->GetData(); 479 if (event_data && event_data->GetFlavor() == WatchpointEventData::GetFlavorString()) 480 return static_cast <const WatchpointEventData *> (event->GetData()); 481 } 482 return nullptr; 483 } 484 485 WatchpointEventType 486 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (const EventSP &event_sp) 487 { 488 const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get()); 489 490 if (data == nullptr) 491 return eWatchpointEventTypeInvalidType; 492 else 493 return data->GetWatchpointEventType(); 494 } 495 496 WatchpointSP 497 Watchpoint::WatchpointEventData::GetWatchpointFromEvent (const EventSP &event_sp) 498 { 499 WatchpointSP wp_sp; 500 501 const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get()); 502 if (data) 503 wp_sp = data->m_new_watchpoint_sp; 504 505 return wp_sp; 506 } 507