15ffd83dbSDimitry Andric //===-- Watchpoint.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Breakpoint/Watchpoint.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
125f757f3fSDimitry Andric #include "lldb/Breakpoint/WatchpointResource.h"
130b57cec5SDimitry Andric #include "lldb/Core/Value.h"
140b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
150b57cec5SDimitry Andric #include "lldb/Core/ValueObjectMemory.h"
165f757f3fSDimitry Andric #include "lldb/DataFormatters/DumpValueObjectOptions.h"
170b57cec5SDimitry Andric #include "lldb/Expression/UserExpression.h"
189dba64beSDimitry Andric #include "lldb/Symbol/TypeSystem.h"
190b57cec5SDimitry Andric #include "lldb/Target/Process.h"
200b57cec5SDimitry Andric #include "lldb/Target/Target.h"
210b57cec5SDimitry Andric #include "lldb/Target/ThreadSpec.h"
2281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
239dba64beSDimitry Andric #include "lldb/Utility/Log.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace lldb;
270b57cec5SDimitry Andric using namespace lldb_private;
280b57cec5SDimitry Andric 
Watchpoint(Target & target,lldb::addr_t addr,uint32_t size,const CompilerType * type,bool hardware)290b57cec5SDimitry Andric Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size,
300b57cec5SDimitry Andric                        const CompilerType *type, bool hardware)
31e8d8bef9SDimitry Andric     : StoppointSite(0, addr, size, hardware), m_target(target),
320b57cec5SDimitry Andric       m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false),
330b57cec5SDimitry Andric       m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0),
345f757f3fSDimitry Andric       m_watch_write(0), m_watch_modify(0), m_ignore_count(0),
355f757f3fSDimitry Andric       m_being_created(true) {
369dba64beSDimitry Andric 
370b57cec5SDimitry Andric   if (type && type->IsValid())
380b57cec5SDimitry Andric     m_type = *type;
390b57cec5SDimitry Andric   else {
400b57cec5SDimitry Andric     // If we don't have a known type, then we force it to unsigned int of the
410b57cec5SDimitry Andric     // right size.
429dba64beSDimitry Andric     auto type_system_or_err =
439dba64beSDimitry Andric         target.GetScratchTypeSystemForLanguage(eLanguageTypeC);
449dba64beSDimitry Andric     if (auto err = type_system_or_err.takeError()) {
4581ad6265SDimitry Andric       LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err),
4606c3fb27SDimitry Andric                      "Failed to set type: {0}");
479dba64beSDimitry Andric     } else {
48bdd1243dSDimitry Andric       if (auto ts = *type_system_or_err)
49bdd1243dSDimitry Andric         m_type =
50bdd1243dSDimitry Andric             ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
51bdd1243dSDimitry Andric       else
52bdd1243dSDimitry Andric         LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err),
5306c3fb27SDimitry Andric                        "Failed to set type: Typesystem is no longer live: {0}");
549dba64beSDimitry Andric     }
550b57cec5SDimitry Andric   }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   // Set the initial value of the watched variable:
580b57cec5SDimitry Andric   if (m_target.GetProcessSP()) {
590b57cec5SDimitry Andric     ExecutionContext exe_ctx;
600b57cec5SDimitry Andric     m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
610b57cec5SDimitry Andric     CaptureWatchedValue(exe_ctx);
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric   m_being_created = false;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric Watchpoint::~Watchpoint() = default;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric // This function is used when "baton" doesn't need to be freed
SetCallback(WatchpointHitCallback callback,void * baton,bool is_synchronous)690b57cec5SDimitry Andric void Watchpoint::SetCallback(WatchpointHitCallback callback, void *baton,
700b57cec5SDimitry Andric                              bool is_synchronous) {
710b57cec5SDimitry Andric   // The default "Baton" class will keep a copy of "baton" and won't free or
725f757f3fSDimitry Andric   // delete it when it goes out of scope.
730b57cec5SDimitry Andric   m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),
740b57cec5SDimitry Andric                         is_synchronous);
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric // This function is used when a baton needs to be freed and therefore is
800b57cec5SDimitry Andric // contained in a "Baton" subclass.
SetCallback(WatchpointHitCallback callback,const BatonSP & callback_baton_sp,bool is_synchronous)810b57cec5SDimitry Andric void Watchpoint::SetCallback(WatchpointHitCallback callback,
820b57cec5SDimitry Andric                              const BatonSP &callback_baton_sp,
830b57cec5SDimitry Andric                              bool is_synchronous) {
840b57cec5SDimitry Andric   m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
850b57cec5SDimitry Andric   SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
SetupVariableWatchpointDisabler(StackFrameSP frame_sp) const8806c3fb27SDimitry Andric bool Watchpoint::SetupVariableWatchpointDisabler(StackFrameSP frame_sp) const {
8906c3fb27SDimitry Andric   if (!frame_sp)
9006c3fb27SDimitry Andric     return false;
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric   ThreadSP thread_sp = frame_sp->GetThread();
9306c3fb27SDimitry Andric   if (!thread_sp)
9406c3fb27SDimitry Andric     return false;
9506c3fb27SDimitry Andric 
9606c3fb27SDimitry Andric   uint32_t return_frame_index =
9706c3fb27SDimitry Andric       thread_sp->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame) + 1;
9806c3fb27SDimitry Andric   if (return_frame_index >= LLDB_INVALID_FRAME_ID)
9906c3fb27SDimitry Andric     return false;
10006c3fb27SDimitry Andric 
10106c3fb27SDimitry Andric   StackFrameSP return_frame_sp(
10206c3fb27SDimitry Andric       thread_sp->GetStackFrameAtIndex(return_frame_index));
10306c3fb27SDimitry Andric   if (!return_frame_sp)
10406c3fb27SDimitry Andric     return false;
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric   ExecutionContext exe_ctx(return_frame_sp);
10706c3fb27SDimitry Andric   TargetSP target_sp = exe_ctx.GetTargetSP();
10806c3fb27SDimitry Andric   if (!target_sp)
10906c3fb27SDimitry Andric     return false;
11006c3fb27SDimitry Andric 
11106c3fb27SDimitry Andric   Address return_address(return_frame_sp->GetFrameCodeAddress());
11206c3fb27SDimitry Andric   lldb::addr_t return_addr = return_address.GetLoadAddress(target_sp.get());
11306c3fb27SDimitry Andric   if (return_addr == LLDB_INVALID_ADDRESS)
11406c3fb27SDimitry Andric     return false;
11506c3fb27SDimitry Andric 
11606c3fb27SDimitry Andric   BreakpointSP bp_sp = target_sp->CreateBreakpoint(
11706c3fb27SDimitry Andric       return_addr, /*internal=*/true, /*request_hardware=*/false);
11806c3fb27SDimitry Andric   if (!bp_sp || !bp_sp->HasResolvedLocations())
11906c3fb27SDimitry Andric     return false;
12006c3fb27SDimitry Andric 
12106c3fb27SDimitry Andric   auto wvc_up = std::make_unique<WatchpointVariableContext>(GetID(), exe_ctx);
12206c3fb27SDimitry Andric   auto baton_sp = std::make_shared<WatchpointVariableBaton>(std::move(wvc_up));
12306c3fb27SDimitry Andric   bp_sp->SetCallback(VariableWatchpointDisabler, baton_sp);
12406c3fb27SDimitry Andric   bp_sp->SetOneShot(true);
12506c3fb27SDimitry Andric   bp_sp->SetBreakpointKind("variable watchpoint disabler");
12606c3fb27SDimitry Andric   return true;
12706c3fb27SDimitry Andric }
12806c3fb27SDimitry Andric 
VariableWatchpointDisabler(void * baton,StoppointCallbackContext * context,user_id_t break_id,user_id_t break_loc_id)12906c3fb27SDimitry Andric bool Watchpoint::VariableWatchpointDisabler(void *baton,
13006c3fb27SDimitry Andric                                             StoppointCallbackContext *context,
13106c3fb27SDimitry Andric                                             user_id_t break_id,
13206c3fb27SDimitry Andric                                             user_id_t break_loc_id) {
13306c3fb27SDimitry Andric   assert(baton && "null baton");
13406c3fb27SDimitry Andric   if (!baton || !context)
13506c3fb27SDimitry Andric     return false;
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric   Log *log = GetLog(LLDBLog::Watchpoints);
13806c3fb27SDimitry Andric 
13906c3fb27SDimitry Andric   WatchpointVariableContext *wvc =
14006c3fb27SDimitry Andric       static_cast<WatchpointVariableContext *>(baton);
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric   LLDB_LOGF(log, "called by breakpoint %" PRIu64 ".%" PRIu64, break_id,
14306c3fb27SDimitry Andric             break_loc_id);
14406c3fb27SDimitry Andric 
14506c3fb27SDimitry Andric   if (wvc->watch_id == LLDB_INVALID_WATCH_ID)
14606c3fb27SDimitry Andric     return false;
14706c3fb27SDimitry Andric 
14806c3fb27SDimitry Andric   TargetSP target_sp = context->exe_ctx_ref.GetTargetSP();
14906c3fb27SDimitry Andric   if (!target_sp)
15006c3fb27SDimitry Andric     return false;
15106c3fb27SDimitry Andric 
15206c3fb27SDimitry Andric   ProcessSP process_sp = target_sp->GetProcessSP();
15306c3fb27SDimitry Andric   if (!process_sp)
15406c3fb27SDimitry Andric     return false;
15506c3fb27SDimitry Andric 
15606c3fb27SDimitry Andric   WatchpointSP watch_sp =
15706c3fb27SDimitry Andric       target_sp->GetWatchpointList().FindByID(wvc->watch_id);
15806c3fb27SDimitry Andric   if (!watch_sp)
15906c3fb27SDimitry Andric     return false;
16006c3fb27SDimitry Andric 
16106c3fb27SDimitry Andric   if (wvc->exe_ctx == context->exe_ctx_ref) {
16206c3fb27SDimitry Andric     LLDB_LOGF(log,
16306c3fb27SDimitry Andric               "callback for watchpoint %" PRId32
16406c3fb27SDimitry Andric               " matched internal breakpoint execution context",
16506c3fb27SDimitry Andric               watch_sp->GetID());
1665f757f3fSDimitry Andric     process_sp->DisableWatchpoint(watch_sp);
16706c3fb27SDimitry Andric     return false;
16806c3fb27SDimitry Andric   }
16906c3fb27SDimitry Andric   LLDB_LOGF(log,
17006c3fb27SDimitry Andric             "callback for watchpoint %" PRId32
17106c3fb27SDimitry Andric             " didn't match internal breakpoint execution context",
17206c3fb27SDimitry Andric             watch_sp->GetID());
17306c3fb27SDimitry Andric   return false;
17406c3fb27SDimitry Andric }
17506c3fb27SDimitry Andric 
ClearCallback()1760b57cec5SDimitry Andric void Watchpoint::ClearCallback() {
1770b57cec5SDimitry Andric   m_options.ClearCallback();
1780b57cec5SDimitry Andric   SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
SetDeclInfo(const std::string & str)1810b57cec5SDimitry Andric void Watchpoint::SetDeclInfo(const std::string &str) { m_decl_str = str; }
1820b57cec5SDimitry Andric 
GetWatchSpec()1830b57cec5SDimitry Andric std::string Watchpoint::GetWatchSpec() { return m_watch_spec_str; }
1840b57cec5SDimitry Andric 
SetWatchSpec(const std::string & str)1850b57cec5SDimitry Andric void Watchpoint::SetWatchSpec(const std::string &str) {
1860b57cec5SDimitry Andric   m_watch_spec_str = str;
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
IsHardware() const189e8d8bef9SDimitry Andric bool Watchpoint::IsHardware() const {
190e8d8bef9SDimitry Andric   lldbassert(m_is_hardware || !HardwareRequired());
191e8d8bef9SDimitry Andric   return m_is_hardware;
192e8d8bef9SDimitry Andric }
1930b57cec5SDimitry Andric 
IsWatchVariable() const1940b57cec5SDimitry Andric bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
1950b57cec5SDimitry Andric 
SetWatchVariable(bool val)1960b57cec5SDimitry Andric void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
1970b57cec5SDimitry Andric 
CaptureWatchedValue(const ExecutionContext & exe_ctx)1980b57cec5SDimitry Andric bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
1995f757f3fSDimitry Andric   ConstString g_watch_name("$__lldb__watch_value");
2000b57cec5SDimitry Andric   m_old_value_sp = m_new_value_sp;
2010b57cec5SDimitry Andric   Address watch_address(GetLoadAddress());
2020b57cec5SDimitry Andric   if (!m_type.IsValid()) {
2030b57cec5SDimitry Andric     // Don't know how to report new & old values, since we couldn't make a
2040b57cec5SDimitry Andric     // scalar type for this watchpoint. This works around an assert in
2050b57cec5SDimitry Andric     // ValueObjectMemory::Create.
2060b57cec5SDimitry Andric     // FIXME: This should not happen, but if it does in some case we care about,
2070b57cec5SDimitry Andric     // we can go grab the value raw and print it as unsigned.
2080b57cec5SDimitry Andric     return false;
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric   m_new_value_sp = ValueObjectMemory::Create(
2115f757f3fSDimitry Andric       exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
2120b57cec5SDimitry Andric       watch_address, m_type);
2135f757f3fSDimitry Andric   m_new_value_sp = m_new_value_sp->CreateConstantValue(g_watch_name);
2140b57cec5SDimitry Andric   return (m_new_value_sp && m_new_value_sp->GetError().Success());
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
WatchedValueReportable(const ExecutionContext & exe_ctx)2175f757f3fSDimitry Andric bool Watchpoint::WatchedValueReportable(const ExecutionContext &exe_ctx) {
2185f757f3fSDimitry Andric   if (!m_watch_modify || m_watch_read)
2195f757f3fSDimitry Andric     return true;
2205f757f3fSDimitry Andric   if (!m_type.IsValid())
2215f757f3fSDimitry Andric     return true;
2225f757f3fSDimitry Andric 
2235f757f3fSDimitry Andric   ConstString g_watch_name("$__lldb__watch_value");
2245f757f3fSDimitry Andric   Address watch_address(GetLoadAddress());
2255f757f3fSDimitry Andric   ValueObjectSP newest_valueobj_sp = ValueObjectMemory::Create(
2265f757f3fSDimitry Andric       exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
2275f757f3fSDimitry Andric       watch_address, m_type);
2285f757f3fSDimitry Andric   newest_valueobj_sp = newest_valueobj_sp->CreateConstantValue(g_watch_name);
2295f757f3fSDimitry Andric   Status error;
2305f757f3fSDimitry Andric 
2315f757f3fSDimitry Andric   DataExtractor new_data;
2325f757f3fSDimitry Andric   DataExtractor old_data;
2335f757f3fSDimitry Andric 
2345f757f3fSDimitry Andric   newest_valueobj_sp->GetData(new_data, error);
2355f757f3fSDimitry Andric   if (error.Fail())
2365f757f3fSDimitry Andric     return true;
2375f757f3fSDimitry Andric   m_new_value_sp->GetData(old_data, error);
2385f757f3fSDimitry Andric   if (error.Fail())
2395f757f3fSDimitry Andric     return true;
2405f757f3fSDimitry Andric 
2415f757f3fSDimitry Andric   if (new_data.GetByteSize() != old_data.GetByteSize() ||
2425f757f3fSDimitry Andric       new_data.GetByteSize() == 0)
2435f757f3fSDimitry Andric     return true;
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   if (memcmp(new_data.GetDataStart(), old_data.GetDataStart(),
2465f757f3fSDimitry Andric              old_data.GetByteSize()) == 0)
2475f757f3fSDimitry Andric     return false; // Value has not changed, user requested modify watchpoint
2485f757f3fSDimitry Andric 
2495f757f3fSDimitry Andric   return true;
2505f757f3fSDimitry Andric }
2515f757f3fSDimitry Andric 
2520b57cec5SDimitry Andric // RETURNS - true if we should stop at this breakpoint, false if we
2530b57cec5SDimitry Andric // should continue.
2540b57cec5SDimitry Andric 
ShouldStop(StoppointCallbackContext * context)2550b57cec5SDimitry Andric bool Watchpoint::ShouldStop(StoppointCallbackContext *context) {
256e8d8bef9SDimitry Andric   m_hit_counter.Increment();
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   return IsEnabled();
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)2610b57cec5SDimitry Andric void Watchpoint::GetDescription(Stream *s, lldb::DescriptionLevel level) {
2620b57cec5SDimitry Andric   DumpWithLevel(s, level);
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
Dump(Stream * s) const2650b57cec5SDimitry Andric void Watchpoint::Dump(Stream *s) const {
2660b57cec5SDimitry Andric   DumpWithLevel(s, lldb::eDescriptionLevelBrief);
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric // If prefix is nullptr, we display the watch id and ignore the prefix
2700b57cec5SDimitry Andric // altogether.
DumpSnapshots(Stream * s,const char * prefix) const2715f757f3fSDimitry Andric bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
2725f757f3fSDimitry Andric   bool printed_anything = false;
2735f757f3fSDimitry Andric 
2745f757f3fSDimitry Andric   // For read watchpoints, don't display any before/after value changes.
2755f757f3fSDimitry Andric   if (m_watch_read && !m_watch_modify && !m_watch_write)
2765f757f3fSDimitry Andric     return printed_anything;
2775f757f3fSDimitry Andric 
2785f757f3fSDimitry Andric   s->Printf("\n");
2795f757f3fSDimitry Andric   s->Printf("Watchpoint %u hit:\n", GetID());
2805f757f3fSDimitry Andric 
2815f757f3fSDimitry Andric   StreamString values_ss;
2825f757f3fSDimitry Andric   if (prefix)
2835f757f3fSDimitry Andric     values_ss.Indent(prefix);
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   if (m_old_value_sp) {
2865f757f3fSDimitry Andric     if (auto *old_value_cstr = m_old_value_sp->GetValueAsCString()) {
2875f757f3fSDimitry Andric       values_ss.Printf("old value: %s", old_value_cstr);
2885f757f3fSDimitry Andric     } else {
2895f757f3fSDimitry Andric       if (auto *old_summary_cstr = m_old_value_sp->GetSummaryAsCString())
2905f757f3fSDimitry Andric         values_ss.Printf("old value: %s", old_summary_cstr);
2910b57cec5SDimitry Andric       else {
2925f757f3fSDimitry Andric         StreamString strm;
2935f757f3fSDimitry Andric         DumpValueObjectOptions options;
2945f757f3fSDimitry Andric         options.SetUseDynamicType(eNoDynamicValues)
2955f757f3fSDimitry Andric             .SetHideRootType(true)
2965f757f3fSDimitry Andric             .SetHideRootName(true)
2975f757f3fSDimitry Andric             .SetHideName(true);
2985f757f3fSDimitry Andric         m_old_value_sp->Dump(strm, options);
2995f757f3fSDimitry Andric         if (strm.GetData())
3005f757f3fSDimitry Andric           values_ss.Printf("old value: %s", strm.GetData());
3015f757f3fSDimitry Andric       }
3020b57cec5SDimitry Andric     }
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   if (m_new_value_sp) {
3065f757f3fSDimitry Andric     if (values_ss.GetSize())
3075f757f3fSDimitry Andric       values_ss.Printf("\n");
3085f757f3fSDimitry Andric 
3095f757f3fSDimitry Andric     if (auto *new_value_cstr = m_new_value_sp->GetValueAsCString())
3105f757f3fSDimitry Andric       values_ss.Printf("new value: %s", new_value_cstr);
3110b57cec5SDimitry Andric     else {
3125f757f3fSDimitry Andric       if (auto *new_summary_cstr = m_new_value_sp->GetSummaryAsCString())
3135f757f3fSDimitry Andric         values_ss.Printf("new value: %s", new_summary_cstr);
3145f757f3fSDimitry Andric       else {
3155f757f3fSDimitry Andric         StreamString strm;
3165f757f3fSDimitry Andric         DumpValueObjectOptions options;
3175f757f3fSDimitry Andric         options.SetUseDynamicType(eNoDynamicValues)
3185f757f3fSDimitry Andric             .SetHideRootType(true)
3195f757f3fSDimitry Andric             .SetHideRootName(true)
3205f757f3fSDimitry Andric             .SetHideName(true);
3215f757f3fSDimitry Andric         m_new_value_sp->Dump(strm, options);
3225f757f3fSDimitry Andric         if (strm.GetData())
3235f757f3fSDimitry Andric           values_ss.Printf("new value: %s", strm.GetData());
3240b57cec5SDimitry Andric       }
3250b57cec5SDimitry Andric     }
3260b57cec5SDimitry Andric   }
3270b57cec5SDimitry Andric 
3285f757f3fSDimitry Andric   if (values_ss.GetSize()) {
3295f757f3fSDimitry Andric     s->Printf("%s", values_ss.GetData());
3305f757f3fSDimitry Andric     printed_anything = true;
3315f757f3fSDimitry Andric   }
3325f757f3fSDimitry Andric 
3335f757f3fSDimitry Andric   return printed_anything;
3345f757f3fSDimitry Andric }
3355f757f3fSDimitry Andric 
DumpWithLevel(Stream * s,lldb::DescriptionLevel description_level) const3360b57cec5SDimitry Andric void Watchpoint::DumpWithLevel(Stream *s,
3370b57cec5SDimitry Andric                                lldb::DescriptionLevel description_level) const {
3380b57cec5SDimitry Andric   if (s == nullptr)
3390b57cec5SDimitry Andric     return;
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   assert(description_level >= lldb::eDescriptionLevelBrief &&
3420b57cec5SDimitry Andric          description_level <= lldb::eDescriptionLevelVerbose);
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric   s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
3455f757f3fSDimitry Andric             " size = %u state = %s type = %s%s%s",
3460b57cec5SDimitry Andric             GetID(), GetLoadAddress(), m_byte_size,
3470b57cec5SDimitry Andric             IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
3485f757f3fSDimitry Andric             m_watch_write ? "w" : "", m_watch_modify ? "m" : "");
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   if (description_level >= lldb::eDescriptionLevelFull) {
3510b57cec5SDimitry Andric     if (!m_decl_str.empty())
3520b57cec5SDimitry Andric       s->Printf("\n    declare @ '%s'", m_decl_str.c_str());
3530b57cec5SDimitry Andric     if (!m_watch_spec_str.empty())
3540b57cec5SDimitry Andric       s->Printf("\n    watchpoint spec = '%s'", m_watch_spec_str.c_str());
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric     // Dump the snapshots we have taken.
3570b57cec5SDimitry Andric     DumpSnapshots(s, "    ");
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric     if (GetConditionText())
3600b57cec5SDimitry Andric       s->Printf("\n    condition = '%s'", GetConditionText());
3610b57cec5SDimitry Andric     m_options.GetCallbackDescription(s, description_level);
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   if (description_level >= lldb::eDescriptionLevelVerbose) {
3655f757f3fSDimitry Andric     s->Printf("\n    hit_count = %-4u  ignore_count = %-4u", GetHitCount(),
3665f757f3fSDimitry Andric               GetIgnoreCount());
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
IsEnabled() const3700b57cec5SDimitry Andric bool Watchpoint::IsEnabled() const { return m_enabled; }
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
3730b57cec5SDimitry Andric // temporarily disable the watchpoint in order to perform possible watchpoint
3740b57cec5SDimitry Andric // actions without triggering further watchpoint events. After the temporary
3750b57cec5SDimitry Andric // disabled watchpoint is enabled, we then turn off the ephemeral mode.
3760b57cec5SDimitry Andric 
TurnOnEphemeralMode()3770b57cec5SDimitry Andric void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral = true; }
3780b57cec5SDimitry Andric 
TurnOffEphemeralMode()3790b57cec5SDimitry Andric void Watchpoint::TurnOffEphemeralMode() {
3800b57cec5SDimitry Andric   m_is_ephemeral = false;
3810b57cec5SDimitry Andric   // Leaving ephemeral mode, reset the m_disabled_count!
3820b57cec5SDimitry Andric   m_disabled_count = 0;
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
IsDisabledDuringEphemeralMode()3850b57cec5SDimitry Andric bool Watchpoint::IsDisabledDuringEphemeralMode() {
3860b57cec5SDimitry Andric   return m_disabled_count > 1 && m_is_ephemeral;
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric 
SetEnabled(bool enabled,bool notify)3890b57cec5SDimitry Andric void Watchpoint::SetEnabled(bool enabled, bool notify) {
3900b57cec5SDimitry Andric   if (!enabled) {
3915f757f3fSDimitry Andric     if (m_is_ephemeral)
3920b57cec5SDimitry Andric       ++m_disabled_count;
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric     // Don't clear the snapshots for now.
3950b57cec5SDimitry Andric     // Within StopInfo.cpp, we purposely do disable/enable watchpoint while
3960b57cec5SDimitry Andric     // performing watchpoint actions.
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric   bool changed = enabled != m_enabled;
3990b57cec5SDimitry Andric   m_enabled = enabled;
4000b57cec5SDimitry Andric   if (notify && !m_is_ephemeral && changed)
4010b57cec5SDimitry Andric     SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled
4020b57cec5SDimitry Andric                                        : eWatchpointEventTypeDisabled);
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
SetWatchpointType(uint32_t type,bool notify)4050b57cec5SDimitry Andric void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
4060b57cec5SDimitry Andric   int old_watch_read = m_watch_read;
4070b57cec5SDimitry Andric   int old_watch_write = m_watch_write;
4085f757f3fSDimitry Andric   int old_watch_modify = m_watch_modify;
4090b57cec5SDimitry Andric   m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
4100b57cec5SDimitry Andric   m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
4115f757f3fSDimitry Andric   m_watch_modify = (type & LLDB_WATCH_TYPE_MODIFY) != 0;
4120b57cec5SDimitry Andric   if (notify &&
4135f757f3fSDimitry Andric       (old_watch_read != m_watch_read || old_watch_write != m_watch_write ||
4145f757f3fSDimitry Andric        old_watch_modify != m_watch_modify))
4150b57cec5SDimitry Andric     SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
4160b57cec5SDimitry Andric }
4170b57cec5SDimitry Andric 
WatchpointRead() const4180b57cec5SDimitry Andric bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
4190b57cec5SDimitry Andric 
WatchpointWrite() const4200b57cec5SDimitry Andric bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
4210b57cec5SDimitry Andric 
WatchpointModify() const4225f757f3fSDimitry Andric bool Watchpoint::WatchpointModify() const { return m_watch_modify != 0; }
4235f757f3fSDimitry Andric 
GetIgnoreCount() const4240b57cec5SDimitry Andric uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
4250b57cec5SDimitry Andric 
SetIgnoreCount(uint32_t n)4260b57cec5SDimitry Andric void Watchpoint::SetIgnoreCount(uint32_t n) {
4270b57cec5SDimitry Andric   bool changed = m_ignore_count != n;
4280b57cec5SDimitry Andric   m_ignore_count = n;
4290b57cec5SDimitry Andric   if (changed)
4300b57cec5SDimitry Andric     SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged);
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
InvokeCallback(StoppointCallbackContext * context)4330b57cec5SDimitry Andric bool Watchpoint::InvokeCallback(StoppointCallbackContext *context) {
4340b57cec5SDimitry Andric   return m_options.InvokeCallback(context, GetID());
4350b57cec5SDimitry Andric }
4360b57cec5SDimitry Andric 
SetCondition(const char * condition)4370b57cec5SDimitry Andric void Watchpoint::SetCondition(const char *condition) {
4380b57cec5SDimitry Andric   if (condition == nullptr || condition[0] == '\0') {
4390b57cec5SDimitry Andric     if (m_condition_up)
4400b57cec5SDimitry Andric       m_condition_up.reset();
4410b57cec5SDimitry Andric   } else {
4420b57cec5SDimitry Andric     // Pass nullptr for expr_prefix (no translation-unit level definitions).
4430b57cec5SDimitry Andric     Status error;
4440b57cec5SDimitry Andric     m_condition_up.reset(m_target.GetUserExpressionForLanguage(
4450b57cec5SDimitry Andric         condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
4460b57cec5SDimitry Andric         UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
4470b57cec5SDimitry Andric         error));
4480b57cec5SDimitry Andric     if (error.Fail()) {
4490b57cec5SDimitry Andric       // FIXME: Log something...
4500b57cec5SDimitry Andric       m_condition_up.reset();
4510b57cec5SDimitry Andric     }
4520b57cec5SDimitry Andric   }
4530b57cec5SDimitry Andric   SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged);
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric 
GetConditionText() const4560b57cec5SDimitry Andric const char *Watchpoint::GetConditionText() const {
4570b57cec5SDimitry Andric   if (m_condition_up)
4580b57cec5SDimitry Andric     return m_condition_up->GetUserText();
4590b57cec5SDimitry Andric   else
4600b57cec5SDimitry Andric     return nullptr;
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric 
SendWatchpointChangedEvent(lldb::WatchpointEventType eventKind)4630b57cec5SDimitry Andric void Watchpoint::SendWatchpointChangedEvent(
4640b57cec5SDimitry Andric     lldb::WatchpointEventType eventKind) {
4657a6dacacSDimitry Andric   if (!m_being_created && GetTarget().EventTypeHasListeners(
4660b57cec5SDimitry Andric                               Target::eBroadcastBitWatchpointChanged)) {
4677a6dacacSDimitry Andric     auto data_sp =
4687a6dacacSDimitry Andric         std::make_shared<WatchpointEventData>(eventKind, shared_from_this());
4697a6dacacSDimitry Andric     GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data_sp);
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric }
4720b57cec5SDimitry Andric 
WatchpointEventData(WatchpointEventType sub_type,const WatchpointSP & new_watchpoint_sp)4730b57cec5SDimitry Andric Watchpoint::WatchpointEventData::WatchpointEventData(
4740b57cec5SDimitry Andric     WatchpointEventType sub_type, const WatchpointSP &new_watchpoint_sp)
47581ad6265SDimitry Andric     : m_watchpoint_event(sub_type), m_new_watchpoint_sp(new_watchpoint_sp) {}
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric Watchpoint::WatchpointEventData::~WatchpointEventData() = default;
4780b57cec5SDimitry Andric 
GetFlavorString()47906c3fb27SDimitry Andric llvm::StringRef Watchpoint::WatchpointEventData::GetFlavorString() {
48006c3fb27SDimitry Andric   return "Watchpoint::WatchpointEventData";
4810b57cec5SDimitry Andric }
4820b57cec5SDimitry Andric 
GetFlavor() const48306c3fb27SDimitry Andric llvm::StringRef Watchpoint::WatchpointEventData::GetFlavor() const {
4840b57cec5SDimitry Andric   return WatchpointEventData::GetFlavorString();
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric 
GetWatchpoint()4870b57cec5SDimitry Andric WatchpointSP &Watchpoint::WatchpointEventData::GetWatchpoint() {
4880b57cec5SDimitry Andric   return m_new_watchpoint_sp;
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric WatchpointEventType
GetWatchpointEventType() const4920b57cec5SDimitry Andric Watchpoint::WatchpointEventData::GetWatchpointEventType() const {
4930b57cec5SDimitry Andric   return m_watchpoint_event;
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric 
Dump(Stream * s) const4960b57cec5SDimitry Andric void Watchpoint::WatchpointEventData::Dump(Stream *s) const {}
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric const Watchpoint::WatchpointEventData *
GetEventDataFromEvent(const Event * event)4990b57cec5SDimitry Andric Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event *event) {
5000b57cec5SDimitry Andric   if (event) {
5010b57cec5SDimitry Andric     const EventData *event_data = event->GetData();
5020b57cec5SDimitry Andric     if (event_data &&
5030b57cec5SDimitry Andric         event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
5040b57cec5SDimitry Andric       return static_cast<const WatchpointEventData *>(event->GetData());
5050b57cec5SDimitry Andric   }
5060b57cec5SDimitry Andric   return nullptr;
5070b57cec5SDimitry Andric }
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric WatchpointEventType
GetWatchpointEventTypeFromEvent(const EventSP & event_sp)5100b57cec5SDimitry Andric Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
5110b57cec5SDimitry Andric     const EventSP &event_sp) {
5120b57cec5SDimitry Andric   const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   if (data == nullptr)
5150b57cec5SDimitry Andric     return eWatchpointEventTypeInvalidType;
5160b57cec5SDimitry Andric   else
5170b57cec5SDimitry Andric     return data->GetWatchpointEventType();
5180b57cec5SDimitry Andric }
5190b57cec5SDimitry Andric 
GetWatchpointFromEvent(const EventSP & event_sp)5200b57cec5SDimitry Andric WatchpointSP Watchpoint::WatchpointEventData::GetWatchpointFromEvent(
5210b57cec5SDimitry Andric     const EventSP &event_sp) {
5220b57cec5SDimitry Andric   WatchpointSP wp_sp;
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric   const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
5250b57cec5SDimitry Andric   if (data)
5260b57cec5SDimitry Andric     wp_sp = data->m_new_watchpoint_sp;
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric   return wp_sp;
5290b57cec5SDimitry Andric }
530