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