Home | History | Annotate | Download | only in Breakpoint
      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, uint32_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     m_being_created(true)
     50 {
     51     if (type && type->IsValid())
     52         m_type = *type;
     53     else
     54     {
     55         // If we don't have a known type, then we force it to unsigned int of the right size.
     56         ClangASTContext *ast_context = target.GetScratchClangASTContext();
     57         m_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
     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     m_being_created = false;
     68 }
     69 
     70 Watchpoint::~Watchpoint()
     71 {
     72 }
     73 
     74 // This function is used when "baton" doesn't need to be freed
     75 void
     76 Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
     77 {
     78     // The default "Baton" class will keep a copy of "baton" and won't free
     79     // or delete it when it goes goes out of scope.
     80     m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
     81 
     82     SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
     83 }
     84 
     85 // This function is used when a baton needs to be freed and therefore is
     86 // contained in a "Baton" subclass.
     87 void
     88 Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
     89 {
     90     m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
     91     SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
     92 }
     93 
     94 void
     95 Watchpoint::ClearCallback ()
     96 {
     97     m_options.ClearCallback ();
     98     SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
     99 }
    100 
    101 void
    102 Watchpoint::SetDeclInfo (const std::string &str)
    103 {
    104     m_decl_str = str;
    105     return;
    106 }
    107 
    108 std::string
    109 Watchpoint::GetWatchSpec()
    110 {
    111     return m_watch_spec_str;
    112 }
    113 
    114 void
    115 Watchpoint::SetWatchSpec (const std::string &str)
    116 {
    117     m_watch_spec_str = str;
    118     return;
    119 }
    120 
    121 // Override default impl of StoppointLocation::IsHardware() since m_is_hardware
    122 // member field is more accurate.
    123 bool
    124 Watchpoint::IsHardware () const
    125 {
    126     return m_is_hardware;
    127 }
    128 
    129 bool
    130 Watchpoint::IsWatchVariable() const
    131 {
    132     return m_is_watch_variable;
    133 }
    134 
    135 void
    136 Watchpoint::SetWatchVariable(bool val)
    137 {
    138     m_is_watch_variable = val;
    139 }
    140 
    141 bool
    142 Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx)
    143 {
    144     ConstString watch_name("$__lldb__watch_value");
    145     m_old_value_sp = m_new_value_sp;
    146     Address watch_address(GetLoadAddress());
    147     if (!m_type.IsValid())
    148     {
    149         // Don't know how to report new & old values, since we couldn't make a scalar type for this watchpoint.
    150         // This works around an assert in ValueObjectMemory::Create.
    151         // FIXME: This should not happen, but if it does in some case we care about,
    152         // we can go grab the value raw and print it as unsigned.
    153         return false;
    154     }
    155     m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
    156     m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
    157     if (m_new_value_sp && m_new_value_sp->GetError().Success())
    158         return true;
    159     else
    160         return false;
    161 }
    162 
    163 void
    164 Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
    165 {
    166     ++m_false_alarms;
    167     if (m_false_alarms)
    168     {
    169         if (m_hit_count >= m_false_alarms)
    170         {
    171             m_hit_count -= m_false_alarms;
    172             m_false_alarms = 0;
    173         }
    174         else
    175         {
    176             m_false_alarms -= m_hit_count;
    177             m_hit_count = 0;
    178         }
    179     }
    180 }
    181 
    182 // RETURNS - true if we should stop at this breakpoint, false if we
    183 // should continue.
    184 
    185 bool
    186 Watchpoint::ShouldStop (StoppointCallbackContext *context)
    187 {
    188     IncrementHitCount();
    189 
    190     if (!IsEnabled())
    191         return false;
    192 
    193     if (GetHitCount() <= GetIgnoreCount())
    194         return false;
    195 
    196     return true;
    197 }
    198 
    199 void
    200 Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
    201 {
    202     DumpWithLevel(s, level);
    203     return;
    204 }
    205 
    206 void
    207 Watchpoint::Dump(Stream *s) const
    208 {
    209     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
    210 }
    211 
    212 // If prefix is NULL, we display the watch id and ignore the prefix altogether.
    213 void
    214 Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
    215 {
    216     if (!prefix)
    217     {
    218         s->Printf("\nWatchpoint %u hit:", GetID());
    219         prefix = "";
    220     }
    221 
    222     if (m_old_value_sp)
    223     {
    224         s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
    225     }
    226     if (m_new_value_sp)
    227     {
    228         s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
    229     }
    230 }
    231 
    232 void
    233 Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
    234 {
    235     if (s == NULL)
    236         return;
    237 
    238     assert(description_level >= lldb::eDescriptionLevelBrief &&
    239            description_level <= lldb::eDescriptionLevelVerbose);
    240 
    241     s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 " size = %u state = %s type = %s%s",
    242               GetID(),
    243               GetLoadAddress(),
    244               m_byte_size,
    245               IsEnabled() ? "enabled" : "disabled",
    246               m_watch_read ? "r" : "",
    247               m_watch_write ? "w" : "");
    248 
    249     if (description_level >= lldb::eDescriptionLevelFull) {
    250         if (!m_decl_str.empty())
    251             s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
    252         if (!m_watch_spec_str.empty())
    253             s->Printf("\n    watchpoint spec = '%s'", m_watch_spec_str.c_str());
    254 
    255         // Dump the snapshots we have taken.
    256         DumpSnapshots(s, "    ");
    257 
    258         if (GetConditionText())
    259             s->Printf("\n    condition = '%s'", GetConditionText());
    260         m_options.GetCallbackDescription(s, description_level);
    261     }
    262 
    263     if (description_level >= lldb::eDescriptionLevelVerbose)
    264     {
    265         s->Printf("\n    hw_index = %i  hit_count = %-4u  ignore_count = %-4u",
    266                   GetHardwareIndex(),
    267                   GetHitCount(),
    268                   GetIgnoreCount());
    269     }
    270 }
    271 
    272 bool
    273 Watchpoint::IsEnabled() const
    274 {
    275     return m_enabled;
    276 }
    277 
    278 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
    279 // in order to perform possible watchpoint actions without triggering further watchpoint events.
    280 // After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
    281 
    282 void
    283 Watchpoint::TurnOnEphemeralMode()
    284 {
    285     m_is_ephemeral = true;
    286 }
    287 
    288 void
    289 Watchpoint::TurnOffEphemeralMode()
    290 {
    291     m_is_ephemeral = false;
    292     // Leaving ephemeral mode, reset the m_disabled_count!
    293     m_disabled_count = 0;
    294 }
    295 
    296 bool
    297 Watchpoint::IsDisabledDuringEphemeralMode()
    298 {
    299     return m_disabled_count > 1;
    300 }
    301 
    302 void
    303 Watchpoint::SetEnabled(bool enabled, bool notify)
    304 {
    305     if (!enabled)
    306     {
    307         if (!m_is_ephemeral)
    308             SetHardwareIndex(LLDB_INVALID_INDEX32);
    309         else
    310             ++m_disabled_count;
    311 
    312         // Don't clear the snapshots for now.
    313         // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
    314     }
    315     bool changed = enabled != m_enabled;
    316     m_enabled = enabled;
    317     if (notify && !m_is_ephemeral && changed)
    318         SendWatchpointChangedEvent (enabled ? eWatchpointEventTypeEnabled : eWatchpointEventTypeDisabled);
    319 }
    320 
    321 void
    322 Watchpoint::SetWatchpointType (uint32_t type, bool notify)
    323 {
    324     int old_watch_read = m_watch_read;
    325     int old_watch_write = m_watch_write;
    326     m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
    327     m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
    328     if (notify && (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
    329         SendWatchpointChangedEvent (eWatchpointEventTypeTypeChanged);
    330 }
    331 
    332 bool
    333 Watchpoint::WatchpointRead () const
    334 {
    335     return m_watch_read != 0;
    336 }
    337 bool
    338 Watchpoint::WatchpointWrite () const
    339 {
    340     return m_watch_write != 0;
    341 }
    342 uint32_t
    343 Watchpoint::GetIgnoreCount () const
    344 {
    345     return m_ignore_count;
    346 }
    347 
    348 void
    349 Watchpoint::SetIgnoreCount (uint32_t n)
    350 {
    351     bool changed = m_ignore_count != n;
    352     m_ignore_count = n;
    353     if (changed)
    354         SendWatchpointChangedEvent (eWatchpointEventTypeIgnoreChanged);
    355 }
    356 
    357 bool
    358 Watchpoint::InvokeCallback (StoppointCallbackContext *context)
    359 {
    360     return m_options.InvokeCallback (context, GetID());
    361 }
    362 
    363 void
    364 Watchpoint::SetCondition (const char *condition)
    365 {
    366     if (condition == NULL || condition[0] == '\0')
    367     {
    368         if (m_condition_ap.get())
    369             m_condition_ap.reset();
    370     }
    371     else
    372     {
    373         // Pass NULL for expr_prefix (no translation-unit level definitions).
    374         m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
    375     }
    376     SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged);
    377 }
    378 
    379 const char *
    380 Watchpoint::GetConditionText () const
    381 {
    382     if (m_condition_ap.get())
    383         return m_condition_ap->GetUserText();
    384     else
    385         return NULL;
    386 }
    387 
    388 void
    389 Watchpoint::SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind)
    390 {
    391     if (!m_being_created
    392         && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
    393     {
    394         WatchpointEventData *data = new Watchpoint::WatchpointEventData (eventKind, shared_from_this());
    395         GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
    396     }
    397 }
    398 
    399 void
    400 Watchpoint::SendWatchpointChangedEvent (WatchpointEventData *data)
    401 {
    402 
    403     if (data == NULL)
    404         return;
    405 
    406     if (!m_being_created
    407         && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
    408         GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
    409     else
    410         delete data;
    411 }
    412 
    413 Watchpoint::WatchpointEventData::WatchpointEventData (WatchpointEventType sub_type,
    414                                                       const WatchpointSP &new_watchpoint_sp) :
    415     EventData (),
    416     m_watchpoint_event (sub_type),
    417     m_new_watchpoint_sp (new_watchpoint_sp)
    418 {
    419 }
    420 
    421 Watchpoint::WatchpointEventData::~WatchpointEventData ()
    422 {
    423 }
    424 
    425 const ConstString &
    426 Watchpoint::WatchpointEventData::GetFlavorString ()
    427 {
    428     static ConstString g_flavor ("Watchpoint::WatchpointEventData");
    429     return g_flavor;
    430 }
    431 
    432 const ConstString &
    433 Watchpoint::WatchpointEventData::GetFlavor () const
    434 {
    435     return WatchpointEventData::GetFlavorString ();
    436 }
    437 
    438 
    439 WatchpointSP &
    440 Watchpoint::WatchpointEventData::GetWatchpoint ()
    441 {
    442     return m_new_watchpoint_sp;
    443 }
    444 
    445 WatchpointEventType
    446 Watchpoint::WatchpointEventData::GetWatchpointEventType () const
    447 {
    448     return m_watchpoint_event;
    449 }
    450 
    451 void
    452 Watchpoint::WatchpointEventData::Dump (Stream *s) const
    453 {
    454 }
    455 
    456 const Watchpoint::WatchpointEventData *
    457 Watchpoint::WatchpointEventData::GetEventDataFromEvent (const Event *event)
    458 {
    459     if (event)
    460     {
    461         const EventData *event_data = event->GetData();
    462         if (event_data && event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
    463             return static_cast <const WatchpointEventData *> (event->GetData());
    464     }
    465     return NULL;
    466 }
    467 
    468 WatchpointEventType
    469 Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (const EventSP &event_sp)
    470 {
    471     const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
    472 
    473     if (data == NULL)
    474         return eWatchpointEventTypeInvalidType;
    475     else
    476         return data->GetWatchpointEventType();
    477 }
    478 
    479 WatchpointSP
    480 Watchpoint::WatchpointEventData::GetWatchpointFromEvent (const EventSP &event_sp)
    481 {
    482     WatchpointSP wp_sp;
    483 
    484     const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
    485     if (data)
    486         wp_sp = data->m_new_watchpoint_sp;
    487 
    488     return wp_sp;
    489 }
    490