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