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