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