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