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 LLDB_HOST_DEBUG_H
10 #define LLDB_HOST_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() = default;
36 
ResumeActionList(lldb::StateType default_action,int signal)37   ResumeActionList(lldb::StateType default_action, int signal) {
38     SetDefaultThreadActionIfNeeded(default_action, signal);
39   }
40 
ResumeActionList(const ResumeAction * actions,size_t num_actions)41   ResumeActionList(const ResumeAction *actions, size_t num_actions) {
42     if (actions && num_actions) {
43       m_actions.assign(actions, actions + num_actions);
44       m_signal_handled.assign(num_actions, false);
45     }
46   }
47 
48   ~ResumeActionList() = default;
49 
IsEmpty()50   bool IsEmpty() const { return m_actions.empty(); }
51 
Append(const ResumeAction & action)52   void Append(const ResumeAction &action) {
53     m_actions.push_back(action);
54     m_signal_handled.push_back(false);
55   }
56 
57   void AppendAction(lldb::tid_t tid, lldb::StateType state, int signal = 0) {
58     ResumeAction action = {tid, state, signal};
59     Append(action);
60   }
61 
AppendResumeAll()62   void AppendResumeAll() {
63     AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateRunning);
64   }
65 
AppendSuspendAll()66   void AppendSuspendAll() {
67     AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateStopped);
68   }
69 
AppendStepAll()70   void AppendStepAll() {
71     AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateStepping);
72   }
73 
GetActionForThread(lldb::tid_t tid,bool default_ok)74   const ResumeAction *GetActionForThread(lldb::tid_t tid,
75                                          bool default_ok) const {
76     const size_t num_actions = m_actions.size();
77     for (size_t i = 0; i < num_actions; ++i) {
78       if (m_actions[i].tid == tid)
79         return &m_actions[i];
80     }
81     if (default_ok && tid != LLDB_INVALID_THREAD_ID)
82       return GetActionForThread(LLDB_INVALID_THREAD_ID, false);
83     return nullptr;
84   }
85 
NumActionsWithState(lldb::StateType state)86   size_t NumActionsWithState(lldb::StateType state) const {
87     size_t count = 0;
88     const size_t num_actions = m_actions.size();
89     for (size_t i = 0; i < num_actions; ++i) {
90       if (m_actions[i].state == state)
91         ++count;
92     }
93     return count;
94   }
95 
SetDefaultThreadActionIfNeeded(lldb::StateType action,int signal)96   bool SetDefaultThreadActionIfNeeded(lldb::StateType action, int signal) {
97     if (GetActionForThread(LLDB_INVALID_THREAD_ID, true) == nullptr) {
98       // There isn't a default action so we do need to set it.
99       ResumeAction default_action = {LLDB_INVALID_THREAD_ID, action, signal};
100       m_actions.push_back(default_action);
101       m_signal_handled.push_back(false);
102       return true; // Return true as we did add the default action
103     }
104     return false;
105   }
106 
SetSignalHandledForThread(lldb::tid_t tid)107   void SetSignalHandledForThread(lldb::tid_t tid) const {
108     if (tid != LLDB_INVALID_THREAD_ID) {
109       const size_t num_actions = m_actions.size();
110       for (size_t i = 0; i < num_actions; ++i) {
111         if (m_actions[i].tid == tid)
112           m_signal_handled[i] = true;
113       }
114     }
115   }
116 
GetFirst()117   const ResumeAction *GetFirst() const { return m_actions.data(); }
118 
GetSize()119   size_t GetSize() const { return m_actions.size(); }
120 
Clear()121   void Clear() {
122     m_actions.clear();
123     m_signal_handled.clear();
124   }
125 
126 protected:
127   std::vector<ResumeAction> m_actions;
128   mutable std::vector<bool> m_signal_handled;
129 };
130 
131 struct ThreadStopInfo {
132   lldb::StopReason reason;
133   uint32_t signo;
134   union {
135     // eStopReasonException
136     struct {
137       uint64_t type;
138       uint32_t data_count;
139       lldb::addr_t data[8];
140     } exception;
141 
142     // eStopReasonFork / eStopReasonVFork
143     struct {
144       lldb::pid_t child_pid;
145       lldb::tid_t child_tid;
146     } fork;
147   } details;
148 };
149 }
150 
151 #endif // LLDB_HOST_DEBUG_H
152