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