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/Target/Process.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Target/ThreadSpec.h" 21 #include "lldb/Expression/ClangUserExpression.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 Watchpoint::Watchpoint (lldb::addr_t addr, size_t size, bool hardware) : 27 StoppointLocation (0, addr, size, hardware), 28 m_target(NULL), 29 m_enabled(false), 30 m_is_hardware(hardware), 31 m_is_watch_variable(false), 32 m_is_ephemeral(false), 33 m_disabled_count(0), 34 m_watch_read(0), 35 m_watch_write(0), 36 m_watch_was_read(0), 37 m_watch_was_written(0), 38 m_ignore_count(0), 39 m_false_alarms(0), 40 m_decl_str(), 41 m_watch_spec_str(), 42 m_snapshot_old_str(), 43 m_snapshot_new_str(), 44 m_snapshot_old_val(0), 45 m_snapshot_new_val(0), 46 m_error(), 47 m_options () 48 { 49 } 50 51 Watchpoint::~Watchpoint() 52 { 53 } 54 55 // This function is used when "baton" doesn't need to be freed 56 void 57 Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous) 58 { 59 // The default "Baton" class will keep a copy of "baton" and won't free 60 // or delete it when it goes goes out of scope. 61 m_options.SetCallback(callback, BatonSP (new Baton(baton)), 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 69 Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous) 70 { 71 m_options.SetCallback(callback, callback_baton_sp, is_synchronous); 72 } 73 74 void 75 Watchpoint::ClearCallback () 76 { 77 m_options.ClearCallback (); 78 } 79 80 void 81 Watchpoint::SetDeclInfo (const std::string &str) 82 { 83 m_decl_str = str; 84 return; 85 } 86 87 std::string 88 Watchpoint::GetWatchSpec() 89 { 90 return m_watch_spec_str; 91 } 92 93 void 94 Watchpoint::SetWatchSpec (const std::string &str) 95 { 96 m_watch_spec_str = str; 97 return; 98 } 99 100 // Strip at most one character from the end of the string. 101 static inline std::string 102 RStripOnce(const std::string &str, const char c) 103 { 104 std::string res = str; 105 size_t len = res.length(); 106 if (len && res.at(len - 1) == '\n') 107 res.resize(len - 1); 108 return res; 109 } 110 111 std::string 112 Watchpoint::GetOldSnapshot() const 113 { 114 return m_snapshot_old_str; 115 } 116 117 void 118 Watchpoint::SetOldSnapshot (const std::string &str) 119 { 120 m_snapshot_old_str = RStripOnce(str, '\n'); 121 } 122 123 std::string 124 Watchpoint::GetNewSnapshot() const 125 { 126 return m_snapshot_new_str; 127 } 128 129 void 130 Watchpoint::SetNewSnapshot (const std::string &str) 131 { 132 m_snapshot_old_str = m_snapshot_new_str; 133 m_snapshot_new_str = RStripOnce(str, '\n'); 134 } 135 136 uint64_t 137 Watchpoint::GetOldSnapshotVal() const 138 { 139 return m_snapshot_old_val; 140 } 141 142 void 143 Watchpoint::SetOldSnapshotVal (uint64_t val) 144 { 145 m_snapshot_old_val = val; 146 return; 147 } 148 149 uint64_t 150 Watchpoint::GetNewSnapshotVal() const 151 { 152 return m_snapshot_new_val; 153 } 154 155 void 156 Watchpoint::SetNewSnapshotVal (uint64_t val) 157 { 158 m_snapshot_old_val = m_snapshot_new_val; 159 m_snapshot_new_val = val; 160 return; 161 } 162 163 void 164 Watchpoint::ClearSnapshots() 165 { 166 m_snapshot_old_str.clear(); 167 m_snapshot_new_str.clear(); 168 m_snapshot_old_val = 0; 169 m_snapshot_new_val = 0; 170 } 171 172 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware 173 // member field is more accurate. 174 bool 175 Watchpoint::IsHardware () const 176 { 177 return m_is_hardware; 178 } 179 180 bool 181 Watchpoint::IsWatchVariable() const 182 { 183 return m_is_watch_variable; 184 } 185 186 void 187 Watchpoint::SetWatchVariable(bool val) 188 { 189 m_is_watch_variable = val; 190 } 191 192 void 193 Watchpoint::IncrementFalseAlarmsAndReviseHitCount() 194 { 195 ++m_false_alarms; 196 if (m_false_alarms) 197 { 198 if (m_hit_count >= m_false_alarms) 199 { 200 m_hit_count -= m_false_alarms; 201 m_false_alarms = 0; 202 } 203 else 204 { 205 m_false_alarms -= m_hit_count; 206 m_hit_count = 0; 207 } 208 } 209 } 210 211 // RETURNS - true if we should stop at this breakpoint, false if we 212 // should continue. 213 214 bool 215 Watchpoint::ShouldStop (StoppointCallbackContext *context) 216 { 217 IncrementHitCount(); 218 219 if (!IsEnabled()) 220 return false; 221 222 if (GetHitCount() <= GetIgnoreCount()) 223 return false; 224 225 return true; 226 } 227 228 void 229 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level) 230 { 231 DumpWithLevel(s, level); 232 return; 233 } 234 235 void 236 Watchpoint::Dump(Stream *s) const 237 { 238 DumpWithLevel(s, lldb::eDescriptionLevelBrief); 239 } 240 241 // If prefix is NULL, we display the watch id and ignore the prefix altogether. 242 void 243 Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const 244 { 245 if (!prefix) 246 { 247 s->Printf("\nWatchpoint %u hit:", GetID()); 248 prefix = ""; 249 } 250 251 if (IsWatchVariable()) 252 { 253 if (!m_snapshot_old_str.empty()) 254 s->Printf("\n%sold value: %s", prefix, m_snapshot_old_str.c_str()); 255 if (!m_snapshot_new_str.empty()) 256 s->Printf("\n%snew value: %s", prefix, m_snapshot_new_str.c_str()); 257 } 258 else 259 { 260 uint32_t num_hex_digits = GetByteSize() * 2; 261 s->Printf("\n%sold value: 0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_old_val); 262 s->Printf("\n%snew value: 0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_new_val); 263 } 264 } 265 266 void 267 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const 268 { 269 if (s == NULL) 270 return; 271 272 assert(description_level >= lldb::eDescriptionLevelBrief && 273 description_level <= lldb::eDescriptionLevelVerbose); 274 275 s->Printf("Watchpoint %u: addr = 0x%8.8llx size = %u state = %s type = %s%s", 276 GetID(), 277 GetLoadAddress(), 278 m_byte_size, 279 IsEnabled() ? "enabled" : "disabled", 280 m_watch_read ? "r" : "", 281 m_watch_write ? "w" : ""); 282 283 if (description_level >= lldb::eDescriptionLevelFull) { 284 if (!m_decl_str.empty()) 285 s->Printf("\n declare @ '%s'", m_decl_str.c_str()); 286 if (!m_watch_spec_str.empty()) 287 s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str()); 288 289 // Dump the snapshots we have taken. 290 DumpSnapshots(s, " "); 291 292 if (GetConditionText()) 293 s->Printf("\n condition = '%s'", GetConditionText()); 294 m_options.GetCallbackDescription(s, description_level); 295 } 296 297 if (description_level >= lldb::eDescriptionLevelVerbose) 298 { 299 s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u", 300 GetHardwareIndex(), 301 GetHitCount(), 302 GetIgnoreCount()); 303 } 304 } 305 306 bool 307 Watchpoint::IsEnabled() const 308 { 309 return m_enabled; 310 } 311 312 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint 313 // in order to perform possible watchpoint actions without triggering further watchpoint events. 314 // After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode. 315 316 void 317 Watchpoint::TurnOnEphemeralMode() 318 { 319 m_is_ephemeral = true; 320 } 321 322 void 323 Watchpoint::TurnOffEphemeralMode() 324 { 325 m_is_ephemeral = false; 326 // Leaving ephemeral mode, reset the m_disabled_count! 327 m_disabled_count = 0; 328 } 329 330 bool 331 Watchpoint::IsDisabledDuringEphemeralMode() 332 { 333 return m_disabled_count > 1; 334 } 335 336 void 337 Watchpoint::SetEnabled(bool enabled) 338 { 339 if (!enabled) 340 { 341 if (!m_is_ephemeral) 342 SetHardwareIndex(LLDB_INVALID_INDEX32); 343 else 344 ++m_disabled_count; 345 346 // Don't clear the snapshots for now. 347 // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions. 348 //ClearSnapshots(); 349 } 350 m_enabled = enabled; 351 } 352 353 void 354 Watchpoint::SetWatchpointType (uint32_t type) 355 { 356 m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0; 357 m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0; 358 } 359 360 bool 361 Watchpoint::WatchpointRead () const 362 { 363 return m_watch_read != 0; 364 } 365 bool 366 Watchpoint::WatchpointWrite () const 367 { 368 return m_watch_write != 0; 369 } 370 uint32_t 371 Watchpoint::GetIgnoreCount () const 372 { 373 return m_ignore_count; 374 } 375 376 void 377 Watchpoint::SetIgnoreCount (uint32_t n) 378 { 379 m_ignore_count = n; 380 } 381 382 bool 383 Watchpoint::InvokeCallback (StoppointCallbackContext *context) 384 { 385 return m_options.InvokeCallback (context, GetID()); 386 } 387 388 void 389 Watchpoint::SetCondition (const char *condition) 390 { 391 if (condition == NULL || condition[0] == '\0') 392 { 393 if (m_condition_ap.get()) 394 m_condition_ap.reset(); 395 } 396 else 397 { 398 // Pass NULL for expr_prefix (no translation-unit level definitions). 399 m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny)); 400 } 401 } 402 403 const char * 404 Watchpoint::GetConditionText () const 405 { 406 if (m_condition_ap.get()) 407 return m_condition_ap->GetUserText(); 408 else 409 return NULL; 410 } 411 412