1 //===-- UnixSignals.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_TARGET_UNIXSIGNALS_H
10 #define LLDB_TARGET_UNIXSIGNALS_H
11 
12 #include <map>
13 #include <optional>
14 #include <string>
15 #include <vector>
16 
17 #include "lldb/lldb-private.h"
18 #include "llvm/Support/JSON.h"
19 
20 namespace lldb_private {
21 
22 class UnixSignals {
23 public:
24   static lldb::UnixSignalsSP Create(const ArchSpec &arch);
25   static lldb::UnixSignalsSP CreateForHost();
26 
27   // Constructors and Destructors
28   UnixSignals();
29 
30   virtual ~UnixSignals();
31 
32   llvm::StringRef GetSignalAsStringRef(int32_t signo) const;
33 
34   std::string
35   GetSignalDescription(int32_t signo,
36                        std::optional<int32_t> code = std::nullopt,
37                        std::optional<lldb::addr_t> addr = std::nullopt,
38                        std::optional<lldb::addr_t> lower = std::nullopt,
39                        std::optional<lldb::addr_t> upper = std::nullopt) const;
40 
41   bool SignalIsValid(int32_t signo) const;
42 
43   int32_t GetSignalNumberFromName(const char *name) const;
44 
45   /// Gets the information for a particular signal
46   ///
47   /// GetSignalInfo takes a signal number and populates 3 out parameters
48   /// describing how lldb should react when a particular signal is received in
49   /// the inferior.
50   ///
51   /// \param[in] signo
52   ///   The signal number to get information about.
53   /// \param[out] should_suppress
54   ///   Should we suppress this signal?
55   /// \param[out] should_stop
56   ///   Should we stop if this signal is received?
57   /// \param[out] should_notify
58   ///   Should we notify the user if this signal is received?
59   ///
60   /// \return
61   ///   Returns a boolean value. Returns true if the out parameters were
62   ///   successfully populated, false otherwise.
63   bool GetSignalInfo(int32_t signo, bool &should_suppress, bool &should_stop,
64                      bool &should_notify) const;
65 
66   bool GetShouldSuppress(int32_t signo) const;
67 
68   bool SetShouldSuppress(int32_t signo, bool value);
69 
70   bool SetShouldSuppress(const char *signal_name, bool value);
71 
72   bool GetShouldStop(int32_t signo) const;
73 
74   bool SetShouldStop(int32_t signo, bool value);
75   bool SetShouldStop(const char *signal_name, bool value);
76 
77   bool GetShouldNotify(int32_t signo) const;
78 
79   bool SetShouldNotify(int32_t signo, bool value);
80 
81   bool SetShouldNotify(const char *signal_name, bool value);
82 
83   bool ResetSignal(int32_t signo, bool reset_stop = true,
84                    bool reset_notify = true, bool reset_suppress = true);
85 
86   // These provide an iterator through the signals available on this system.
87   // Call GetFirstSignalNumber to get the first entry, then iterate on
88   // GetNextSignalNumber till you get back LLDB_INVALID_SIGNAL_NUMBER.
89   int32_t GetFirstSignalNumber() const;
90 
91   int32_t GetNextSignalNumber(int32_t current_signal) const;
92 
93   int32_t GetNumSignals() const;
94 
95   int32_t GetSignalAtIndex(int32_t index) const;
96 
97   // We assume that the elements of this object are constant once it is
98   // constructed, since a process should never need to add or remove symbols as
99   // it runs.  So don't call these functions anywhere but the constructor of
100   // your subclass of UnixSignals or in your Process Plugin's GetUnixSignals
101   // method before you return the UnixSignal object.
102 
103   void AddSignal(int signo, llvm::StringRef name, bool default_suppress,
104                  bool default_stop, bool default_notify,
105                  llvm::StringRef description,
106                  llvm::StringRef alias = llvm::StringRef());
107 
108   enum SignalCodePrintOption { None, Address, Bounds };
109 
110   // Instead of calling this directly, use a ADD_SIGCODE macro to get compile
111   // time checks when on the native platform.
112   void AddSignalCode(
113       int signo, int code, const llvm::StringLiteral description,
114       SignalCodePrintOption print_option = SignalCodePrintOption::None);
115 
116   void RemoveSignal(int signo);
117 
118   /// Track how many times signals are hit as stop reasons.
119   void IncrementSignalHitCount(int signo);
120 
121   /// Get the hit count statistics for signals.
122   ///
123   /// Gettings statistics on the hit counts of signals can help explain why some
124   /// debug sessions are slow since each stop takes a few hundred ms and some
125   /// software use signals a lot and can cause slow debugging performance if
126   /// they are used too often. Even if a signal is not stopped at, it will auto
127   /// continue the process and a delay will happen.
128   llvm::json::Value GetHitCountStatistics() const;
129 
130   // Returns a current version of the data stored in this class. Version gets
131   // incremented each time Set... method is called.
132   uint64_t GetVersion() const;
133 
134   // Returns a vector of signals that meet criteria provided in arguments. Each
135   // should_[suppress|stop|notify] flag can be std::nullopt - no filtering by
136   // this flag true - only signals that have it set to true are returned false -
137   // only signals that have it set to true are returned
138   std::vector<int32_t> GetFilteredSignals(std::optional<bool> should_suppress,
139                                           std::optional<bool> should_stop,
140                                           std::optional<bool> should_notify);
141 
142 protected:
143   // Classes that inherit from UnixSignals can see and modify these
144 
145   struct SignalCode {
146     const llvm::StringLiteral m_description;
147     const SignalCodePrintOption m_print_option;
148   };
149 
150   // The StringRefs in Signal are either backed by string literals or reside in
151   // persistent storage (e.g. a StringSet).
152   struct Signal {
153     llvm::StringRef m_name;
154     llvm::StringRef m_alias;
155     llvm::StringRef m_description;
156     std::map<int32_t, SignalCode> m_codes;
157     uint32_t m_hit_count = 0;
158     bool m_suppress : 1, m_stop : 1, m_notify : 1;
159     bool m_default_suppress : 1, m_default_stop : 1, m_default_notify : 1;
160 
161     Signal(llvm::StringRef name, bool default_suppress, bool default_stop,
162            bool default_notify, llvm::StringRef description,
163            llvm::StringRef alias);
164 
165     ~Signal() = default;
166     void Reset(bool reset_stop, bool reset_notify, bool reset_suppress);
167   };
168 
169   llvm::StringRef GetShortName(llvm::StringRef name) const;
170 
171   virtual void Reset();
172 
173   typedef std::map<int32_t, Signal> collection;
174 
175   collection m_signals;
176 
177   // This version gets incremented every time something is changing in this
178   // 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