1130812Smarcel//===-- UnixSignals.h -------------------------------------------*- C++ -*-===//
2130812Smarcel//
3130812Smarcel// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4130812Smarcel// See https://llvm.org/LICENSE.txt for license information.
5130812Smarcel// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6130812Smarcel//
7130812Smarcel//===----------------------------------------------------------------------===//
8130812Smarcel
9130812Smarcel#ifndef LLDB_TARGET_UNIXSIGNALS_H
10130812Smarcel#define LLDB_TARGET_UNIXSIGNALS_H
11130812Smarcel
12130812Smarcel#include <map>
13130812Smarcel#include <optional>
14130812Smarcel#include <string>
15130812Smarcel#include <vector>
16130812Smarcel
17130812Smarcel#include "lldb/lldb-private.h"
18130812Smarcel#include "llvm/Support/JSON.h"
19130812Smarcel
20130812Smarcelnamespace lldb_private {
21130812Smarcel
22130812Smarcelclass UnixSignals {
23130812Smarcelpublic:
24130812Smarcel  static lldb::UnixSignalsSP Create(const ArchSpec &arch);
25130812Smarcel  static lldb::UnixSignalsSP CreateForHost();
26130812Smarcel
27130812Smarcel  // Constructors and Destructors
28130812Smarcel  UnixSignals();
29130812Smarcel
30130812Smarcel  virtual ~UnixSignals();
31130812Smarcel
32130812Smarcel  llvm::StringRef GetSignalAsStringRef(int32_t signo) const;
33130812Smarcel
34130812Smarcel  std::string
35130812Smarcel  GetSignalDescription(int32_t signo,
36130812Smarcel                       std::optional<int32_t> code = std::nullopt,
37130812Smarcel                       std::optional<lldb::addr_t> addr = std::nullopt,
38130812Smarcel                       std::optional<lldb::addr_t> lower = std::nullopt,
39130812Smarcel                       std::optional<lldb::addr_t> upper = std::nullopt) const;
40130812Smarcel
41130812Smarcel  bool SignalIsValid(int32_t signo) const;
42130812Smarcel
43130812Smarcel  int32_t GetSignalNumberFromName(const char *name) const;
44130812Smarcel
45130812Smarcel  /// Gets the information for a particular signal
46130812Smarcel  ///
47130812Smarcel  /// GetSignalInfo takes a signal number and populates 3 out parameters
48130812Smarcel  /// describing how lldb should react when a particular signal is received in
49130812Smarcel  /// the inferior.
50130812Smarcel  ///
51130812Smarcel  /// \param[in] signo
52130812Smarcel  ///   The signal number to get information about.
53130812Smarcel  /// \param[out] should_suppress
54130812Smarcel  ///   Should we suppress this signal?
55130812Smarcel  /// \param[out] should_stop
56130812Smarcel  ///   Should we stop if this signal is received?
57130812Smarcel  /// \param[out] should_notify
58130812Smarcel  ///   Should we notify the user if this signal is received?
59130812Smarcel  ///
60130812Smarcel  /// \return
61130812Smarcel  ///   Returns a boolean value. Returns true if the out parameters were
62130812Smarcel  ///   successfully populated, false otherwise.
63130812Smarcel  bool GetSignalInfo(int32_t signo, bool &should_suppress, bool &should_stop,
64130812Smarcel                     bool &should_notify) const;
65130812Smarcel
66130812Smarcel  bool GetShouldSuppress(int32_t signo) const;
67130812Smarcel
68130812Smarcel  bool SetShouldSuppress(int32_t signo, bool value);
69130812Smarcel
70130812Smarcel  bool SetShouldSuppress(const char *signal_name, bool value);
71130812Smarcel
72130812Smarcel  bool GetShouldStop(int32_t signo) const;
73130812Smarcel
74130812Smarcel  bool SetShouldStop(int32_t signo, bool value);
75130812Smarcel  bool SetShouldStop(const char *signal_name, bool value);
76130812Smarcel
77130812Smarcel  bool GetShouldNotify(int32_t signo) const;
78130812Smarcel
79130812Smarcel  bool SetShouldNotify(int32_t signo, bool value);
80130812Smarcel
81130812Smarcel  bool SetShouldNotify(const char *signal_name, bool value);
82130812Smarcel
83130812Smarcel  bool ResetSignal(int32_t signo, bool reset_stop = true,
84130812Smarcel                   bool reset_notify = true, bool reset_suppress = true);
85130812Smarcel
86130812Smarcel  // These provide an iterator through the signals available on this system.
87130812Smarcel  // Call GetFirstSignalNumber to get the first entry, then iterate on
88130812Smarcel  // GetNextSignalNumber till you get back LLDB_INVALID_SIGNAL_NUMBER.
89130812Smarcel  int32_t GetFirstSignalNumber() const;
90130812Smarcel
91130812Smarcel  int32_t GetNextSignalNumber(int32_t current_signal) const;
92130812Smarcel
93130812Smarcel  int32_t GetNumSignals() const;
94130812Smarcel
95130812Smarcel  int32_t GetSignalAtIndex(int32_t index) const;
96130812Smarcel
97130812Smarcel  // We assume that the elements of this object are constant once it is
98130812Smarcel  // constructed, since a process should never need to add or remove symbols as
99130812Smarcel  // it runs.  So don't call these functions anywhere but the constructor of
100130812Smarcel  // your subclass of UnixSignals or in your Process Plugin's GetUnixSignals
101130812Smarcel  // method before you return the UnixSignal object.
102130812Smarcel
103130812Smarcel  void AddSignal(int signo, llvm::StringRef name, bool default_suppress,
104130812Smarcel                 bool default_stop, bool default_notify,
105130812Smarcel                 llvm::StringRef description,
106130812Smarcel                 llvm::StringRef alias = llvm::StringRef());
107130812Smarcel
108130812Smarcel  enum SignalCodePrintOption { None, Address, Bounds };
109130812Smarcel
110130812Smarcel  // Instead of calling this directly, use a ADD_SIGCODE macro to get compile
111130812Smarcel  // time checks when on the native platform.
112130812Smarcel  void AddSignalCode(
113130812Smarcel      int signo, int code, const llvm::StringLiteral description,
114130812Smarcel      SignalCodePrintOption print_option = SignalCodePrintOption::None);
115130812Smarcel
116130812Smarcel  void RemoveSignal(int signo);
117130812Smarcel
118130812Smarcel  /// Track how many times signals are hit as stop reasons.
119130812Smarcel  void IncrementSignalHitCount(int signo);
120130812Smarcel
121130812Smarcel  /// Get the hit count statistics for signals.
122130812Smarcel  ///
123130812Smarcel  /// Gettings statistics on the hit counts of signals can help explain why some
124130812Smarcel  /// debug sessions are slow since each stop takes a few hundred ms and some
125130812Smarcel  /// software use signals a lot and can cause slow debugging performance if
126130812Smarcel  /// they are used too often. Even if a signal is not stopped at, it will auto
127130812Smarcel  /// continue the process and a delay will happen.
128130812Smarcel  llvm::json::Value GetHitCountStatistics() const;
129130812Smarcel
130130812Smarcel  // Returns a current version of the data stored in this class. Version gets
131130812Smarcel  // incremented each time Set... method is called.
132130812Smarcel  uint64_t GetVersion() const;
133130812Smarcel
134130812Smarcel  // Returns a vector of signals that meet criteria provided in arguments. Each
135130812Smarcel  // should_[suppress|stop|notify] flag can be std::nullopt - no filtering by
136130812Smarcel  // this flag true - only signals that have it set to true are returned false -
137130812Smarcel  // only signals that have it set to true are returned
138130812Smarcel  std::vector<int32_t> GetFilteredSignals(std::optional<bool> should_suppress,
139130812Smarcel                                          std::optional<bool> should_stop,
140130812Smarcel                                          std::optional<bool> should_notify);
141130812Smarcel
142130812Smarcelprotected:
143130812Smarcel  // Classes that inherit from UnixSignals can see and modify these
144130812Smarcel
145130812Smarcel  struct SignalCode {
146130812Smarcel    const llvm::StringLiteral m_description;
147130812Smarcel    const SignalCodePrintOption m_print_option;
148130812Smarcel  };
149130812Smarcel
150130812Smarcel  // The StringRefs in Signal are either backed by string literals or reside in
151130812Smarcel  // persistent storage (e.g. a StringSet).
152130812Smarcel  struct Signal {
153130812Smarcel    llvm::StringRef m_name;
154130812Smarcel    llvm::StringRef m_alias;
155130812Smarcel    llvm::StringRef m_description;
156130812Smarcel    std::map<int32_t, SignalCode> m_codes;
157130812Smarcel    uint32_t m_hit_count = 0;
158130812Smarcel    bool m_suppress : 1, m_stop : 1, m_notify : 1;
159130812Smarcel    bool m_default_suppress : 1, m_default_stop : 1, m_default_notify : 1;
160130812Smarcel
161130812Smarcel    Signal(llvm::StringRef name, bool default_suppress, bool default_stop,
162130812Smarcel           bool default_notify, llvm::StringRef description,
163130812Smarcel           llvm::StringRef alias);
164130812Smarcel
165130812Smarcel    ~Signal() = default;
166130812Smarcel    void Reset(bool reset_stop, bool reset_notify, bool reset_suppress);
167130812Smarcel  };
168130812Smarcel
169130812Smarcel  llvm::StringRef GetShortName(llvm::StringRef name) const;
170130812Smarcel
171130812Smarcel  virtual void Reset();
172130812Smarcel
173130812Smarcel  typedef std::map<int32_t, Signal> collection;
174130812Smarcel
175130812Smarcel  collection m_signals;
176130812Smarcel
177130812Smarcel  // This version gets incremented every time something is changing in this
178130812Smarcel  // class, including when we call AddSignal from the constructor. So after the
179  // object is constructed m_version is going to be > 0 if it has at least one
180  // signal registered in it.
181  uint64_t m_version = 0;
182
183  // GDBRemote signals need to be copyable.
184  UnixSignals(const UnixSignals &rhs);
185
186  const UnixSignals &operator=(const UnixSignals &rhs) = delete;
187};
188
189} // Namespace lldb
190#endif // LLDB_TARGET_UNIXSIGNALS_H
191