1 | //===-- UnixSignalsTest.cpp -----------------------------------------------===// |
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 | #include <string> |
9 | |
10 | #include "gtest/gtest.h" |
11 | |
12 | #include "lldb/Target/UnixSignals.h" |
13 | #include "llvm/Support/FormatVariadic.h" |
14 | |
15 | using namespace lldb; |
16 | using namespace lldb_private; |
17 | |
18 | class TestSignals : public UnixSignals { |
19 | public: |
20 | TestSignals() { |
21 | m_signals.clear(); |
22 | AddSignal(signo: 2, name: "SIG2" , default_suppress: false, default_stop: true, default_notify: true, description: "DESC2" ); |
23 | AddSignal(signo: 4, name: "SIG4" , default_suppress: true, default_stop: false, default_notify: true, description: "DESC4" ); |
24 | AddSignal(signo: 8, name: "SIG8" , default_suppress: true, default_stop: true, default_notify: true, description: "DESC8" ); |
25 | AddSignal(signo: 16, name: "SIG16" , default_suppress: true, default_stop: false, default_notify: false, description: "DESC16" ); |
26 | AddSignalCode(signo: 16, code: 1, description: "a specific type of SIG16" ); |
27 | AddSignalCode(signo: 16, code: 2, description: "SIG16 with a fault address" , |
28 | print_option: SignalCodePrintOption::Address); |
29 | AddSignalCode(signo: 16, code: 3, description: "bounds violation" , print_option: SignalCodePrintOption::Bounds); |
30 | } |
31 | }; |
32 | |
33 | void ExpectEqArrays(llvm::ArrayRef<int32_t> expected, |
34 | llvm::ArrayRef<int32_t> observed, const char *file, |
35 | int line) { |
36 | std::string location = llvm::formatv(Fmt: "{0}:{1}" , Vals&: file, Vals&: line); |
37 | ASSERT_EQ(expected.size(), observed.size()) << location; |
38 | |
39 | for (size_t i = 0; i < observed.size(); ++i) { |
40 | ASSERT_EQ(expected[i], observed[i]) |
41 | << "array index: " << i << "location:" << location; |
42 | } |
43 | } |
44 | |
45 | #define EXPECT_EQ_ARRAYS(expected, observed) \ |
46 | ExpectEqArrays((expected), (observed), __FILE__, __LINE__); |
47 | |
48 | TEST(UnixSignalsTest, Iteration) { |
49 | TestSignals signals; |
50 | |
51 | EXPECT_EQ(4, signals.GetNumSignals()); |
52 | EXPECT_EQ(2, signals.GetFirstSignalNumber()); |
53 | EXPECT_EQ(4, signals.GetNextSignalNumber(2)); |
54 | EXPECT_EQ(8, signals.GetNextSignalNumber(4)); |
55 | EXPECT_EQ(16, signals.GetNextSignalNumber(8)); |
56 | EXPECT_EQ(LLDB_INVALID_SIGNAL_NUMBER, signals.GetNextSignalNumber(16)); |
57 | } |
58 | |
59 | TEST(UnixSignalsTest, Reset) { |
60 | TestSignals signals; |
61 | bool stop_val = signals.GetShouldStop(signo: 2); |
62 | bool notify_val = signals.GetShouldNotify(signo: 2); |
63 | bool suppress_val = signals.GetShouldSuppress(signo: 2); |
64 | |
65 | // Change two, then reset one and make sure only that one was reset: |
66 | EXPECT_EQ(true, signals.SetShouldNotify(2, !notify_val)); |
67 | EXPECT_EQ(true, signals.SetShouldSuppress(2, !suppress_val)); |
68 | EXPECT_EQ(true, signals.ResetSignal(2, false, true, false)); |
69 | EXPECT_EQ(stop_val, signals.GetShouldStop(2)); |
70 | EXPECT_EQ(notify_val, signals.GetShouldStop(2)); |
71 | EXPECT_EQ(!suppress_val, signals.GetShouldNotify(2)); |
72 | |
73 | // Make sure reset with no arguments resets them all: |
74 | EXPECT_EQ(true, signals.SetShouldSuppress(2, !suppress_val)); |
75 | EXPECT_EQ(true, signals.SetShouldNotify(2, !notify_val)); |
76 | EXPECT_EQ(true, signals.ResetSignal(2)); |
77 | EXPECT_EQ(stop_val, signals.GetShouldStop(2)); |
78 | EXPECT_EQ(notify_val, signals.GetShouldNotify(2)); |
79 | EXPECT_EQ(suppress_val, signals.GetShouldSuppress(2)); |
80 | } |
81 | |
82 | TEST(UnixSignalsTest, GetInfo) { |
83 | TestSignals signals; |
84 | |
85 | bool should_suppress = false, should_stop = false, should_notify = false; |
86 | int32_t signo = 4; |
87 | bool success = |
88 | signals.GetSignalInfo(signo, should_suppress, should_stop, should_notify); |
89 | ASSERT_TRUE(success); |
90 | EXPECT_EQ(true, should_suppress); |
91 | EXPECT_EQ(false, should_stop); |
92 | EXPECT_EQ(true, should_notify); |
93 | |
94 | EXPECT_EQ(true, signals.GetShouldSuppress(signo)); |
95 | EXPECT_EQ(false, signals.GetShouldStop(signo)); |
96 | EXPECT_EQ(true, signals.GetShouldNotify(signo)); |
97 | } |
98 | |
99 | TEST(UnixSignalsTest, GetAsStringRef) { |
100 | TestSignals signals; |
101 | |
102 | ASSERT_EQ(llvm::StringRef(), signals.GetSignalAsStringRef(100)); |
103 | ASSERT_EQ("SIG16" , signals.GetSignalAsStringRef(16)); |
104 | } |
105 | |
106 | TEST(UnixSignalsTest, GetAsString) { |
107 | TestSignals signals; |
108 | |
109 | ASSERT_EQ("" , signals.GetSignalDescription(100, std::nullopt)); |
110 | ASSERT_EQ("SIG16" , signals.GetSignalDescription(16, std::nullopt)); |
111 | ASSERT_EQ("" , signals.GetSignalDescription(100, 100)); |
112 | ASSERT_EQ("SIG16" , signals.GetSignalDescription(16, 100)); |
113 | ASSERT_EQ("SIG16: a specific type of SIG16" , |
114 | signals.GetSignalDescription(16, 1)); |
115 | |
116 | // Unknown code, won't use the address. |
117 | ASSERT_EQ("SIG16" , signals.GetSignalDescription(16, 100, 0xCAFEF00D)); |
118 | // Known code, that shouldn't print fault address. |
119 | ASSERT_EQ("SIG16: a specific type of SIG16" , |
120 | signals.GetSignalDescription(16, 1, 0xCAFEF00D)); |
121 | // Known code that should. |
122 | ASSERT_EQ("SIG16: SIG16 with a fault address (fault address: 0xcafef00d)" , |
123 | signals.GetSignalDescription(16, 2, 0xCAFEF00D)); |
124 | // No address given just print the code description. |
125 | ASSERT_EQ("SIG16: SIG16 with a fault address" , |
126 | signals.GetSignalDescription(16, 2)); |
127 | |
128 | const char *expected = "SIG16: bounds violation" ; |
129 | // Must pass all needed info to get full output. |
130 | ASSERT_EQ(expected, signals.GetSignalDescription(16, 3)); |
131 | ASSERT_EQ(expected, signals.GetSignalDescription(16, 3, 0xcafef00d)); |
132 | ASSERT_EQ(expected, signals.GetSignalDescription(16, 3, 0xcafef00d, 0x1234)); |
133 | |
134 | ASSERT_EQ("SIG16: upper bound violation (fault address: 0x5679, lower bound: " |
135 | "0x1234, upper bound: 0x5678)" , |
136 | signals.GetSignalDescription(16, 3, 0x5679, 0x1234, 0x5678)); |
137 | ASSERT_EQ("SIG16: lower bound violation (fault address: 0x1233, lower bound: " |
138 | "0x1234, upper bound: 0x5678)" , |
139 | signals.GetSignalDescription(16, 3, 0x1233, 0x1234, 0x5678)); |
140 | } |
141 | |
142 | TEST(UnixSignalsTest, VersionChange) { |
143 | TestSignals signals; |
144 | |
145 | int32_t signo = 8; |
146 | uint64_t ver = signals.GetVersion(); |
147 | EXPECT_GT(ver, 0ull); |
148 | EXPECT_EQ(true, signals.GetShouldSuppress(signo)); |
149 | EXPECT_EQ(true, signals.GetShouldStop(signo)); |
150 | EXPECT_EQ(true, signals.GetShouldNotify(signo)); |
151 | |
152 | EXPECT_EQ(signals.GetVersion(), ver); |
153 | |
154 | signals.SetShouldSuppress(signo, value: false); |
155 | EXPECT_LT(ver, signals.GetVersion()); |
156 | ver = signals.GetVersion(); |
157 | |
158 | signals.SetShouldStop(signo, value: true); |
159 | EXPECT_LT(ver, signals.GetVersion()); |
160 | ver = signals.GetVersion(); |
161 | |
162 | signals.SetShouldNotify(signo, value: false); |
163 | EXPECT_LT(ver, signals.GetVersion()); |
164 | ver = signals.GetVersion(); |
165 | |
166 | EXPECT_EQ(false, signals.GetShouldSuppress(signo)); |
167 | EXPECT_EQ(true, signals.GetShouldStop(signo)); |
168 | EXPECT_EQ(false, signals.GetShouldNotify(signo)); |
169 | |
170 | EXPECT_EQ(ver, signals.GetVersion()); |
171 | } |
172 | |
173 | TEST(UnixSignalsTest, GetFilteredSignals) { |
174 | TestSignals signals; |
175 | |
176 | auto all_signals = |
177 | signals.GetFilteredSignals(should_suppress: std::nullopt, should_stop: std::nullopt, should_notify: std::nullopt); |
178 | std::vector<int32_t> expected = {2, 4, 8, 16}; |
179 | EXPECT_EQ_ARRAYS(expected, all_signals); |
180 | |
181 | auto supressed = signals.GetFilteredSignals(should_suppress: true, should_stop: std::nullopt, should_notify: std::nullopt); |
182 | expected = {4, 8, 16}; |
183 | EXPECT_EQ_ARRAYS(expected, supressed); |
184 | |
185 | auto not_supressed = |
186 | signals.GetFilteredSignals(should_suppress: false, should_stop: std::nullopt, should_notify: std::nullopt); |
187 | expected = {2}; |
188 | EXPECT_EQ_ARRAYS(expected, not_supressed); |
189 | |
190 | auto stopped = signals.GetFilteredSignals(should_suppress: std::nullopt, should_stop: true, should_notify: std::nullopt); |
191 | expected = {2, 8}; |
192 | EXPECT_EQ_ARRAYS(expected, stopped); |
193 | |
194 | auto not_stopped = |
195 | signals.GetFilteredSignals(should_suppress: std::nullopt, should_stop: false, should_notify: std::nullopt); |
196 | expected = {4, 16}; |
197 | EXPECT_EQ_ARRAYS(expected, not_stopped); |
198 | |
199 | auto notified = signals.GetFilteredSignals(should_suppress: std::nullopt, should_stop: std::nullopt, should_notify: true); |
200 | expected = {2, 4, 8}; |
201 | EXPECT_EQ_ARRAYS(expected, notified); |
202 | |
203 | auto not_notified = |
204 | signals.GetFilteredSignals(should_suppress: std::nullopt, should_stop: std::nullopt, should_notify: false); |
205 | expected = {16}; |
206 | EXPECT_EQ_ARRAYS(expected, not_notified); |
207 | |
208 | auto signal4 = signals.GetFilteredSignals(should_suppress: true, should_stop: false, should_notify: true); |
209 | expected = {4}; |
210 | EXPECT_EQ_ARRAYS(expected, signal4); |
211 | } |
212 | |