1 /*
2 * Copyright (c) 2021-2022 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 /* This files contains faultlog cpp crasher modules. */
17
18 #include "dfx_crasher.h"
19
20 #include <cinttypes>
21 #include <csignal>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 #include <fstream>
26 #include <hilog/log.h>
27 #include <iostream>
28 #include <pthread.h>
29 #include <sys/prctl.h>
30 #include <sys/resource.h>
31 #include <thread>
32 #include <unistd.h>
33 #include <vector>
34 #include "securec.h"
35
36 #ifdef HAS_HITRACE
37 #include <hitrace/hitracechain.h>
38 using namespace OHOS::HiviewDFX;
39 #endif
40
41 #ifdef LOG_DOMAIN
42 #undef LOG_DOMAIN
43 #define LOG_DOMAIN 0xD002D11
44 #endif
45
46 #ifdef LOG_TAG
47 #undef LOG_TAG
48 #define LOG_TAG "Unwind"
49 #endif
50
51 static const int ARG1024 = 1024;
52 static const int ARG128 = 128;
53
54 static const int NUMBER_TWO = 2;
55 static const int NUMBER_ONE = 1;
56
57 static const int SIGDUMP = 35;
58
DfxCrasher()59 DfxCrasher::DfxCrasher() {}
~DfxCrasher()60 DfxCrasher::~DfxCrasher() {}
61
GetInstance()62 DfxCrasher &DfxCrasher::GetInstance()
63 {
64 static DfxCrasher instance;
65 return instance;
66 }
67
TriggerTrapException() const68 NOINLINE int DfxCrasher::TriggerTrapException() const
69 {
70 __asm__ volatile(".inst 0xde01");
71
72 return 0;
73 }
74
TriggerSegmentFaultException() const75 NOINLINE int DfxCrasher::TriggerSegmentFaultException() const
76 {
77 std::cout << "test TriggerSegmentFaultException" << std::endl;
78 // for crash test force cast the type
79 int *a = (int *)(&TestFunc70);
80 *a = SIGSEGV;
81 return 0;
82 }
83
RaiseAbort() const84 NOINLINE int DfxCrasher::RaiseAbort() const
85 {
86 HILOG_FATAL(LOG_CORE, "Test Trigger ABORT!");
87 raise(SIGABRT);
88 return 0;
89 }
90
Abort(void) const91 NOINLINE int DfxCrasher::Abort(void) const
92 {
93 HILOG_FATAL(LOG_CORE, "Test Trigger ABORT!");
94 abort();
95 return 0;
96 }
97
RaiseBusError() const98 NOINLINE int DfxCrasher::RaiseBusError() const
99 {
100 raise(SIGBUS);
101 return 0;
102 }
103
DumpStackTrace() const104 NOINLINE int DfxCrasher::DumpStackTrace() const
105 {
106 if (raise(SIGDUMP) != 0) {
107 std::cout << "raise error" << std::endl;
108 }
109 return 0;
110 }
111
RaiseFloatingPointException() const112 NOINLINE int DfxCrasher::RaiseFloatingPointException() const
113 {
114 raise(SIGFPE);
115 return 0;
116 }
117
RaiseIllegalInstructionException() const118 NOINLINE int DfxCrasher::RaiseIllegalInstructionException() const
119 {
120 raise(SIGILL);
121 return 0;
122 }
123
IllegalInstructionException(void) const124 NOINLINE int DfxCrasher::IllegalInstructionException(void) const
125 {
126 char mes[] = "ABCDEFGHIJ";
127 char* ptr = mes;
128 ptr = nullptr;
129 *ptr = 0;
130
131 return 0;
132 }
133
SegmentFaultException(void) const134 NOINLINE int DfxCrasher::SegmentFaultException(void) const
135 {
136 volatile char *ptr = nullptr;
137 *ptr;
138
139 return 0;
140 }
141
RaiseSegmentFaultException() const142 NOINLINE int DfxCrasher::RaiseSegmentFaultException() const
143 {
144 std::cout << "call RaiseSegmentFaultException" << std::endl;
145 raise(SIGSEGV);
146 return 0;
147 }
148
RaiseTrapException() const149 NOINLINE int DfxCrasher::RaiseTrapException() const
150 {
151 raise(SIGTRAP);
152 return 0;
153 }
154
MaxStackDepth() const155 NOINLINE int DfxCrasher::MaxStackDepth() const
156 {
157 return TestFunc1();
158 }
159
MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC() const160 NOINLINE int DfxCrasher::MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC() const
161 {
162 std::cout << "call MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC" << std::endl;
163 raise(SIGSEGV);
164 return 0;
165 }
166
StackOverflow() const167 NOINLINE int DfxCrasher::StackOverflow() const
168 {
169 std::cout << "call StackOverflow" << std::endl;
170 // for stack overflow test
171 char a[1024][1024][1024] = { { {'1'} } };
172 char b[1024][1024][1024] = { { {'1'} } };
173 char c[1024][1024][1024] = { { {'1'} } };
174 char d[1024][1024][1024] = { { {'1'} } };
175
176 std::cout << a[0][0] << std::endl;
177 std::cout << b[0][0] << std::endl;
178 std::cout << c[0][0] << std::endl;
179 std::cout << d[0][0] << std::endl;
180
181 return 0;
182 }
183
Oom() const184 NOINLINE int DfxCrasher::Oom() const
185 {
186 std::cout << "test oom" << std::endl;
187 struct rlimit oldRlimit;
188 if (getrlimit(RLIMIT_AS, &oldRlimit) != 0) {
189 std::cout << "getrlimit failed" << std::endl;
190 raise(SIGINT);
191 }
192 std::cout << std::hex << "old rlimit, cur:0x" << oldRlimit.rlim_cur << std::endl;
193 std::cout << std::hex << "old rlimit, max:0x" << oldRlimit.rlim_max << std::endl;
194
195 struct rlimit rlim = {
196 .rlim_cur = ARG128 * ARG1024 * ARG1024,
197 .rlim_max = ARG128 * ARG1024 * ARG1024,
198 };
199
200 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
201 std::cout << "setrlimit failed" << std::endl;
202 raise(SIGINT);
203 }
204
205 std::vector<void*> vec;
206 for (int i = 0; i < ARG128; i++) {
207 char* buf = static_cast<char*>(malloc(ARG1024 * ARG1024));
208 if (!buf) {
209 std::cout << "malloc return null" << std::endl;
210 if (setrlimit(RLIMIT_AS, &oldRlimit) != 0) {
211 std::cout << "restore rlimit failed" << std::endl;
212 }
213 std::cout << "restore rlimit ok" << std::endl;
214 abort();
215 }
216
217 if (memset_s(buf, ARG1024 * ARG1024, 0xff, ARG1024 * ARG1024)) {
218 std::cout << "oom memset_s failed." << std::endl;
219 }
220 vec.push_back(buf);
221 }
222 return 0;
223 }
224
ProgramCounterZero() const225 NOINLINE int DfxCrasher::ProgramCounterZero() const
226 {
227 std::cout << "test PCZero" << std::endl;
228 #if defined(__arm__)
229 __asm__ volatile (
230 "mov r0, #0x00\n mov lr, pc\n bx r0\n"
231 );
232 #elif defined(__aarch64__)
233 __asm__ volatile (
234 "movz x0, #0x0\n"
235 "adr x30, .\n"
236 "br x0\n"
237 );
238 #endif
239 return 0;
240 }
241
MultiThreadCrash() const242 NOINLINE int DfxCrasher::MultiThreadCrash() const
243 {
244 std::cout << "test MultiThreadCrash" << std::endl;
245
246 std::thread (SleepThread, NUMBER_ONE).detach();
247 std::thread (SleepThread, NUMBER_TWO).detach();
248 sleep(1);
249
250 raise(SIGSEGV);
251
252 return 0;
253 }
254
StackOver64() const255 NOINLINE int DfxCrasher::StackOver64() const
256 {
257 std::cout << "test StackOver64" << std::endl;
258
259 return TestFunc1();
260 }
261
SleepThread(int threadID)262 int SleepThread(int threadID)
263 {
264 std::cout << "create MultiThread " << threadID << std::endl;
265
266 int sleepTime = 10;
267 sleep(sleepTime);
268
269 return 0;
270 }
271
StackTop() const272 NOINLINE int DfxCrasher::StackTop() const
273 {
274 std::cout << "test StackTop" << std::endl;
275 #if defined(__arm__)
276 unsigned int stackTop;
277 __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
278 #elif defined(__aarch64__)
279 uint64_t stackTop;
280 __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
281 #endif
282 std::cout << "crasher_c: stack top is = " << std::hex << stackTop << std::endl;
283
284 std::ofstream fout;
285 fout.open("sp");
286 fout << std::hex << stackTop << std::endl;
287 fout.close();
288
289 // trigger an error to crash
290 int a = 1;
291 int *b = &a;
292 b = nullptr;
293 *b = 1;
294
295 return 0;
296 }
297
PrintUsage() const298 void DfxCrasher::PrintUsage() const
299 {
300 std::cout << " usage: crasher CMD" << std::endl;
301 std::cout << "" << std::endl;
302 std::cout << " where CMD support:" << std::endl;
303 std::cout << " SIGFPE raise a SIGFPE" << std::endl;
304 std::cout << " SIGILL raise a SIGILL" << std::endl;
305 std::cout << " SIGSEGV raise a SIGSEGV" << std::endl;
306 std::cout << " SIGTRAP raise a SIGTRAP" << std::endl;
307 std::cout << " SIGABRT raise a SIGABRT" << std::endl;
308 std::cout << " SIGBUS raise a SIGBUS" << std::endl;
309 std::cout << " STACKTRACE raise a SIGDUMP" << std::endl;
310
311 std::cout << " triSIGILL trigger a SIGILL\n" << std::endl;
312 std::cout << " triSIGSEGV trigger a SIGSEGV\n" << std::endl;
313 std::cout << " triSIGTRAP trigger a SIGTRAP\n" << std::endl;
314 std::cout << " triSIGABRT trigger a SIGABRT\n" << std::endl;
315
316 std::cout << " Loop trigger a ForeverLoop" << std::endl;
317 std::cout << " MaxStack trigger SIGSEGV after 64 function call" << std::endl;
318 std::cout << " MaxMethod trigger SIGSEGV after call a function with longer name" << std::endl;
319 std::cout << " STACKOF trigger a stack overflow" << std::endl;
320 std::cout << " OOM trigger out of memory" << std::endl;
321 std::cout << " PCZero trigger pc = 0" << std::endl;
322 std::cout << " MTCrash trigger crash with multi-thread" << std::endl;
323 std::cout << " StackOver64 trigger SIGSEGV after 70 function call" << std::endl;
324 std::cout << " StackTop trigger SIGSEGV to make sure stack top" << std::endl;
325 std::cout << " if you want the command execute in a sub thread" << std::endl;
326 std::cout << " add thread Prefix, e.g crasher thread-SIGFPE" << std::endl;
327 std::cout << std::endl;
328 }
329
CrashInLambda()330 NOINLINE static uint64_t CrashInLambda()
331 {
332 std::function<void()> lambda = TestFunc50;
333 lambda();
334 return 0;
335 }
336
DoDumpCrash()337 NOINLINE static uint64_t DoDumpCrash()
338 {
339 std::thread t(TestFunc1);
340 raise(SIGDUMP);
341 t.join();
342 return 0;
343 }
344
TestExitHook()345 NOINLINE static uint64_t TestExitHook()
346 {
347 exit(1);
348 return 0;
349 }
350
SigHookHandler(int signo)351 void SigHookHandler(int signo)
352 {
353 printf("SigHookHandler:%d\n", signo);
354 }
355
TestSigHook()356 NOINLINE static uint64_t TestSigHook()
357 {
358 signal(SIGSEGV, SigHookHandler);
359 return 0;
360 }
361
DoCrashInThread(void * inputArg)362 void* DfxCrasher::DoCrashInThread(void * inputArg)
363 {
364 prctl(PR_SET_NAME, "SubTestThread");
365 const char* arg = (const char *)(inputArg);
366 return (void*)(DfxCrasher::GetInstance().ParseAndDoCrash(arg));
367 }
368
DoActionOnSubThread(const char * arg) const369 uint64_t DfxCrasher::DoActionOnSubThread(const char *arg) const
370 {
371 pthread_t t;
372 pthread_create(&t, nullptr, DfxCrasher::DoCrashInThread, const_cast<char*>(arg));
373 void *result = nullptr;
374 pthread_join(t, &result);
375 return (uint64_t)(result);
376 }
377
ParseAndDoCrash(const char * arg)378 uint64_t DfxCrasher::ParseAndDoCrash(const char *arg)
379 {
380 // Prefix
381 if (!strncmp(arg, "thread-", strlen("thread-"))) {
382 return DoActionOnSubThread(arg + strlen("thread-"));
383 }
384 #ifdef HAS_HITRACE
385 auto beginId = HiTraceChain::Begin("test", HITRACE_FLAG_NO_BE_INFO);
386 #endif
387 // Action
388 if (!strcasecmp(arg, "SIGFPE")) {
389 return RaiseFloatingPointException();
390 }
391
392 if (!strcasecmp(arg, "SIGILL")) {
393 return RaiseIllegalInstructionException();
394 }
395
396 if (!strcasecmp(arg, "SIGSEGV")) {
397 return RaiseSegmentFaultException();
398 }
399
400 if (!strcasecmp(arg, "SIGTRAP")) {
401 return RaiseTrapException();
402 }
403
404 if (!strcasecmp(arg, "triSIGILL")) {
405 return IllegalInstructionException();
406 }
407
408 if (!strcasecmp(arg, "SIGABRT")) {
409 return RaiseAbort();
410 }
411
412 if (!strcasecmp(arg, "triSIGABRT")) {
413 return Abort();
414 }
415
416 if (!strcasecmp(arg, "SIGBUS")) {
417 return RaiseBusError();
418 }
419
420 if (!strcasecmp(arg, "STACKTRACE")) {
421 return DumpStackTrace();
422 }
423
424 if (!strcasecmp(arg, "triSIGTRAP")) {
425 return TriggerTrapException();
426 }
427
428 if (!strcasecmp(arg, "Loop")) {
429 int i = 0;
430 while (1) {
431 usleep(10000); // 10000:sleep 0.01 second
432 i++;
433 }
434 }
435
436 if (!strcasecmp(arg, "triSIGSEGV")) {
437 return SegmentFaultException();
438 }
439
440 if (!strcasecmp(arg, "MaxStack")) {
441 return MaxStackDepth();
442 }
443
444 if (!strcasecmp(arg, "MaxMethod")) {
445 return MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC();
446 }
447
448 if (!strcasecmp(arg, "STACKOF")) {
449 return StackOverflow();
450 }
451
452 if (!strcasecmp(arg, "OOM")) {
453 return Oom();
454 }
455
456 if (!strcasecmp(arg, "PCZero")) {
457 return ProgramCounterZero();
458 }
459
460 if (!strcasecmp(arg, "MTCrash")) {
461 return MultiThreadCrash();
462 }
463
464 if (!strcasecmp(arg, "StackOver64")) {
465 return StackOver64();
466 }
467
468 if (!strcasecmp(arg, "StackTop")) {
469 return StackTop();
470 }
471
472 if (!strcasecmp(arg, "DumpCrash")) {
473 return DoDumpCrash();
474 }
475
476 if (!strcasecmp(arg, "CrashInLambda")) {
477 return CrashInLambda();
478 }
479
480 if (!strcasecmp(arg, "ExitHook")) {
481 return TestExitHook();
482 }
483
484 if (!strcasecmp(arg, "SigHook")) {
485 return TestSigHook();
486 }
487 #ifdef HAS_HITRACE
488 HiTraceChain::End(beginId);
489 #endif
490 return 0;
491 }
492
TestFunc70()493 NOINLINE int TestFunc70()
494 {
495 raise(SIGSEGV);
496 return 0;
497 }
498
main(int argc,char * argv[])499 int main(int argc, char *argv[])
500 {
501 DfxCrasher::GetInstance().PrintUsage();
502 if (argc <= 1) {
503 std::cout << "wrong usage!";
504 DfxCrasher::GetInstance().PrintUsage();
505 return 0;
506 }
507
508 std::cout << "ParseAndDoCrash done:" << DfxCrasher::GetInstance().ParseAndDoCrash(argv[1]) << "!\n";
509 return 0;
510 }
511
512 // auto gen function
513 GEN_TEST_FUNCTION(0, 1)
514 GEN_TEST_FUNCTION(1, 2)
515 GEN_TEST_FUNCTION(2, 3)
516 GEN_TEST_FUNCTION(3, 4)
517 GEN_TEST_FUNCTION(4, 5)
518 GEN_TEST_FUNCTION(5, 6)
519 GEN_TEST_FUNCTION(6, 7)
520 GEN_TEST_FUNCTION(7, 8)
521 GEN_TEST_FUNCTION(8, 9)
522 GEN_TEST_FUNCTION(9, 10)
523
524 GEN_TEST_FUNCTION(10, 11)
525 GEN_TEST_FUNCTION(11, 12)
526 GEN_TEST_FUNCTION(12, 13)
527 GEN_TEST_FUNCTION(13, 14)
528 GEN_TEST_FUNCTION(14, 15)
529 GEN_TEST_FUNCTION(15, 16)
530 GEN_TEST_FUNCTION(16, 17)
531 GEN_TEST_FUNCTION(17, 18)
532 GEN_TEST_FUNCTION(18, 19)
533 GEN_TEST_FUNCTION(19, 20)
534
535 GEN_TEST_FUNCTION(20, 21)
536 GEN_TEST_FUNCTION(21, 22)
537 GEN_TEST_FUNCTION(22, 23)
538 GEN_TEST_FUNCTION(23, 24)
539 GEN_TEST_FUNCTION(24, 25)
540 GEN_TEST_FUNCTION(25, 26)
541 GEN_TEST_FUNCTION(26, 27)
542 GEN_TEST_FUNCTION(27, 28)
543 GEN_TEST_FUNCTION(28, 29)
544 GEN_TEST_FUNCTION(29, 30)
545
546 GEN_TEST_FUNCTION(30, 31)
547 GEN_TEST_FUNCTION(31, 32)
548 GEN_TEST_FUNCTION(32, 33)
549 GEN_TEST_FUNCTION(33, 34)
550 GEN_TEST_FUNCTION(34, 35)
551 GEN_TEST_FUNCTION(35, 36)
552 GEN_TEST_FUNCTION(36, 37)
553 GEN_TEST_FUNCTION(37, 38)
554 GEN_TEST_FUNCTION(38, 39)
555 GEN_TEST_FUNCTION(39, 40)
556
557 GEN_TEST_FUNCTION(40, 41)
558 GEN_TEST_FUNCTION(41, 42)
559 GEN_TEST_FUNCTION(42, 43)
560 GEN_TEST_FUNCTION(43, 44)
561 GEN_TEST_FUNCTION(44, 45)
562 GEN_TEST_FUNCTION(45, 46)
563 GEN_TEST_FUNCTION(46, 47)
564 GEN_TEST_FUNCTION(47, 48)
565 GEN_TEST_FUNCTION(48, 49)
566 GEN_TEST_FUNCTION(49, 50)
567
568 GEN_TEST_FUNCTION(50, 51)
569 GEN_TEST_FUNCTION(51, 52)
570 GEN_TEST_FUNCTION(52, 53)
571 GEN_TEST_FUNCTION(53, 54)
572 GEN_TEST_FUNCTION(54, 55)
573 GEN_TEST_FUNCTION(55, 56)
574 GEN_TEST_FUNCTION(56, 57)
575 GEN_TEST_FUNCTION(57, 58)
576 GEN_TEST_FUNCTION(58, 59)
577 GEN_TEST_FUNCTION(59, 60)
578
579 GEN_TEST_FUNCTION(60, 61)
580 GEN_TEST_FUNCTION(61, 62)
581 GEN_TEST_FUNCTION(62, 63)
582 GEN_TEST_FUNCTION(63, 64)
583 GEN_TEST_FUNCTION(64, 65)
584 GEN_TEST_FUNCTION(65, 66)
585 GEN_TEST_FUNCTION(66, 67)
586 GEN_TEST_FUNCTION(67, 68)
587 GEN_TEST_FUNCTION(68, 69)
588 GEN_TEST_FUNCTION(69, 70)
589