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