1 //===-- Debug.h -------------------------------------------------*- 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 #ifndef liblldb_Debug_h_
10 #define liblldb_Debug_h_
11 
12 #include <vector>
13 
14 #include "lldb/lldb-private.h"
15 
16 namespace lldb_private {
17 
18 // Tells a thread what it needs to do when the process is resumed.
19 struct ResumeAction {
20   lldb::tid_t tid;       // The thread ID that this action applies to,
21                          // LLDB_INVALID_THREAD_ID for the default thread
22                          // action
23   lldb::StateType state; // Valid values are eStateStopped/eStateSuspended,
24                          // eStateRunning, and eStateStepping.
25   int signal; // When resuming this thread, resume it with this signal if this
26               // value is > 0
27 };
28 
29 // A class that contains instructions for all threads for
30 // NativeProcessProtocol::Resume(). Each thread can either run, stay suspended,
31 // or step when the process is resumed. We optionally have the ability to also
32 // send a signal to the thread when the action is run or step.
33 class ResumeActionList {
34 public:
35   ResumeActionList() : m_actions(), m_signal_handled() {}
36 
37   ResumeActionList(lldb::StateType default_action, int signal)
38       : m_actions(), m_signal_handled() {
39     SetDefaultThreadActionIfNeeded(default_action, signal);
40   }
41 
42   ResumeActionList(const ResumeAction *actions, size_t num_actions)
43       : m_actions(), m_signal_handled() {
44     if (actions && num_actions) {
45       m_actions.assign(actions, actions + num_actions);
46       m_signal_handled.assign(num_actions, false);
47     }
48   }
49 
50   ~ResumeActionList() = default;
51 
52   bool IsEmpty() const { return m_actions.empty(); }
53 
54   void Append(const ResumeAction &action) {
55     m_actions.push_back(action);
56     m_signal_handled.push_back(false);
57   }
58 
59   void AppendAction(lldb::tid_t tid, lldb::StateType state, int signal = 0) {
60     ResumeAction action = {tid, state, signal};
61     Append(action);
62   }
63 
64   void AppendResumeAll() {
65     AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateRunning);
66   }
67 
68   void AppendSuspendAll() {
69     AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateStopped);
70   }
71 
72   void AppendStepAll() {
73     AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateStepping);
74   }
75 
76   const ResumeAction *GetActionForThread(lldb::tid_t tid,
77                                          bool default_ok) const {
78     const size_t num_actions = m_actions.size();
79     for (size_t i = 0; i < num_actions; ++i) {
80       if (m_actions[i].tid == tid)
81         return &m_actions[i];
82     }
83     if (default_ok && tid != LLDB_INVALID_THREAD_ID)
84       return GetActionForThread(LLDB_INVALID_THREAD_ID, false);
85     return nullptr;
86   }
87 
88   size_t NumActionsWithState(lldb::StateType state) const {
89     size_t count = 0;
90     const size_t num_actions = m_actions.size();
91     for (size_t i = 0; i < num_actions; ++i) {
92       if (m_actions[i].state == state)
93         ++count;
94     }
95     return count;
96   }
97 
98   bool SetDefaultThreadActionIfNeeded(lldb::StateType action, int signal) {
99     if (GetActionForThread(LLDB_INVALID_THREAD_ID, true) == nullptr) {
100       // There isn't a default action so we do need to set it.
101       ResumeAction default_action = {LLDB_INVALID_THREAD_ID, action, signal};
102       m_actions.push_back(default_action);
103       m_signal_handled.push_back(false);
104       return true; // Return true as we did add the default action
105     }
106     return false;
107   }
108 
109   void SetSignalHandledForThread(lldb::tid_t tid) const {
110     if (tid != LLDB_INVALID_THREAD_ID) {
111       const size_t num_actions = m_actions.size();
112       for (size_t i = 0; i < num_actions; ++i) {
113         if (m_actions[i].tid == tid)
114           m_signal_handled[i] = true;
115       }
116     }
117   }
118 
119   const ResumeAction *GetFirst() const { return m_actions.data(); }
120 
121   size_t GetSize() const { return m_actions.size(); }
122 
123   void Clear() {
124     m_actions.clear();
125     m_signal_handled.clear();
126   }
127 
128 protected:
129   std::vector<ResumeAction> m_actions;
130   mutable std::vector<bool> m_signal_handled;
131 };
132 
133 struct ThreadStopInfo {
134   lldb::StopReason reason;
135   union {
136     // eStopReasonSignal
137     struct {
138       uint32_t signo;
139     } signal;
140 
141     // eStopReasonException
142     struct {
143       uint64_t type;
144       uint32_t data_count;
145       lldb::addr_t data[8];
146     } exception;
147   } details;
148 };
149 }
150 
151 #endif // liblldb_Debug_h_
152