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