1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17 #include <csignal>
18 #include <map>
19 #include <securec.h>
20 #include <string>
21 #include <thread>
22 #include <unistd.h>
23 #include <vector>
24 #include <sys/prctl.h>
25
26 #include "dfx_define.h"
27 #include "dfx_signal_local_handler.h"
28 #include "dfx_signal_handler.h"
29 #include "dfx_test_util.h"
30
31 using namespace testing;
32 using namespace testing::ext;
33 using namespace std;
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 class SignalHandlerTest : public testing::Test {
38 public:
39 static void SetUpTestCase();
40 static void TearDownTestCase();
41 void SetUp();
42 void TearDown();
43 };
44
SetUpTestCase()45 void SignalHandlerTest::SetUpTestCase()
46 {}
47
TearDownTestCase()48 void SignalHandlerTest::TearDownTestCase()
49 {}
50
SetUp()51 void SignalHandlerTest::SetUp()
52 {}
53
TearDown()54 void SignalHandlerTest::TearDown()
55 {}
56
CheckLocalCrashKeyWords(const string & filePath,pid_t pid,int sig)57 static bool CheckLocalCrashKeyWords(const string& filePath, pid_t pid, int sig)
58 {
59 if (filePath.empty() || pid <= 0) {
60 return false;
61 }
62 map<int, string> sigKey = {
63 { SIGILL, string("Signal(4)") },
64 { SIGABRT, string("Signal(6)") },
65 { SIGBUS, string("Signal(7)") },
66 { SIGSEGV, string("Signal(11)") },
67 };
68 string sigKeyword = "";
69 map<int, string>::iterator iter = sigKey.find(sig);
70 if (iter != sigKey.end()) {
71 sigKeyword = iter->second;
72 }
73 #ifdef __aarch64__
74 string keywords[] = {
75 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler",
76 sigKeyword, "Tid:", "fp", "x0:", "test_signalhandler"
77 };
78 #else
79 string keywords[] = {
80 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler",
81 sigKeyword, "Tid:", "#00", "test_signalhandler"
82 };
83 #endif
84
85 int length = sizeof(keywords) / sizeof(keywords[0]);
86 int minRegIdx = -1;
87 return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
88 }
89
CheckThreadCrashKeyWords(const string & filePath,pid_t pid,int sig)90 static bool CheckThreadCrashKeyWords(const string& filePath, pid_t pid, int sig)
91 {
92 if (filePath.empty() || pid <= 0) {
93 return false;
94 }
95 map<int, string> sigKey = {
96 { SIGILL, string("SIGILL") },
97 { SIGBUS, string("SIGBUS") },
98 { SIGSEGV, string("SIGSEGV") },
99 };
100 string sigKeyword = "";
101 map<int, string>::iterator iter = sigKey.find(sig);
102 if (iter != sigKey.end()) {
103 sigKeyword = iter->second;
104 }
105 string keywords[] = {
106 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword, "LastFatalMessage:",
107 "Tid:", "#00", "Registers:", "FaultStack:", "Maps:", "test_signalhandler"
108 };
109 int length = sizeof(keywords) / sizeof(keywords[0]);
110 int minRegIdx = -1;
111 return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
112 }
CheckCrashKeyWords(const string & filePath,pid_t pid,int sig)113 static bool CheckCrashKeyWords(const string& filePath, pid_t pid, int sig)
114 {
115 if (filePath.empty() || pid <= 0) {
116 return false;
117 }
118 map<int, string> sigKey = {
119 { SIGILL, string("SIGILL") },
120 { SIGBUS, string("SIGBUS") },
121 { SIGSEGV, string("SIGSEGV") },
122 { SIGABRT, string("SIGABRT") },
123 { SIGFPE, string("SIGFPE") },
124 { SIGSTKFLT, string("SIGSTKFLT") },
125 { SIGSYS, string("SIGSYS") },
126 { SIGTRAP, string("SIGTRAP") },
127 };
128 string sigKeyword = "";
129 map<int, string>::iterator iter = sigKey.find(sig);
130 if (iter != sigKey.end()) {
131 sigKeyword = iter->second;
132 }
133 string keywords[] = {
134 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword,
135 "Tid:", "#00", "Registers:", "FaultStack:", "Maps:", "test_signalhandler"
136 };
137 int length = sizeof(keywords) / sizeof(keywords[0]);
138 int minRegIdx = -1;
139 return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
140 }
141
ThreadInfo(char * buf,size_t len,void * context)142 void ThreadInfo(char* buf, size_t len, void* context __attribute__((unused)))
143 {
144 char mes[] = "this is cash information of test thread";
145 (void)memcpy_s(buf, len, mes, sizeof(mes));
146 }
147
TestThread(int threadId,int sig)148 int TestThread(int threadId, int sig)
149 {
150 std::string subThreadName = "SubTestThread" + to_string(threadId);
151 prctl(PR_SET_NAME, subThreadName.c_str());
152 SetThreadInfoCallback(ThreadInfo);
153 int cashThreadId = 2;
154 if (threadId == cashThreadId) {
155 GTEST_LOG_(INFO) << subThreadName << " is ready to raise signo(" << sig <<")";
156 raise(sig);
157 }
158 return 0;
159 }
160
161 /**
162 * @tc.name: LocalHandlerTest001
163 * @tc.desc: test crashlocalhandler signo(SIGILL)
164 * @tc.type: FUNC
165 */
166 HWTEST_F(SignalHandlerTest, LocalHandlerTest001, TestSize.Level2)
167 {
168 GTEST_LOG_(INFO) << "LocalHandlerTest001: start.";
169 pid_t pid = fork();
170 if (pid < 0) {
171 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
172 } else if (pid == 0) {
173 DFX_InstallLocalSignalHandler();
174 sleep(1);
175 } else {
176 usleep(10000); // 10000 : sleep 10ms
177 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
178 kill(pid, SIGILL);
179 sleep(2); // 2 : wait for cppcrash generating
180 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
181 ASSERT_TRUE(ret);
182 }
183 GTEST_LOG_(INFO) << "LocalHandlerTest001: end.";
184 }
185
186 /**
187 * @tc.name: LocalHandlerTest002
188 * @tc.desc: test crashlocalhandler signo(SIGABRT)
189 * @tc.type: FUNC
190 */
191 HWTEST_F(SignalHandlerTest, LocalHandlerTest002, TestSize.Level2)
192 {
193 GTEST_LOG_(INFO) << "LocalHandlerTest002: start.";
194 pid_t pid = fork();
195 if (pid < 0) {
196 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
197 } else if (pid == 0) {
198 DFX_InstallLocalSignalHandler();
199 sleep(1);
200 } else {
201 usleep(10000); // 10000 : sleep 10ms
202 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
203 kill(pid, SIGABRT);
204 sleep(2); // 2 : wait for cppcrash generating
205 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT);
206 ASSERT_TRUE(ret);
207 }
208 GTEST_LOG_(INFO) << "LocalHandlerTest002: end.";
209 }
210
211 /**
212 * @tc.name: LocalHandlerTest003
213 * @tc.desc: test crashlocalhandler signo(SIGBUS)
214 * @tc.type: FUNC
215 */
216 HWTEST_F(SignalHandlerTest, LocalHandlerTest003, TestSize.Level2)
217 {
218 GTEST_LOG_(INFO) << "LocalHandlerTest003: start.";
219 pid_t pid = fork();
220 if (pid < 0) {
221 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
222 } else if (pid == 0) {
223 DFX_InstallLocalSignalHandler();
224 sleep(1);
225 } else {
226 usleep(10000); // 10000 : sleep 10ms
227 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
228 kill(pid, SIGBUS);
229 sleep(2); // 2 : wait for cppcrash generating
230 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
231 ASSERT_TRUE(ret);
232 }
233 GTEST_LOG_(INFO) << "LocalHandlerTest003: end.";
234 }
235
236 /**
237 * @tc.name: LocalHandlerTest004
238 * @tc.desc: test crashlocalhandler signo(SIGSEGV)
239 * @tc.type: FUNC
240 */
241 HWTEST_F(SignalHandlerTest, LocalHandlerTest004, TestSize.Level2)
242 {
243 GTEST_LOG_(INFO) << "LocalHandlerTest004: start.";
244 pid_t pid = fork();
245 if (pid < 0) {
246 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
247 } else if (pid == 0) {
248 DFX_InstallLocalSignalHandler();
249 sleep(1);
250 } else {
251 usleep(10000); // 10000 : sleep 10ms
252 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
253 kill(pid, SIGSEGV);
254 sleep(2); // 2 : wait for cppcrash generating
255 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
256 ASSERT_TRUE(ret);
257 }
258 GTEST_LOG_(INFO) << "LocalHandlerTest004: end.";
259 }
260
261 /**
262 * @tc.name: LocalHandlerTest005
263 * @tc.desc: test crashlocalhandler signo(SIGSEGV) by execl
264 * @tc.type: FUNC
265 */
266 HWTEST_F(SignalHandlerTest, LocalHandlerTest005, TestSize.Level2)
267 {
268 GTEST_LOG_(INFO) << "LocalHandlerTest005: start.";
269 pid_t pid = fork();
270 if (pid < 0) {
271 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
272 } else if (pid == 0) {
273 DFX_InstallLocalSignalHandler();
274 sleep(1);
275 raise(SIGSEGV);
276 } else {
277 usleep(10000); // 10000 : sleep 10ms
278 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to wait process(" << pid << ")";
279 sleep(2); // 2 : wait for cppcrash generating
280 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
281 ASSERT_TRUE(ret);
282 }
283 GTEST_LOG_(INFO) << "LocalHandlerTest005: end.";
284 }
285
286 /**
287 * @tc.name: SignalHandlerTest001
288 * @tc.desc: test thread cash SignalHandler signo(SIGILL)
289 * @tc.type: FUNC
290 */
291 HWTEST_F(SignalHandlerTest, SignalHandlerTest001, TestSize.Level2)
292 {
293 GTEST_LOG_(INFO) << "SignalHandlerTest001: start.";
294 pid_t pid = fork();
295 if (pid < 0) {
296 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
297 } else if (pid == 0) {
298 SetThreadInfoCallback(ThreadInfo);
299 sleep(1);
300 } else {
301 usleep(10000); // 10000 : sleep 10ms
302 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
303 kill(pid, SIGILL);
304 sleep(2); // 2 : wait for cppcrash generating
305 bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
306 ASSERT_TRUE(ret);
307 }
308 GTEST_LOG_(INFO) << "SignalHandlerTest001: end.";
309 }
310
311 /**
312 * @tc.name: SignalHandlerTest002
313 * @tc.desc: test thread cash SignalHandler signo(SIGBUS)
314 * @tc.type: FUNC
315 */
316 HWTEST_F(SignalHandlerTest, SignalHandlerTest002, TestSize.Level2)
317 {
318 GTEST_LOG_(INFO) << "SignalHandlerTest002: start.";
319 pid_t pid = fork();
320 if (pid < 0) {
321 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
322 } else if (pid == 0) {
323 SetThreadInfoCallback(ThreadInfo);
324 sleep(1);
325 } else {
326 usleep(10000); // 10000 : sleep 10ms
327 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
328 kill(pid, SIGBUS);
329 sleep(2); // 2 : wait for cppcrash generating
330 bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
331 ASSERT_TRUE(ret);
332 }
333 GTEST_LOG_(INFO) << "SignalHandlerTest002: end.";
334 }
335
336 /**
337 * @tc.name: SignalHandlerTest003
338 * @tc.desc: test thread cash SignalHandler signo(SIGSEGV)
339 * @tc.type: FUNC
340 */
341 HWTEST_F(SignalHandlerTest, SignalHandlerTest003, TestSize.Level2)
342 {
343 GTEST_LOG_(INFO) << "SignalHandlerTest003: start.";
344 pid_t pid = fork();
345 if (pid < 0) {
346 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
347 } else if (pid == 0) {
348 SetThreadInfoCallback(ThreadInfo);
349 sleep(1);
350 } else {
351 usleep(10000); // 10000 : sleep 10ms
352 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
353 kill(pid, SIGSEGV);
354 sleep(2); // 2 : wait for cppcrash generating
355 bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
356 ASSERT_TRUE(ret);
357 }
358 GTEST_LOG_(INFO) << "SignalHandlerTest003: end.";
359 }
360
361 /**
362 * @tc.name: SignalHandlerTest004
363 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGILL)
364 * @tc.type: FUNC
365 */
366 HWTEST_F(SignalHandlerTest, SignalHandlerTest004, TestSize.Level2)
367 {
368 GTEST_LOG_(INFO) << "SignalHandlerTest004: start.";
369 pid_t pid = fork();
370 if (pid < 0) {
371 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
372 } else if (pid == 0) {
373 std::thread (TestThread, 1, SIGILL).join(); // 1 : first thread
374 std::thread (TestThread, 2, SIGILL).join(); // 2 : second thread
375 } else {
376 sleep(2); // 2 : wait for cppcrash generating
377 bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
378 ASSERT_TRUE(ret);
379 }
380 GTEST_LOG_(INFO) << "SignalHandlerTest004: end.";
381 }
382
383 /**
384 * @tc.name: SignalHandlerTest005
385 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGBUS)
386 * @tc.type: FUNC
387 */
388 HWTEST_F(SignalHandlerTest, SignalHandlerTest005, TestSize.Level2)
389 {
390 GTEST_LOG_(INFO) << "SignalHandlerTest005: start.";
391 pid_t pid = fork();
392 if (pid < 0) {
393 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
394 } else if (pid == 0) {
395 std::thread (TestThread, 1, SIGBUS).join(); // 1 : first thread
396 std::thread (TestThread, 2, SIGBUS).join(); // 2 : second thread
397 } else {
398 sleep(2); // 2 : wait for cppcrash generating
399 bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
400 ASSERT_TRUE(ret);
401 }
402 GTEST_LOG_(INFO) << "SignalHandlerTest005: end.";
403 }
404
405 /**
406 * @tc.name: SignalHandlerTest006
407 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGSEGV)
408 * @tc.type: FUNC
409 */
410 HWTEST_F(SignalHandlerTest, SignalHandlerTest006, TestSize.Level2)
411 {
412 GTEST_LOG_(INFO) << "SignalHandlerTest006: start.";
413 pid_t pid = fork();
414 if (pid < 0) {
415 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
416 } else if (pid == 0) {
417 std::thread (TestThread, 1, SIGSEGV).join(); // 1 : first thread
418 std::thread (TestThread, 2, SIGSEGV).join(); // 2 : second thread
419 } else {
420 sleep(2); // 2 : wait for cppcrash generating
421 bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
422 ASSERT_TRUE(ret);
423 }
424 GTEST_LOG_(INFO) << "SignalHandlerTest006: end.";
425 }
426
427 /**
428 * @tc.name: SignalHandlerTest007
429 * @tc.desc: test DFX_InstallSignalHandler interface
430 * @tc.type: FUNC
431 */
432 HWTEST_F(SignalHandlerTest, SignalHandlerTest007, TestSize.Level2)
433 {
434 GTEST_LOG_(INFO) << "SignalHandlerTest007: start.";
435 int interestedSignalList[] = {
436 SIGABRT, SIGBUS, SIGFPE,
437 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
438 };
439 for (int sig : interestedSignalList) {
440 pid_t pid = fork();
441 if (pid < 0) {
442 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
443 } else if (pid == 0) {
444 DFX_InstallSignalHandler();
445 sleep(1);
446 } else {
447 usleep(10000); // 10000 : sleep 10ms
448 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill << process(" << pid << ")";
449 GTEST_LOG_(INFO) << "signal:" << sig;
450 kill(pid, sig);
451 sleep(2); // 2 : wait for cppcrash generating
452 bool ret = CheckCrashKeyWords(GetCppCrashFileName(pid), pid, sig);
453 ASSERT_TRUE(ret);
454 }
455 }
456 GTEST_LOG_(INFO) << "SignalHandlerTest007: end.";
457 }
458 } // namespace HiviewDFX
459 } // namepsace OHOS
460