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