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