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