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
16namespace lldb_private {
17
18// Tells a thread what it needs to do when the process is resumed.
19struct 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.
33class ResumeActionList {
34public:
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
128protected:
129  std::vector<ResumeAction> m_actions;
130  mutable std::vector<bool> m_signal_handled;
131};
132
133struct 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