1 //===-- WatchpointOptions.cpp -----------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Breakpoint/WatchpointOptions.h"
10 
11 #include "lldb/Breakpoint/StoppointCallbackContext.h"
12 #include "lldb/Core/Value.h"
13 #include "lldb/Target/Process.h"
14 #include "lldb/Target/Target.h"
15 #include "lldb/Target/ThreadSpec.h"
16 #include "lldb/Utility/Stream.h"
17 #include "lldb/Utility/StringList.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 bool WatchpointOptions::NullCallback(void *baton,
23                                      StoppointCallbackContext *context,
24                                      lldb::user_id_t watch_id) {
25   return true;
26 }
27 
28 //----------------------------------------------------------------------
29 // WatchpointOptions constructor
30 //----------------------------------------------------------------------
31 WatchpointOptions::WatchpointOptions()
32     : m_callback(WatchpointOptions::NullCallback), m_callback_baton_sp(),
33       m_callback_is_synchronous(false), m_thread_spec_up() {}
34 
35 //----------------------------------------------------------------------
36 // WatchpointOptions copy constructor
37 //----------------------------------------------------------------------
38 WatchpointOptions::WatchpointOptions(const WatchpointOptions &rhs)
39     : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
40       m_callback_is_synchronous(rhs.m_callback_is_synchronous),
41       m_thread_spec_up() {
42   if (rhs.m_thread_spec_up != nullptr)
43     m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
44 }
45 
46 //----------------------------------------------------------------------
47 // WatchpointOptions assignment operator
48 //----------------------------------------------------------------------
49 const WatchpointOptions &WatchpointOptions::
50 operator=(const WatchpointOptions &rhs) {
51   m_callback = rhs.m_callback;
52   m_callback_baton_sp = rhs.m_callback_baton_sp;
53   m_callback_is_synchronous = rhs.m_callback_is_synchronous;
54   if (rhs.m_thread_spec_up != nullptr)
55     m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
56   return *this;
57 }
58 
59 WatchpointOptions *
60 WatchpointOptions::CopyOptionsNoCallback(WatchpointOptions &orig) {
61   WatchpointHitCallback orig_callback = orig.m_callback;
62   lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
63   bool orig_is_sync = orig.m_callback_is_synchronous;
64 
65   orig.ClearCallback();
66   WatchpointOptions *ret_val = new WatchpointOptions(orig);
67 
68   orig.SetCallback(orig_callback, orig_callback_baton_sp, orig_is_sync);
69 
70   return ret_val;
71 }
72 
73 //----------------------------------------------------------------------
74 // Destructor
75 //----------------------------------------------------------------------
76 WatchpointOptions::~WatchpointOptions() = default;
77 
78 //------------------------------------------------------------------
79 // Callbacks
80 //------------------------------------------------------------------
81 void WatchpointOptions::SetCallback(WatchpointHitCallback callback,
82                                     const BatonSP &callback_baton_sp,
83                                     bool callback_is_synchronous) {
84   m_callback_is_synchronous = callback_is_synchronous;
85   m_callback = callback;
86   m_callback_baton_sp = callback_baton_sp;
87 }
88 
89 void WatchpointOptions::ClearCallback() {
90   m_callback = WatchpointOptions::NullCallback;
91   m_callback_is_synchronous = false;
92   m_callback_baton_sp.reset();
93 }
94 
95 Baton *WatchpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
96 
97 const Baton *WatchpointOptions::GetBaton() const {
98   return m_callback_baton_sp.get();
99 }
100 
101 bool WatchpointOptions::InvokeCallback(StoppointCallbackContext *context,
102                                        lldb::user_id_t watch_id) {
103   if (m_callback && context->is_synchronous == IsCallbackSynchronous()) {
104     return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
105                                           : nullptr,
106                       context, watch_id);
107   } else
108     return true;
109 }
110 
111 bool WatchpointOptions::HasCallback() {
112   return m_callback != WatchpointOptions::NullCallback;
113 }
114 
115 const ThreadSpec *WatchpointOptions::GetThreadSpecNoCreate() const {
116   return m_thread_spec_up.get();
117 }
118 
119 ThreadSpec *WatchpointOptions::GetThreadSpec() {
120   if (m_thread_spec_up == nullptr)
121     m_thread_spec_up.reset(new ThreadSpec());
122 
123   return m_thread_spec_up.get();
124 }
125 
126 void WatchpointOptions::SetThreadID(lldb::tid_t thread_id) {
127   GetThreadSpec()->SetTID(thread_id);
128 }
129 
130 void WatchpointOptions::GetCallbackDescription(
131     Stream *s, lldb::DescriptionLevel level) const {
132   if (m_callback_baton_sp.get()) {
133     s->EOL();
134     m_callback_baton_sp->GetDescription(s, level);
135   }
136 }
137 
138 void WatchpointOptions::GetDescription(Stream *s,
139                                        lldb::DescriptionLevel level) const {
140   // Figure out if there are any options not at their default value, and only
141   // print anything if there are:
142 
143   if ((GetThreadSpecNoCreate() != nullptr &&
144        GetThreadSpecNoCreate()->HasSpecification())) {
145     if (level == lldb::eDescriptionLevelVerbose) {
146       s->EOL();
147       s->IndentMore();
148       s->Indent();
149       s->PutCString("Watchpoint Options:\n");
150       s->IndentMore();
151       s->Indent();
152     } else
153       s->PutCString(" Options: ");
154 
155     if (m_thread_spec_up)
156       m_thread_spec_up->GetDescription(s, level);
157     else if (level == eDescriptionLevelBrief)
158       s->PutCString("thread spec: no ");
159     if (level == lldb::eDescriptionLevelFull) {
160       s->IndentLess();
161       s->IndentMore();
162     }
163   }
164 
165   GetCallbackDescription(s, level);
166 }
167 
168 void WatchpointOptions::CommandBaton::GetDescription(
169     Stream *s, lldb::DescriptionLevel level) const {
170   const CommandData *data = getItem();
171 
172   if (level == eDescriptionLevelBrief) {
173     s->Printf(", commands = %s",
174               (data && data->user_source.GetSize() > 0) ? "yes" : "no");
175     return;
176   }
177 
178   s->IndentMore();
179   s->Indent("watchpoint commands:\n");
180 
181   s->IndentMore();
182   if (data && data->user_source.GetSize() > 0) {
183     const size_t num_strings = data->user_source.GetSize();
184     for (size_t i = 0; i < num_strings; ++i) {
185       s->Indent(data->user_source.GetStringAtIndex(i));
186       s->EOL();
187     }
188   } else {
189     s->PutCString("No commands.\n");
190   }
191   s->IndentLess();
192   s->IndentLess();
193 }
194