• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <info/fatal_message.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <sys/mman.h>
22 #include <sys/prctl.h>
23 #include <sys/resource.h>
24 #include <unistd.h>
25 #include "dfx_crash.h"
26 #include "errno.h"
27 #include "hilog/log.h"
28 #include "inttypes.h"
29 #include "stdio.h"
30 #include "stdlib.h"
31 #include "string.h"
32 #include "strings.h"
33 #include "dfx_define.h"
34 
35 #ifdef LOG_DOMAIN
36 #undef LOG_DOMAIN
37 #define LOG_DOMAIN 0xD002D11
38 #endif
39 
40 #ifdef LOG_TAG
41 #undef LOG_TAG
42 #define LOG_TAG "Unwind"
43 #endif
44 
TriggerTrapException(void)45 NOINLINE int TriggerTrapException(void)
46 {
47 #if defined(__arm__) || defined(__aarch64__)
48     __asm__ volatile(".inst 0xde01");
49 #elif defined(__loongarch_lp64)
50     // Effective illegal instruction on LoongArch64: amswap.w $zero, $ra, $zero
51     __asm__ volatile(".word 0x38600400\n");
52 #endif
53     return 0;
54 }
55 
RaiseAbort(void)56 NOINLINE int RaiseAbort(void)
57 {
58     HILOG_FATAL(LOG_CORE, "Test Trigger ABORT!");
59     int ret = raise(SIGABRT);
60     if (ret != 0) {
61         printf("raise SIGABRT failed!");
62     }
63     return 0;
64 }
65 
Abort(void)66 NOINLINE int Abort(void)
67 {
68     HILOG_FATAL(LOG_CORE, "Test Trigger ABORT!");
69     abort();
70     return 0;
71 }
72 
SetLastFatalMessage(void)73 NOINLINE int SetLastFatalMessage(void)
74 {
75     const char msg[] = "Test Trigger ABORT!";
76     set_fatal_message(msg);
77     int ret = raise(SIGABRT);
78     if (ret != 0) {
79         printf("raise SIGABRT failed!");
80     }
81     return 0;
82 }
83 
RaiseBusError(void)84 NOINLINE int RaiseBusError(void)
85 {
86     int ret = raise(SIGBUS);
87     if (ret != 0) {
88         printf("raise SIGBUS failed!");
89     }
90     return 0;
91 }
92 
RaiseFloatingPointException(void)93 NOINLINE int RaiseFloatingPointException(void)
94 {
95     int ret = raise(SIGFPE);
96     if (ret != 0) {
97         printf("raise SIGFPE failed!");
98     }
99     return 0;
100 }
101 
RaiseIllegalInstructionException(void)102 NOINLINE int RaiseIllegalInstructionException(void)
103 {
104     int ret = raise(SIGILL);
105     if (ret != 0) {
106         printf("raise SIGILL failed!");
107     }
108     return 0;
109 }
110 
IllegalInstructionException(void)111 NOINLINE int IllegalInstructionException(void)
112 {
113     IllegalVolatile();
114     return 0;
115 }
116 
RaiseSegmentFaultException(void)117 NOINLINE int RaiseSegmentFaultException(void)
118 {
119     printf("call RaiseSegmentFaultException \n");
120     int ret = raise(SIGSEGV);
121     if (ret != 0) {
122         printf("raise SIGSEGV failed!");
123     }
124     return 0;
125 }
126 
SegmentFaultException(void)127 NOINLINE int SegmentFaultException(void)
128 {
129     volatile char *ptr = NULL;
130     *ptr;
131 
132     return 0;
133 }
134 
RaiseTrapException(void)135 NOINLINE int RaiseTrapException(void)
136 {
137     int ret = raise(SIGTRAP);
138     if (ret != 0) {
139         printf("raise SIGTRAP failed!");
140     }
141     return 0;
142 }
143 
TrapException(void)144 NOINLINE int TrapException(void)
145 {
146     return 0;
147 }
148 
MaxStackDepth(void)149 NOINLINE int MaxStackDepth(void)
150 {
151     return TestFunc1();
152 }
153 
MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC(void)154 NOINLINE int MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC(void)
155 {
156     printf("call MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC \n");
157     int ret = raise(SIGSEGV);
158     if (ret != 0) {
159         printf("raise SIGSEGV failed!");
160     }
161     return 0;
162 }
163 
StackOverflow(void)164 NOINLINE int StackOverflow(void)
165 {
166     printf("call StackOverflow\n");
167 
168     // for stack overflow test
169     char a[1024][1024][1024] = { { {'1'} } };
170     char b[1024][1024][1024] = { { {'1'} } };
171     char c[1024][1024][1024] = { { {'1'} } };
172     char d[1024][1024][1024] = { { {'1'} } };
173     printf("a[0][0] is %s\n", a[0][0]);
174     printf("b[0][0] is %s\n", b[0][0]);
175     printf("c[0][0] is %s\n", c[0][0]);
176     printf("d[0][0] is %s\n", d[0][0]);
177 
178     return 0;
179 }
180 
Oom(void)181 NOINLINE int Oom(void)
182 {
183     struct rlimit oldRlimit;
184     if (getrlimit(RLIMIT_AS, &oldRlimit) != 0) {
185         printf("getrlimit failed\n");
186         raise(SIGINT);
187     }
188     printf("old rlimit, cur:0x%016" PRIx64 " max:0x%016" PRIx64 "\n",
189         (uint64_t)oldRlimit.rlim_cur, (uint64_t)oldRlimit.rlim_max);
190 
191     struct rlimit rlim = {
192         .rlim_cur = (ARG128 - 1) * ARG1024 * ARG1024,
193         .rlim_max = (ARG128 - 1) * ARG1024 * ARG1024,
194     };
195 
196     if (setrlimit(RLIMIT_AS, &rlim) != 0) {
197         printf("setrlimit failed\n");
198         raise(SIGINT);
199     }
200     char* bufferArray[ARG128];
201     for (int i = 0; i < ARG128; i++) {
202         char* buf = (char*)mmap(NULL, (ARG1024 * ARG1024), PROT_READ | PROT_WRITE,
203                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
204         if (buf == (char*)MAP_FAILED) {
205             printf("malloc return null\n");
206             if (setrlimit(RLIMIT_AS, &oldRlimit) != 0) {
207                 printf("restore rlimit failed\n");
208             }
209             printf("restore rlimit ok\n");
210             abort();
211         }
212         bufferArray[i] = buf;
213     }
214     for (int i = 0; i < ARG128; i++) {
215         printf("0x%x", *(bufferArray[i] + 1));
216     }
217 
218     return 0;
219 }
220 
ProgramCounterZero(void)221 static NOINLINE int ProgramCounterZero(void)
222 {
223     printf("test PCZero");
224     ProgramVolatile();
225     return 0;
226 }
227 
MultiThreadCrash(void)228 NOINLINE int MultiThreadCrash(void)
229 {
230     printf("test MultiThreadCrash");
231 
232     pthread_t t[2];
233     int threadID[2] = {1, 2};
234     pthread_create(&t[0], NULL, SleepThread, &threadID[0]);
235     pthread_create(&t[1], NULL, SleepThread, &threadID[1]);
236     pthread_detach(t[0]);
237     pthread_detach(t[1]);
238     sleep(1);
239 
240     int ret = raise(SIGSEGV);
241     if (ret != 0) {
242         printf("raise SIGSEGV failed!");
243     }
244 
245     return 0;
246 }
247 
StackOver64(void)248 NOINLINE int StackOver64(void)
249 {
250     printf("test StackOver64");
251 
252     return TestFunc1();
253 }
254 
SleepThread(void * argv)255 void *SleepThread(void *argv)
256 {
257     int threadID = *(int*)argv;
258     printf("create MultiThread %d", threadID);
259 
260     int sleepTime = 10;
261     sleep(sleepTime);
262 
263     return 0;
264 }
265 
StackTop(void)266 NOINLINE int StackTop(void)
267 {
268     printf("test StackTop\n");
269     __attribute__((unused))register void* stackTop;
270 #if defined(__arm__)
271     __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
272     printf("crasher_c: stack top is = %08x\n", (unsigned int)stackTop);
273 #elif defined(__aarch64__)
274     __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
275     printf("crasher_c: stack top is = %16llx\n", (unsigned long long)stackTop);
276 #elif defined(__loongarch_lp64)
277     __asm__ volatile ("move %0, $sp":"=r"(stackTop)::);
278     printf("crasher_c: stack top is = %16llx\n", (unsigned long long)stackTop);
279 #else
280     return 0;
281 #endif
282 
283     FILE *fp = NULL;
284     fp = fopen("/data/sp", "w");
285     if (fp == NULL) {
286         printf("Open /data/sp failed, errno(%d)\n", errno);
287         return 0;
288     }
289 
290     int ret = 0; // for fixing compile error on x64
291 #if defined(__arm__)
292     ret = fprintf(fp, "%08x", (unsigned int)stackTop);
293 #elif defined(__aarch64__) || defined(__loongarch_lp64)
294     ret = fprintf(fp, "%16llx", (unsigned long long)stackTop);
295 #endif
296     if (ret == EOF) {
297         printf("error!");
298     }
299     ret = fclose(fp);
300     if (ret == EOF) {
301         printf("close error!");
302     }
303 
304 #if defined(__arm__)
305     __asm__ volatile ("mov r1, #0\nldr r2, [r1]\n");
306 #elif defined(__aarch64__)
307     __asm__ volatile ("mov x1, #0\nldr x2, [x1]\n");
308 #elif defined(__loongarch_lp64)
309     __asm__ volatile ("move $a1, $zero\nld.d $a2, $a1, 0\n");
310 #endif
311     return ret;
312 }
313 
PrintUsage(void)314 void PrintUsage(void)
315 {
316     printf("  usage: crasher CMD\n");
317     printf("\n");
318     printf("  where CMD support:\n");
319     printf("  SIGFPE                raise a SIGFPE\n");
320     printf("  SIGILL                raise a SIGILL\n");
321     printf("  SIGSEGV               raise a SIGSEGV\n");
322     printf("  SIGTRAP               raise a SIGTRAP\n");
323     printf("  SIGABRT               raise a SIGABRT\n");
324     printf("  SIGBUS                raise a SIGBUS\n");
325 
326     printf("  triSIGILL             trigger a SIGILL\n");
327     printf("  triSIGSEGV            trigger a SIGSEGV\n");
328     printf("  triSIGTRAP            trigger a SIGTRAP\n");
329     printf("  triSIGABRT            trigger a SIGABRT\n");
330 
331     printf("  Loop                  trigger a ForeverLoop\n");
332     printf("  MaxStack              trigger SIGSEGV after 64 function call\n");
333     printf("  MaxMethod             trigger SIGSEGV after call a function with longer name\n");
334     printf("  OOM                   trigger out of memory\n");
335     printf("  STACKOF               trigger a stack overflow\n");
336     printf("  PCZero                trigger pc = 0\n");
337     printf("  MTCrash               trigger crash with multi-thread\n");
338     printf("  StackOver64           trigger SIGSEGV after 70 function call\n");
339     printf("  StackTop              trigger SIGSEGV to make sure stack top\n");
340     printf("  if you want the command execute in a sub thread\n");
341     printf("  add thread Prefix, e.g crasher thread-SIGFPE\n");
342     printf("\n");
343 }
344 
DoCrashInThread(void * inputArg)345 void *DoCrashInThread(void *inputArg)
346 {
347     prctl(PR_SET_NAME, "SubTestThread");
348     const char *arg = (const char *)(inputArg);
349     return (void *)((uint64_t)(ParseAndDoCrash(arg)));
350 }
351 
DoActionOnSubThread(const char * arg)352 uint64_t DoActionOnSubThread(const char *arg)
353 {
354     pthread_t t;
355     pthread_create(&t, NULL, DoCrashInThread, (char *)(arg));
356     void *result = NULL;
357     pthread_join(t, &result);
358     return (uint64_t)(result);
359 }
360 
ParseAndDoCrash(const char * arg)361 uint64_t ParseAndDoCrash(const char *arg)
362 {
363     // Prefix
364     if (!strncmp(arg, "thread-", strlen("thread-"))) {
365         return DoActionOnSubThread(arg + strlen("thread-"));
366     }
367 
368     // Action
369     struct ActionStruct {
370         const char *action;
371         int (*handler)(void);
372     };
373     const struct ActionStruct actions[] = {
374         {"SIGFPE", RaiseFloatingPointException},
375         {"SIGILL", RaiseIllegalInstructionException},
376         {"triSIGILL", IllegalInstructionException},
377         {"SIGSEGV", RaiseSegmentFaultException},
378         {"SIGTRAP", RaiseTrapException},
379         {"SIGABRT", RaiseAbort},
380         {"SetLastFatalMessage", SetLastFatalMessage},
381         {"triSIGABRT", Abort},
382         {"triSIGSEGV", SegmentFaultException},
383         {"SIGBUS", RaiseBusError},
384         {"triSIGTRAP", TriggerTrapException},
385         {"MaxStack", MaxStackDepth},
386         {"MaxMethod", MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC},
387         {"STACKOF", StackOverflow},
388         {"OOM", Oom},
389         {"PCZero", ProgramCounterZero},
390         {"MTCrash", MultiThreadCrash},
391         {"StackOver64", StackOver64},
392         {"StackTop", StackTop},
393         {"CrashTest", CrashTest},
394     };
395 
396     int length = sizeof(actions) / sizeof(actions[0]);
397     for (int i = 0; i < length; i++) {
398         if (!strcasecmp(arg, actions[i].action)) {
399             return actions[i].handler();
400         }
401     }
402 
403     if (!strcasecmp(arg, "Loop")) {
404         int i = 0;
405         while (1) {
406             usleep(10000); // 10000:sleep 0.01 second
407             i++;
408         }
409     }
410     return 0;
411 }
412 
TestFunc70(void)413 NOINLINE int TestFunc70(void)
414 {
415     int ret = raise(SIGSEGV);
416     if (ret != 0) {
417         printf("raise SIGSEGV failed!");
418     }
419     return 0;
420 }
421 
CrashTest(void)422 NOINLINE int CrashTest(void)
423 {
424     int sleepTime = 3;
425     sleep(sleepTime);
426     int ret = raise(SIGSEGV);
427     if (ret != 0) {
428         printf("raise SIGSEGV failed!");
429     }
430     return 0;
431 }
432 
main(int argc,char * argv[])433 int main(int argc, char *argv[])
434 {
435     PrintUsage();
436     if (argc <= 1) {
437         printf("wrong usage!");
438         PrintUsage();
439         return 0;
440     }
441 
442     printf("ParseAndDoCrash done: %" PRIu64 "!\n", ParseAndDoCrash(argv[1]));
443     return 0;
444 }
445