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