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/ClangUserExpression.h" 26 27using namespace lldb; 28using namespace lldb_private; 29 30Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, uint32_t size, const ClangASTType *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 70Watchpoint::~Watchpoint() 71{ 72} 73 74// This function is used when "baton" doesn't need to be freed 75void 76Watchpoint::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. 87void 88Watchpoint::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 94void 95Watchpoint::ClearCallback () 96{ 97 m_options.ClearCallback (); 98 SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged); 99} 100 101void 102Watchpoint::SetDeclInfo (const std::string &str) 103{ 104 m_decl_str = str; 105 return; 106} 107 108std::string 109Watchpoint::GetWatchSpec() 110{ 111 return m_watch_spec_str; 112} 113 114void 115Watchpoint::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. 123bool 124Watchpoint::IsHardware () const 125{ 126 return m_is_hardware; 127} 128 129bool 130Watchpoint::IsWatchVariable() const 131{ 132 return m_is_watch_variable; 133} 134 135void 136Watchpoint::SetWatchVariable(bool val) 137{ 138 m_is_watch_variable = val; 139} 140 141bool 142Watchpoint::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 163void 164Watchpoint::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 185bool 186Watchpoint::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 199void 200Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level) 201{ 202 DumpWithLevel(s, level); 203 return; 204} 205 206void 207Watchpoint::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. 213void 214Watchpoint::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 s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString()); 225 } 226 if (m_new_value_sp) 227 { 228 s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString()); 229 } 230} 231 232void 233Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const 234{ 235 if (s == NULL) 236 return; 237 238 assert(description_level >= lldb::eDescriptionLevelBrief && 239 description_level <= lldb::eDescriptionLevelVerbose); 240 241 s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 " size = %u state = %s type = %s%s", 242 GetID(), 243 GetLoadAddress(), 244 m_byte_size, 245 IsEnabled() ? "enabled" : "disabled", 246 m_watch_read ? "r" : "", 247 m_watch_write ? "w" : ""); 248 249 if (description_level >= lldb::eDescriptionLevelFull) { 250 if (!m_decl_str.empty()) 251 s->Printf("\n declare @ '%s'", m_decl_str.c_str()); 252 if (!m_watch_spec_str.empty()) 253 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str()); 254 255 // Dump the snapshots we have taken. 256 DumpSnapshots(s, " "); 257 258 if (GetConditionText()) 259 s->Printf("\n condition = '%s'", GetConditionText()); 260 m_options.GetCallbackDescription(s, description_level); 261 } 262 263 if (description_level >= lldb::eDescriptionLevelVerbose) 264 { 265 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u", 266 GetHardwareIndex(), 267 GetHitCount(), 268 GetIgnoreCount()); 269 } 270} 271 272bool 273Watchpoint::IsEnabled() const 274{ 275 return m_enabled; 276} 277 278// Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint 279// in order to perform possible watchpoint actions without triggering further watchpoint events. 280// After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode. 281 282void 283Watchpoint::TurnOnEphemeralMode() 284{ 285 m_is_ephemeral = true; 286} 287 288void 289Watchpoint::TurnOffEphemeralMode() 290{ 291 m_is_ephemeral = false; 292 // Leaving ephemeral mode, reset the m_disabled_count! 293 m_disabled_count = 0; 294} 295 296bool 297Watchpoint::IsDisabledDuringEphemeralMode() 298{ 299 return m_disabled_count > 1; 300} 301 302void 303Watchpoint::SetEnabled(bool enabled, bool notify) 304{ 305 if (!enabled) 306 { 307 if (!m_is_ephemeral) 308 SetHardwareIndex(LLDB_INVALID_INDEX32); 309 else 310 ++m_disabled_count; 311 312 // Don't clear the snapshots for now. 313 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions. 314 } 315 bool changed = enabled != m_enabled; 316 m_enabled = enabled; 317 if (notify && !m_is_ephemeral && changed) 318 SendWatchpointChangedEvent (enabled ? eWatchpointEventTypeEnabled : eWatchpointEventTypeDisabled); 319} 320 321void 322Watchpoint::SetWatchpointType (uint32_t type, bool notify) 323{ 324 int old_watch_read = m_watch_read; 325 int old_watch_write = m_watch_write; 326 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0; 327 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0; 328 if (notify && (old_watch_read != m_watch_read || old_watch_write != m_watch_write)) 329 SendWatchpointChangedEvent (eWatchpointEventTypeTypeChanged); 330} 331 332bool 333Watchpoint::WatchpointRead () const 334{ 335 return m_watch_read != 0; 336} 337bool 338Watchpoint::WatchpointWrite () const 339{ 340 return m_watch_write != 0; 341} 342uint32_t 343Watchpoint::GetIgnoreCount () const 344{ 345 return m_ignore_count; 346} 347 348void 349Watchpoint::SetIgnoreCount (uint32_t n) 350{ 351 bool changed = m_ignore_count != n; 352 m_ignore_count = n; 353 if (changed) 354 SendWatchpointChangedEvent (eWatchpointEventTypeIgnoreChanged); 355} 356 357bool 358Watchpoint::InvokeCallback (StoppointCallbackContext *context) 359{ 360 return m_options.InvokeCallback (context, GetID()); 361} 362 363void 364Watchpoint::SetCondition (const char *condition) 365{ 366 if (condition == NULL || condition[0] == '\0') 367 { 368 if (m_condition_ap.get()) 369 m_condition_ap.reset(); 370 } 371 else 372 { 373 // Pass NULL for expr_prefix (no translation-unit level definitions). 374 m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny)); 375 } 376 SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged); 377} 378 379const char * 380Watchpoint::GetConditionText () const 381{ 382 if (m_condition_ap.get()) 383 return m_condition_ap->GetUserText(); 384 else 385 return NULL; 386} 387 388void 389Watchpoint::SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind) 390{ 391 if (!m_being_created 392 && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 393 { 394 WatchpointEventData *data = new Watchpoint::WatchpointEventData (eventKind, shared_from_this()); 395 GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data); 396 } 397} 398 399void 400Watchpoint::SendWatchpointChangedEvent (WatchpointEventData *data) 401{ 402 403 if (data == NULL) 404 return; 405 406 if (!m_being_created 407 && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 408 GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data); 409 else 410 delete data; 411} 412 413Watchpoint::WatchpointEventData::WatchpointEventData (WatchpointEventType sub_type, 414 const WatchpointSP &new_watchpoint_sp) : 415 EventData (), 416 m_watchpoint_event (sub_type), 417 m_new_watchpoint_sp (new_watchpoint_sp) 418{ 419} 420 421Watchpoint::WatchpointEventData::~WatchpointEventData () 422{ 423} 424 425const ConstString & 426Watchpoint::WatchpointEventData::GetFlavorString () 427{ 428 static ConstString g_flavor ("Watchpoint::WatchpointEventData"); 429 return g_flavor; 430} 431 432const ConstString & 433Watchpoint::WatchpointEventData::GetFlavor () const 434{ 435 return WatchpointEventData::GetFlavorString (); 436} 437 438 439WatchpointSP & 440Watchpoint::WatchpointEventData::GetWatchpoint () 441{ 442 return m_new_watchpoint_sp; 443} 444 445WatchpointEventType 446Watchpoint::WatchpointEventData::GetWatchpointEventType () const 447{ 448 return m_watchpoint_event; 449} 450 451void 452Watchpoint::WatchpointEventData::Dump (Stream *s) const 453{ 454} 455 456const Watchpoint::WatchpointEventData * 457Watchpoint::WatchpointEventData::GetEventDataFromEvent (const Event *event) 458{ 459 if (event) 460 { 461 const EventData *event_data = event->GetData(); 462 if (event_data && event_data->GetFlavor() == WatchpointEventData::GetFlavorString()) 463 return static_cast <const WatchpointEventData *> (event->GetData()); 464 } 465 return NULL; 466} 467 468WatchpointEventType 469Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (const EventSP &event_sp) 470{ 471 const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get()); 472 473 if (data == NULL) 474 return eWatchpointEventTypeInvalidType; 475 else 476 return data->GetWatchpointEventType(); 477} 478 479WatchpointSP 480Watchpoint::WatchpointEventData::GetWatchpointFromEvent (const EventSP &event_sp) 481{ 482 WatchpointSP wp_sp; 483 484 const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get()); 485 if (data) 486 wp_sp = data->m_new_watchpoint_sp; 487 488 return wp_sp; 489} 490