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