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