1af245d11STodd Fiala //===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===//
2af245d11STodd Fiala //
3af245d11STodd Fiala //                     The LLVM Compiler Infrastructure
4af245d11STodd Fiala //
5af245d11STodd Fiala // This file is distributed under the University of Illinois Open Source
6af245d11STodd Fiala // License. See LICENSE.TXT for details.
7af245d11STodd Fiala //
8af245d11STodd Fiala //===----------------------------------------------------------------------===//
9af245d11STodd Fiala 
102fe1d0abSChaoren Lin #include "lldb/Host/common/NativeProcessProtocol.h"
11af245d11STodd Fiala 
12af245d11STodd Fiala #include "lldb/Core/ArchSpec.h"
13e77fce0aSTodd Fiala #include "lldb/Core/ModuleSpec.h"
14af245d11STodd Fiala #include "lldb/Core/State.h"
15511e5cdcSTodd Fiala #include "lldb/Host/Host.h"
162fe1d0abSChaoren Lin #include "lldb/Host/common/NativeRegisterContext.h"
172fe1d0abSChaoren Lin #include "lldb/Host/common/NativeThreadProtocol.h"
182fe1d0abSChaoren Lin #include "lldb/Host/common/SoftwareBreakpoint.h"
19e77fce0aSTodd Fiala #include "lldb/Symbol/ObjectFile.h"
20e77fce0aSTodd Fiala #include "lldb/Target/Process.h"
21e77fce0aSTodd Fiala #include "lldb/Utility/LLDBAssert.h"
226f9e6901SZachary Turner #include "lldb/Utility/Log.h"
23b9c1b51eSKate Stone #include "lldb/lldb-enumerations.h"
24af245d11STodd Fiala 
25af245d11STodd Fiala using namespace lldb;
26af245d11STodd Fiala using namespace lldb_private;
27af245d11STodd Fiala 
28af245d11STodd Fiala // -----------------------------------------------------------------------------
29af245d11STodd Fiala // NativeProcessProtocol Members
30af245d11STodd Fiala // -----------------------------------------------------------------------------
31af245d11STodd Fiala 
32*96e600fcSPavel Labath NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid, int terminal_fd,
33*96e600fcSPavel Labath                                              NativeDelegate &delegate)
34*96e600fcSPavel Labath     : m_pid(pid), m_terminal_fd(terminal_fd) {
35*96e600fcSPavel Labath   bool registered = RegisterNativeDelegate(delegate);
36*96e600fcSPavel Labath   assert(registered);
37*96e600fcSPavel Labath   (void)registered;
38*96e600fcSPavel Labath }
39af245d11STodd Fiala 
4097206d57SZachary Turner lldb_private::Status NativeProcessProtocol::Interrupt() {
4197206d57SZachary Turner   Status error;
42511e5cdcSTodd Fiala #if !defined(SIGSTOP)
43511e5cdcSTodd Fiala   error.SetErrorString("local host does not support signaling");
44511e5cdcSTodd Fiala   return error;
45511e5cdcSTodd Fiala #else
46511e5cdcSTodd Fiala   return Signal(SIGSTOP);
47511e5cdcSTodd Fiala #endif
48511e5cdcSTodd Fiala }
49511e5cdcSTodd Fiala 
5097206d57SZachary Turner Status NativeProcessProtocol::IgnoreSignals(llvm::ArrayRef<int> signals) {
514a705e7eSPavel Labath   m_signals_to_ignore.clear();
524a705e7eSPavel Labath   m_signals_to_ignore.insert(signals.begin(), signals.end());
5397206d57SZachary Turner   return Status();
544a705e7eSPavel Labath }
554a705e7eSPavel Labath 
5697206d57SZachary Turner lldb_private::Status
57b9c1b51eSKate Stone NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr,
58b9c1b51eSKate Stone                                            MemoryRegionInfo &range_info) {
59af245d11STodd Fiala   // Default: not implemented.
6097206d57SZachary Turner   return Status("not implemented");
61af245d11STodd Fiala }
62af245d11STodd Fiala 
633508fc8cSPavel Labath llvm::Optional<WaitStatus> NativeProcessProtocol::GetExitStatus() {
643508fc8cSPavel Labath   if (m_state == lldb::eStateExited)
653508fc8cSPavel Labath     return m_exit_status;
663508fc8cSPavel Labath 
673508fc8cSPavel Labath   return llvm::None;
68af245d11STodd Fiala }
69af245d11STodd Fiala 
703508fc8cSPavel Labath bool NativeProcessProtocol::SetExitStatus(WaitStatus status,
71b9c1b51eSKate Stone                                           bool bNotifyStateChange) {
72af245d11STodd Fiala   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
733508fc8cSPavel Labath   LLDB_LOG(log, "status = {0}, notify = {1}", status, bNotifyStateChange);
74af245d11STodd Fiala 
75af245d11STodd Fiala   // Exit status already set
76b9c1b51eSKate Stone   if (m_state == lldb::eStateExited) {
773508fc8cSPavel Labath     if (m_exit_status)
783508fc8cSPavel Labath       LLDB_LOG(log, "exit status already set to {0}", *m_exit_status);
793508fc8cSPavel Labath     else
803508fc8cSPavel Labath       LLDB_LOG(log, "state is exited, but status not set");
81af245d11STodd Fiala     return false;
82af245d11STodd Fiala   }
83af245d11STodd Fiala 
84af245d11STodd Fiala   m_state = lldb::eStateExited;
85af245d11STodd Fiala   m_exit_status = status;
86af245d11STodd Fiala 
87af245d11STodd Fiala   if (bNotifyStateChange)
88af245d11STodd Fiala     SynchronouslyNotifyProcessStateChanged(lldb::eStateExited);
89af245d11STodd Fiala 
90af245d11STodd Fiala   return true;
91af245d11STodd Fiala }
92af245d11STodd Fiala 
93b9c1b51eSKate Stone NativeThreadProtocolSP NativeProcessProtocol::GetThreadAtIndex(uint32_t idx) {
9416ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
95af245d11STodd Fiala   if (idx < m_threads.size())
96af245d11STodd Fiala     return m_threads[idx];
97af245d11STodd Fiala   return NativeThreadProtocolSP();
98af245d11STodd Fiala }
99af245d11STodd Fiala 
100af245d11STodd Fiala NativeThreadProtocolSP
101b9c1b51eSKate Stone NativeProcessProtocol::GetThreadByIDUnlocked(lldb::tid_t tid) {
102b9c1b51eSKate Stone   for (auto thread_sp : m_threads) {
103af245d11STodd Fiala     if (thread_sp->GetID() == tid)
104af245d11STodd Fiala       return thread_sp;
105af245d11STodd Fiala   }
106af245d11STodd Fiala   return NativeThreadProtocolSP();
107af245d11STodd Fiala }
108af245d11STodd Fiala 
109b9c1b51eSKate Stone NativeThreadProtocolSP NativeProcessProtocol::GetThreadByID(lldb::tid_t tid) {
11016ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
111511e5cdcSTodd Fiala   return GetThreadByIDUnlocked(tid);
112511e5cdcSTodd Fiala }
113511e5cdcSTodd Fiala 
114b9c1b51eSKate Stone bool NativeProcessProtocol::IsAlive() const {
115b9c1b51eSKate Stone   return m_state != eStateDetached && m_state != eStateExited &&
116b9c1b51eSKate Stone          m_state != eStateInvalid && m_state != eStateUnloaded;
117af245d11STodd Fiala }
118af245d11STodd Fiala 
119b9c1b51eSKate Stone bool NativeProcessProtocol::GetByteOrder(lldb::ByteOrder &byte_order) const {
120af245d11STodd Fiala   ArchSpec process_arch;
121af245d11STodd Fiala   if (!GetArchitecture(process_arch))
122af245d11STodd Fiala     return false;
123af245d11STodd Fiala   byte_order = process_arch.GetByteOrder();
124af245d11STodd Fiala   return true;
125af245d11STodd Fiala }
126af245d11STodd Fiala 
12718fe6404SChaoren Lin const NativeWatchpointList::WatchpointMap &
128b9c1b51eSKate Stone NativeProcessProtocol::GetWatchpointMap() const {
12918fe6404SChaoren Lin   return m_watchpoint_list.GetWatchpointMap();
13018fe6404SChaoren Lin }
13118fe6404SChaoren Lin 
132d5ffbad2SOmair Javaid llvm::Optional<std::pair<uint32_t, uint32_t>>
133d5ffbad2SOmair Javaid NativeProcessProtocol::GetHardwareDebugSupportInfo() const {
134af245d11STodd Fiala   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
135af245d11STodd Fiala 
136af245d11STodd Fiala   // get any thread
137b9c1b51eSKate Stone   NativeThreadProtocolSP thread_sp(
138b9c1b51eSKate Stone       const_cast<NativeProcessProtocol *>(this)->GetThreadAtIndex(0));
139b9c1b51eSKate Stone   if (!thread_sp) {
140af245d11STodd Fiala     if (log)
141b9c1b51eSKate Stone       log->Warning("NativeProcessProtocol::%s (): failed to find a thread to "
142b9c1b51eSKate Stone                    "grab a NativeRegisterContext!",
143b9c1b51eSKate Stone                    __FUNCTION__);
144d5ffbad2SOmair Javaid     return llvm::None;
145af245d11STodd Fiala   }
146af245d11STodd Fiala 
147af245d11STodd Fiala   NativeRegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
148b9c1b51eSKate Stone   if (!reg_ctx_sp) {
149af245d11STodd Fiala     if (log)
150b9c1b51eSKate Stone       log->Warning("NativeProcessProtocol::%s (): failed to get a "
151b9c1b51eSKate Stone                    "RegisterContextNativeProcess from the first thread!",
152b9c1b51eSKate Stone                    __FUNCTION__);
153d5ffbad2SOmair Javaid     return llvm::None;
154af245d11STodd Fiala   }
155af245d11STodd Fiala 
156d5ffbad2SOmair Javaid   return std::make_pair(reg_ctx_sp->NumSupportedHardwareBreakpoints(),
157d5ffbad2SOmair Javaid                         reg_ctx_sp->NumSupportedHardwareWatchpoints());
158af245d11STodd Fiala }
159af245d11STodd Fiala 
16097206d57SZachary Turner Status NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
161b9c1b51eSKate Stone                                             uint32_t watch_flags,
162b9c1b51eSKate Stone                                             bool hardware) {
163af245d11STodd Fiala   // This default implementation assumes setting the watchpoint for
164af245d11STodd Fiala   // the process will require setting the watchpoint for each of the
165af245d11STodd Fiala   // threads.  Furthermore, it will track watchpoints set for the
166af245d11STodd Fiala   // process and will add them to each thread that is attached to
167af245d11STodd Fiala   // via the (FIXME implement) OnThreadAttached () method.
168af245d11STodd Fiala 
169af245d11STodd Fiala   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
170af245d11STodd Fiala 
171af245d11STodd Fiala   // Update the thread list
172af245d11STodd Fiala   UpdateThreads();
173af245d11STodd Fiala 
174af245d11STodd Fiala   // Keep track of the threads we successfully set the watchpoint
175af245d11STodd Fiala   // for.  If one of the thread watchpoint setting operations fails,
176af245d11STodd Fiala   // back off and remove the watchpoint for all the threads that
177af245d11STodd Fiala   // were successfully set so we get back to a consistent state.
178af245d11STodd Fiala   std::vector<NativeThreadProtocolSP> watchpoint_established_threads;
179af245d11STodd Fiala 
180af245d11STodd Fiala   // Tell each thread to set a watchpoint.  In the event that
181af245d11STodd Fiala   // hardware watchpoints are requested but the SetWatchpoint fails,
182af245d11STodd Fiala   // try to set a software watchpoint as a fallback.  It's
183af245d11STodd Fiala   // conceivable that if there are more threads than hardware
184af245d11STodd Fiala   // watchpoints available, some of the threads will fail to set
185af245d11STodd Fiala   // hardware watchpoints while software ones may be available.
18616ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
187b9c1b51eSKate Stone   for (auto thread_sp : m_threads) {
188af245d11STodd Fiala     assert(thread_sp && "thread list should not have a NULL thread!");
189af245d11STodd Fiala     if (!thread_sp)
190af245d11STodd Fiala       continue;
191af245d11STodd Fiala 
19297206d57SZachary Turner     Status thread_error =
193b9c1b51eSKate Stone         thread_sp->SetWatchpoint(addr, size, watch_flags, hardware);
194b9c1b51eSKate Stone     if (thread_error.Fail() && hardware) {
195af245d11STodd Fiala       // Try software watchpoints since we failed on hardware watchpoint setting
196af245d11STodd Fiala       // and we may have just run out of hardware watchpoints.
197af245d11STodd Fiala       thread_error = thread_sp->SetWatchpoint(addr, size, watch_flags, false);
198b9c1b51eSKate Stone       if (thread_error.Success()) {
199af245d11STodd Fiala         if (log)
200b9c1b51eSKate Stone           log->Warning(
201b9c1b51eSKate Stone               "hardware watchpoint requested but software watchpoint set");
202af245d11STodd Fiala       }
203af245d11STodd Fiala     }
204af245d11STodd Fiala 
205b9c1b51eSKate Stone     if (thread_error.Success()) {
206af245d11STodd Fiala       // Remember that we set this watchpoint successfully in
207af245d11STodd Fiala       // case we need to clear it later.
208af245d11STodd Fiala       watchpoint_established_threads.push_back(thread_sp);
209b9c1b51eSKate Stone     } else {
210af245d11STodd Fiala       // Unset the watchpoint for each thread we successfully
211af245d11STodd Fiala       // set so that we get back to a consistent state of "not
212af245d11STodd Fiala       // set" for the watchpoint.
213b9c1b51eSKate Stone       for (auto unwatch_thread_sp : watchpoint_established_threads) {
21497206d57SZachary Turner         Status remove_error = unwatch_thread_sp->RemoveWatchpoint(addr);
215b9c1b51eSKate Stone         if (remove_error.Fail() && log) {
216b9c1b51eSKate Stone           log->Warning("NativeProcessProtocol::%s (): RemoveWatchpoint failed "
217b9c1b51eSKate Stone                        "for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
218b9c1b51eSKate Stone                        __FUNCTION__, GetID(), unwatch_thread_sp->GetID(),
219b9c1b51eSKate Stone                        remove_error.AsCString());
220af245d11STodd Fiala         }
221af245d11STodd Fiala       }
222af245d11STodd Fiala 
223af245d11STodd Fiala       return thread_error;
224af245d11STodd Fiala     }
225af245d11STodd Fiala   }
22618fe6404SChaoren Lin   return m_watchpoint_list.Add(addr, size, watch_flags, hardware);
227af245d11STodd Fiala }
228af245d11STodd Fiala 
22997206d57SZachary Turner Status NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) {
230af245d11STodd Fiala   // Update the thread list
231af245d11STodd Fiala   UpdateThreads();
232af245d11STodd Fiala 
23397206d57SZachary Turner   Status overall_error;
234af245d11STodd Fiala 
23516ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
236b9c1b51eSKate Stone   for (auto thread_sp : m_threads) {
237af245d11STodd Fiala     assert(thread_sp && "thread list should not have a NULL thread!");
238af245d11STodd Fiala     if (!thread_sp)
239af245d11STodd Fiala       continue;
240af245d11STodd Fiala 
24197206d57SZachary Turner     const Status thread_error = thread_sp->RemoveWatchpoint(addr);
242b9c1b51eSKate Stone     if (thread_error.Fail()) {
243af245d11STodd Fiala       // Keep track of the first thread error if any threads
244af245d11STodd Fiala       // fail. We want to try to remove the watchpoint from
245af245d11STodd Fiala       // every thread, though, even if one or more have errors.
246af245d11STodd Fiala       if (!overall_error.Fail())
247af245d11STodd Fiala         overall_error = thread_error;
248af245d11STodd Fiala     }
249af245d11STodd Fiala   }
25097206d57SZachary Turner   const Status error = m_watchpoint_list.Remove(addr);
25118fe6404SChaoren Lin   return overall_error.Fail() ? overall_error : error;
252af245d11STodd Fiala }
253af245d11STodd Fiala 
254d5ffbad2SOmair Javaid const HardwareBreakpointMap &
255d5ffbad2SOmair Javaid NativeProcessProtocol::GetHardwareBreakpointMap() const {
256d5ffbad2SOmair Javaid   return m_hw_breakpoints_map;
257d5ffbad2SOmair Javaid }
258d5ffbad2SOmair Javaid 
25997206d57SZachary Turner Status NativeProcessProtocol::SetHardwareBreakpoint(lldb::addr_t addr,
260d5ffbad2SOmair Javaid                                                     size_t size) {
261d5ffbad2SOmair Javaid   // This default implementation assumes setting a hardware breakpoint for
262d5ffbad2SOmair Javaid   // this process will require setting same hardware breakpoint for each
263d5ffbad2SOmair Javaid   // of its existing threads. New thread will do the same once created.
264d5ffbad2SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
265d5ffbad2SOmair Javaid 
266d5ffbad2SOmair Javaid   // Update the thread list
267d5ffbad2SOmair Javaid   UpdateThreads();
268d5ffbad2SOmair Javaid 
269d5ffbad2SOmair Javaid   // Exit here if target does not have required hardware breakpoint capability.
270d5ffbad2SOmair Javaid   auto hw_debug_cap = GetHardwareDebugSupportInfo();
271d5ffbad2SOmair Javaid 
272d5ffbad2SOmair Javaid   if (hw_debug_cap == llvm::None || hw_debug_cap->first == 0 ||
273d5ffbad2SOmair Javaid       hw_debug_cap->first <= m_hw_breakpoints_map.size())
27497206d57SZachary Turner     return Status("Target does not have required no of hardware breakpoints");
275d5ffbad2SOmair Javaid 
276d5ffbad2SOmair Javaid   // Vector below stores all thread pointer for which we have we successfully
277d5ffbad2SOmair Javaid   // set this hardware breakpoint. If any of the current process threads fails
278d5ffbad2SOmair Javaid   // to set this hardware breakpoint then roll back and remove this breakpoint
279d5ffbad2SOmair Javaid   // for all the threads that had already set it successfully.
280d5ffbad2SOmair Javaid   std::vector<NativeThreadProtocolSP> breakpoint_established_threads;
281d5ffbad2SOmair Javaid 
282d5ffbad2SOmair Javaid   // Request to set a hardware breakpoint for each of current process threads.
283d5ffbad2SOmair Javaid   std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
284d5ffbad2SOmair Javaid   for (auto thread_sp : m_threads) {
285d5ffbad2SOmair Javaid     assert(thread_sp && "thread list should not have a NULL thread!");
286d5ffbad2SOmair Javaid     if (!thread_sp)
287d5ffbad2SOmair Javaid       continue;
288d5ffbad2SOmair Javaid 
28997206d57SZachary Turner     Status thread_error = thread_sp->SetHardwareBreakpoint(addr, size);
290d5ffbad2SOmair Javaid     if (thread_error.Success()) {
291d5ffbad2SOmair Javaid       // Remember that we set this breakpoint successfully in
292d5ffbad2SOmair Javaid       // case we need to clear it later.
293d5ffbad2SOmair Javaid       breakpoint_established_threads.push_back(thread_sp);
294d5ffbad2SOmair Javaid     } else {
295d5ffbad2SOmair Javaid       // Unset the breakpoint for each thread we successfully
296d5ffbad2SOmair Javaid       // set so that we get back to a consistent state of "not
297d5ffbad2SOmair Javaid       // set" for this hardware breakpoint.
298d5ffbad2SOmair Javaid       for (auto rollback_thread_sp : breakpoint_established_threads) {
29997206d57SZachary Turner         Status remove_error =
30097206d57SZachary Turner             rollback_thread_sp->RemoveHardwareBreakpoint(addr);
301d5ffbad2SOmair Javaid         if (remove_error.Fail() && log) {
302d5ffbad2SOmair Javaid           log->Warning("NativeProcessProtocol::%s (): RemoveHardwareBreakpoint"
303d5ffbad2SOmair Javaid                        " failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
304d5ffbad2SOmair Javaid                        __FUNCTION__, GetID(), rollback_thread_sp->GetID(),
305d5ffbad2SOmair Javaid                        remove_error.AsCString());
306d5ffbad2SOmair Javaid         }
307d5ffbad2SOmair Javaid       }
308d5ffbad2SOmair Javaid 
309d5ffbad2SOmair Javaid       return thread_error;
310d5ffbad2SOmair Javaid     }
311d5ffbad2SOmair Javaid   }
312d5ffbad2SOmair Javaid 
313d5ffbad2SOmair Javaid   // Register new hardware breakpoint into hardware breakpoints map of current
314d5ffbad2SOmair Javaid   // process.
315d5ffbad2SOmair Javaid   m_hw_breakpoints_map[addr] = {addr, size};
316d5ffbad2SOmair Javaid 
31797206d57SZachary Turner   return Status();
318d5ffbad2SOmair Javaid }
319d5ffbad2SOmair Javaid 
32097206d57SZachary Turner Status NativeProcessProtocol::RemoveHardwareBreakpoint(lldb::addr_t addr) {
321d5ffbad2SOmair Javaid   // Update the thread list
322d5ffbad2SOmair Javaid   UpdateThreads();
323d5ffbad2SOmair Javaid 
32497206d57SZachary Turner   Status error;
325d5ffbad2SOmair Javaid 
326d5ffbad2SOmair Javaid   std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
327d5ffbad2SOmair Javaid   for (auto thread_sp : m_threads) {
328d5ffbad2SOmair Javaid     assert(thread_sp && "thread list should not have a NULL thread!");
329d5ffbad2SOmair Javaid     if (!thread_sp)
330d5ffbad2SOmair Javaid       continue;
331d5ffbad2SOmair Javaid 
332d5ffbad2SOmair Javaid     error = thread_sp->RemoveHardwareBreakpoint(addr);
333d5ffbad2SOmair Javaid   }
334d5ffbad2SOmair Javaid 
335d5ffbad2SOmair Javaid   // Also remove from hardware breakpoint map of current process.
336d5ffbad2SOmair Javaid   m_hw_breakpoints_map.erase(addr);
337d5ffbad2SOmair Javaid 
338d5ffbad2SOmair Javaid   return error;
339d5ffbad2SOmair Javaid }
340d5ffbad2SOmair Javaid 
341b9c1b51eSKate Stone bool NativeProcessProtocol::RegisterNativeDelegate(
342b9c1b51eSKate Stone     NativeDelegate &native_delegate) {
34316ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
344b9c1b51eSKate Stone   if (std::find(m_delegates.begin(), m_delegates.end(), &native_delegate) !=
345b9c1b51eSKate Stone       m_delegates.end())
346af245d11STodd Fiala     return false;
347af245d11STodd Fiala 
348af245d11STodd Fiala   m_delegates.push_back(&native_delegate);
349af245d11STodd Fiala   native_delegate.InitializeDelegate(this);
350af245d11STodd Fiala   return true;
351af245d11STodd Fiala }
352af245d11STodd Fiala 
353b9c1b51eSKate Stone bool NativeProcessProtocol::UnregisterNativeDelegate(
354b9c1b51eSKate Stone     NativeDelegate &native_delegate) {
35516ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
356af245d11STodd Fiala 
357af245d11STodd Fiala   const auto initial_size = m_delegates.size();
358b9c1b51eSKate Stone   m_delegates.erase(
359b9c1b51eSKate Stone       remove(m_delegates.begin(), m_delegates.end(), &native_delegate),
360b9c1b51eSKate Stone       m_delegates.end());
361af245d11STodd Fiala 
362af245d11STodd Fiala   // We removed the delegate if the count of delegates shrank after
363af245d11STodd Fiala   // removing all copies of the given native_delegate from the vector.
364af245d11STodd Fiala   return m_delegates.size() < initial_size;
365af245d11STodd Fiala }
366af245d11STodd Fiala 
367b9c1b51eSKate Stone void NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged(
368b9c1b51eSKate Stone     lldb::StateType state) {
369af245d11STodd Fiala   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
370af245d11STodd Fiala 
37116ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
372af245d11STodd Fiala   for (auto native_delegate : m_delegates)
373af245d11STodd Fiala     native_delegate->ProcessStateChanged(this, state);
374af245d11STodd Fiala 
375b9c1b51eSKate Stone   if (log) {
376b9c1b51eSKate Stone     if (!m_delegates.empty()) {
377b9c1b51eSKate Stone       log->Printf("NativeProcessProtocol::%s: sent state notification [%s] "
378b9c1b51eSKate Stone                   "from process %" PRIu64,
379af245d11STodd Fiala                   __FUNCTION__, lldb_private::StateAsCString(state), GetID());
380b9c1b51eSKate Stone     } else {
381b9c1b51eSKate Stone       log->Printf("NativeProcessProtocol::%s: would send state notification "
382b9c1b51eSKate Stone                   "[%s] from process %" PRIu64 ", but no delegates",
383af245d11STodd Fiala                   __FUNCTION__, lldb_private::StateAsCString(state), GetID());
384af245d11STodd Fiala     }
385af245d11STodd Fiala   }
386af245d11STodd Fiala }
387af245d11STodd Fiala 
388b9c1b51eSKate Stone void NativeProcessProtocol::NotifyDidExec() {
389a9882ceeSTodd Fiala   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
390a9882ceeSTodd Fiala   if (log)
391b9c1b51eSKate Stone     log->Printf("NativeProcessProtocol::%s - preparing to call delegates",
392b9c1b51eSKate Stone                 __FUNCTION__);
393a9882ceeSTodd Fiala 
394a9882ceeSTodd Fiala   {
39516ff8604SSaleem Abdulrasool     std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
396a9882ceeSTodd Fiala     for (auto native_delegate : m_delegates)
397a9882ceeSTodd Fiala       native_delegate->DidExec(this);
398a9882ceeSTodd Fiala   }
399a9882ceeSTodd Fiala }
400a9882ceeSTodd Fiala 
40197206d57SZachary Turner Status NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr,
402b9c1b51eSKate Stone                                                     uint32_t size_hint) {
403af245d11STodd Fiala   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
404af245d11STodd Fiala   if (log)
405b9c1b51eSKate Stone     log->Printf("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__,
406b9c1b51eSKate Stone                 addr);
407af245d11STodd Fiala 
408b9c1b51eSKate Stone   return m_breakpoint_list.AddRef(
409b9c1b51eSKate Stone       addr, size_hint, false,
410b9c1b51eSKate Stone       [this](lldb::addr_t addr, size_t size_hint, bool /* hardware */,
41197206d57SZachary Turner              NativeBreakpointSP &breakpoint_sp) -> Status {
412b9c1b51eSKate Stone         return SoftwareBreakpoint::CreateSoftwareBreakpoint(
413b9c1b51eSKate Stone             *this, addr, size_hint, breakpoint_sp);
414b9c1b51eSKate Stone       });
415af245d11STodd Fiala }
416af245d11STodd Fiala 
41797206d57SZachary Turner Status NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr,
418d5ffbad2SOmair Javaid                                                bool hardware) {
419d5ffbad2SOmair Javaid   if (hardware)
420d5ffbad2SOmair Javaid     return RemoveHardwareBreakpoint(addr);
421d5ffbad2SOmair Javaid   else
422af245d11STodd Fiala     return m_breakpoint_list.DecRef(addr);
423af245d11STodd Fiala }
424af245d11STodd Fiala 
42597206d57SZachary Turner Status NativeProcessProtocol::EnableBreakpoint(lldb::addr_t addr) {
426af245d11STodd Fiala   return m_breakpoint_list.EnableBreakpoint(addr);
427af245d11STodd Fiala }
428af245d11STodd Fiala 
42997206d57SZachary Turner Status NativeProcessProtocol::DisableBreakpoint(lldb::addr_t addr) {
430af245d11STodd Fiala   return m_breakpoint_list.DisableBreakpoint(addr);
431af245d11STodd Fiala }
432af245d11STodd Fiala 
433b9c1b51eSKate Stone lldb::StateType NativeProcessProtocol::GetState() const {
43416ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
435af245d11STodd Fiala   return m_state;
436af245d11STodd Fiala }
437af245d11STodd Fiala 
438b9c1b51eSKate Stone void NativeProcessProtocol::SetState(lldb::StateType state,
439b9c1b51eSKate Stone                                      bool notify_delegates) {
44016ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
4415830aa75STamas Berghammer 
4425830aa75STamas Berghammer   if (state == m_state)
4435830aa75STamas Berghammer     return;
4445830aa75STamas Berghammer 
445af245d11STodd Fiala   m_state = state;
446af245d11STodd Fiala 
447b9c1b51eSKate Stone   if (StateIsStoppedState(state, false)) {
448af245d11STodd Fiala     ++m_stop_id;
449af245d11STodd Fiala 
450af245d11STodd Fiala     // Give process a chance to do any stop id bump processing, such as
451af245d11STodd Fiala     // clearing cached data that is invalidated each time the process runs.
452af245d11STodd Fiala     // Note if/when we support some threads running, we'll end up needing
453af245d11STodd Fiala     // to manage this per thread and per process.
454af245d11STodd Fiala     DoStopIDBumped(m_stop_id);
455af245d11STodd Fiala   }
456af245d11STodd Fiala 
457af245d11STodd Fiala   // Optionally notify delegates of the state change.
458af245d11STodd Fiala   if (notify_delegates)
459af245d11STodd Fiala     SynchronouslyNotifyProcessStateChanged(state);
460af245d11STodd Fiala }
461af245d11STodd Fiala 
462b9c1b51eSKate Stone uint32_t NativeProcessProtocol::GetStopID() const {
46316ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
464af245d11STodd Fiala   return m_stop_id;
465af245d11STodd Fiala }
466af245d11STodd Fiala 
467b9c1b51eSKate Stone void NativeProcessProtocol::DoStopIDBumped(uint32_t /* newBumpId */) {
468af245d11STodd Fiala   // Default implementation does nothing.
469af245d11STodd Fiala }
4708bc34f4dSOleksiy Vyalov 
47197206d57SZachary Turner Status NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid,
472b9c1b51eSKate Stone                                                          ArchSpec &arch) {
473e77fce0aSTodd Fiala   // Grab process info for the running process.
474e77fce0aSTodd Fiala   ProcessInstanceInfo process_info;
475e77fce0aSTodd Fiala   if (!Host::GetProcessInfo(pid, process_info))
47697206d57SZachary Turner     return Status("failed to get process info");
477e77fce0aSTodd Fiala 
478e77fce0aSTodd Fiala   // Resolve the executable module.
479e77fce0aSTodd Fiala   ModuleSpecList module_specs;
480b9c1b51eSKate Stone   if (!ObjectFile::GetModuleSpecifications(process_info.GetExecutableFile(), 0,
481b9c1b51eSKate Stone                                            0, module_specs))
48297206d57SZachary Turner     return Status("failed to get module specifications");
483e77fce0aSTodd Fiala   lldbassert(module_specs.GetSize() == 1);
484e77fce0aSTodd Fiala 
485e77fce0aSTodd Fiala   arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture();
486e77fce0aSTodd Fiala   if (arch.IsValid())
48797206d57SZachary Turner     return Status();
488e77fce0aSTodd Fiala   else
48997206d57SZachary Turner     return Status(
49097206d57SZachary Turner         "failed to retrieve a valid architecture from the exe module");
491e77fce0aSTodd Fiala }
492e77fce0aSTodd Fiala 
493*96e600fcSPavel Labath NativeProcessProtocol::Factory::~Factory() = default;
494