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