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 <cerrno>
19 #include <cinttypes>
20 #include <csignal>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <fstream>
25 #include <hilog/log.h>
26 #include <info/fatal_message.h>
27 #include <iostream>
28 #include <sstream>
29 #include <pthread.h>
30 #include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/resource.h>
33 #include <thread>
34 #include <unistd.h>
35 #include <vector>
36
37 #include "async_stack.h"
38 #include "dfx_crash.h"
39 #include "dfx_define.h"
40 #ifndef is_ohos_lite
41 #include "ffrt_inner.h"
42 #include "uv.h"
43 #endif // !is_ohos_lite
44
45 #include "info/fatal_message.h"
46 #include "securec.h"
47
48 #ifdef HAS_HITRACE
49 #include <hitrace/hitracechain.h>
50 #endif
51
52 #ifdef HAS_CRASH_EXAMPLES
53 #include "faults/nullpointer_dereference.h"
54 #include "faults/multi_thread_container_access.h"
55 #include "faults/ipc_issues.h"
56 #endif
57
58 #ifdef LOG_TAG
59 #undef LOG_TAG
60 #define LOG_TAG "Unwind"
61 #endif
62
63 #ifdef LOG_DOMAIN
64 #undef LOG_DOMAIN
65 #define LOG_DOMAIN 0xD002D11
66 #endif
67
68 static const int CMD_SZ = 32;
69 static const int CMD_DESC_SZ = 128;
70
71 static const int NUMBER_TWO = 2;
72 static const int NUMBER_ONE = 1;
73
74 using namespace OHOS::HiviewDFX;
75 using CommandFunc = int(*)();
76 using CommandFuncParam = int(*)(const std::string &);
77 struct CrasherCommandLine {
78 char cmdline[CMD_SZ];
79 char description[CMD_DESC_SZ];
80 CommandFunc func;
81 };
82
83 struct CrasherCommandLineParam {
84 char cmdline[CMD_SZ];
85 char description[CMD_DESC_SZ];
86 CommandFuncParam func;
87 };
88
89 constexpr static CrasherCommandLine CMDLINE_TABLE[] = {
90 {"SIGFPE", "raise a SIGFPE", &DfxCrasher::RaiseFloatingPointException},
91 {"SIGILL", "raise a SIGILL", &DfxCrasher::RaiseIllegalInstructionException},
92 {"SIGSEGV", "raise a SIGSEGV", &DfxCrasher::RaiseSegmentFaultException},
93 {"SIGTRAP", "raise a SIGTRAP", &DfxCrasher::RaiseTrapException},
94 {"SIGABRT", "raise a SIGABRT", &DfxCrasher::RaiseAbort},
95 {"SetLastFatalMessage", "raise a SIGABRT", &DfxCrasher::SetLastFatalMessage},
96 {"SIGBUS", "raise a SIGBUS", &DfxCrasher::RaiseBusError},
97
98 {"triSIGILL", "trigger a SIGILL", &DfxCrasher::IllegalInstructionException},
99 {"triSIGSEGV", "trigger a SIGSEGV", &DfxCrasher::SegmentFaultException},
100 {"triSIGTRAP", "trigger a SIGTRAP", &DfxCrasher::TriggerTrapException},
101 {"triSIGABRT", "trigger a SIGABRT", &DfxCrasher::Abort},
102
103 {"Loop", "trigger a ForeverLoop", &DfxCrasher::Loop},
104 {"MaxStack", "trigger SIGSEGV after 64 function call", &DfxCrasher::MaxStackDepth},
105 {"MaxMethod", "trigger SIGSEGV after call a function with longer name",
106 &DfxCrasher::MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC},
107
108 {"STACKOF", "trigger a stack overflow", &DfxCrasher::StackOverflow},
109 {"OOM", "trigger out of memory", &DfxCrasher::Oom},
110 {"PCZero", "trigger a crash with pc equal zero", &DfxCrasher::ProgramCounterZero},
111 {"MTCrash", "trigger a multi-thread crash", &DfxCrasher::MultiThreadCrash},
112 {"StackOver64", "trigger SIGSEGV after 70 function call", &DfxCrasher::StackOver64},
113 {"StackTop", "trigger SIGSEGV to make sure stack top", &DfxCrasher::StackTop},
114 {"DumpCrash", "trigger a SIGDUMP", &DfxCrasher::DoDumpCrash},
115 {"CrashInLambda", "trigger a crash in lambda", &DfxCrasher::CrashInLambda},
116 {"ExitHook", "trigger a process exit using exit(0)", &DfxCrasher::TestExitHook},
117 {"SigHook", "register sigsegv signal handler", &DfxCrasher::TestSigHook},
118 {"StackCorruption", "reset values stored on stack", &DfxCrasher::StackCorruption},
119 {"StackCorruption2", "reset values stored in the middle of the stack", &DfxCrasher::StackCorruption2},
120
121 #ifdef HAS_CRASH_EXAMPLES
122 {"NullPointerDeref0", "nullpointer fault testcase 0", &TestNullPointerDereferenceCrash0},
123 {"NullPointerDeref1", "nullpointer fault testcase 1", &TestNullPointerDereferenceCrash1},
124 {"NullPointerDeref2", "nullpointer fault testcase 2", &TestNullPointerDereferenceCrash2},
125 {"NullPointerDeref3", "nullpointer fault testcase 3", &TestNullPointerDereferenceCrash3},
126
127 {"MultiThreadList", "manipulate list without lock in multithread case", &MultiThreadListAccess},
128 {"MultiThreadVector", "manipulate vector without lock in multithread case", &MultiThreadVectorAccess},
129 {"MultiThreadMap", "manipulate map without lock in multithread case", &MultiThreadMapAccess},
130
131 {"SptrMismatch", "mix use sptr and raw pointer", &IPCIssues::SptrMismatch},
132 {"SptrAndSharedPtrMixUsage", "miss match parcel marshalling and unmarshalling",
133 &IPCIssues::SptrAndSharedPtrMixUsage},
134 {"ParcelReadWriteMismatch", "miss match parcel marshalling and unmarshalling",
135 &IPCIssues::ParcelReadWriteMismatch},
136 #endif
137 {"FatalMessage", "PrintFatalMessageInLibc",
138 &DfxCrasher::PrintFatalMessageInLibc},
139 {"TestGetCrashObj", "Test get object when crash",
140 &DfxCrasher::TestGetCrashObj},
141 {"TestGetCrashObjMemory", "Test get memory info when crash",
142 &DfxCrasher::TestGetCrashObjMemory},
143 #ifndef is_ohos_lite
144 {"AsyncStack", "Test async stacktrace in nomal thread crash case",
145 &DfxCrasher::AsyncStacktrace},
146 #endif
147 {"Deadlock", "Test deadlock and parse lock owner",
148 &DfxCrasher::TestDeadlock},
149 };
150
151 constexpr static CrasherCommandLineParam CMDLINE_TABLE_PARAM[] = {
152 #ifndef is_ohos_lite
153 {"CrashInFFRT", "Test async-stacktrace api in ffrt crash case",
154 &DfxCrasher::CrashInFFRT},
155 {"CrashInLibuvWork", "Test async-stacktrace api in work callback crash case",
156 &DfxCrasher::CrashInLibuvWork},
157 {"CrashInLibuvTimer", "Test async-stacktrace api in timer callback crash case",
158 &DfxCrasher::CrashInLibuvTimer},
159 {"CrashInLibuvWorkDone", "Test async-stacktrace api in work callback done crash case",
160 &DfxCrasher::CrashInLibuvWorkDone},
161 #endif
162 };
163
164 extern "C" uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr) __attribute__((weak));
165 extern "C" void DFX_ResetCrashObj(uintptr_t crashObj) __attribute__((weak));
166
DfxCrasher()167 DfxCrasher::DfxCrasher() {}
~DfxCrasher()168 DfxCrasher::~DfxCrasher() {}
169
GetInstance()170 DfxCrasher &DfxCrasher::GetInstance()
171 {
172 static DfxCrasher instance;
173 return instance;
174 }
175
TestDeadlock()176 int DfxCrasher::TestDeadlock()
177 {
178 pthread_mutexattr_t mutexAttr;
179 pthread_mutexattr_init(&mutexAttr);
180 pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_ERRORCHECK);
181
182 pthread_mutex_t mutex;
183 pthread_mutex_init(&mutex, &mutexAttr);
184 pthread_mutexattr_destroy(&mutexAttr);
185
186 int lockOnwerIdx = 1;
187 int lockOwnerMask = 0x3fffffff;
188 auto mutexInt = reinterpret_cast<int*>(&mutex);
189 printf("mutex address:%llx\n", reinterpret_cast<long long>(&mutex));
190 printf("mutex owner before lock:%d\n", mutexInt[lockOnwerIdx] & lockOwnerMask);
191 pthread_mutex_lock(&mutex);
192 printf("mutex owner after lock:%d\n", mutexInt[lockOnwerIdx] & lockOwnerMask);
193 std::thread t1([&mutex] {
194 pthread_mutex_lock(&mutex);
195 });
196 t1.join();
197 return 0;
198 }
199
RecursiveHelperFunction(int curLevel,int targetLevel,int midLevel)200 static NOINLINE int RecursiveHelperFunction(int curLevel, int targetLevel, int midLevel)
201 {
202 auto top = __builtin_frame_address(0);
203 uintptr_t size = 256;
204 if (curLevel == targetLevel) {
205 if (midLevel != 0) {
206 abort();
207 }
208 printf("RecursiveHelperFunction top:%p\n", top);
209 // crash in return address
210 (void)memset_s(top, size, 0, size);
211 return 0;
212 }
213
214 if (midLevel != 0 && curLevel == midLevel) {
215 // crash in return address
216 (void)memset_s(top, size, 0, size);
217 }
218
219 int nextLevel = curLevel + 1;
220 if (midLevel != 0 || targetLevel != 0) {
221 RecursiveHelperFunction(nextLevel, targetLevel, midLevel);
222 }
223
224 printf("RecursiveHelperFunction curLevel:%d targetLevel:%d top:%p\n", curLevel, targetLevel, top);
225 return nextLevel + 1;
226 }
227
StackCorruption()228 NOINLINE int DfxCrasher::StackCorruption()
229 {
230 constexpr int targetLevel = 64;
231 constexpr int midLevel = 0;
232 return RecursiveHelperFunction(1, targetLevel, midLevel);
233 }
234
StackCorruption2()235 NOINLINE int DfxCrasher::StackCorruption2()
236 {
237 constexpr int targetLevel = 64;
238 constexpr int midLevel = 32;
239 return RecursiveHelperFunction(1, targetLevel, midLevel);
240 }
241
RaiseFloatingPointException()242 NOINLINE int DfxCrasher::RaiseFloatingPointException()
243 {
244 raise(SIGFPE);
245 return 0;
246 }
247
RaiseIllegalInstructionException()248 NOINLINE int DfxCrasher::RaiseIllegalInstructionException()
249 {
250 raise(SIGILL);
251 return 0;
252 }
253
RaiseSegmentFaultException()254 NOINLINE int DfxCrasher::RaiseSegmentFaultException()
255 {
256 std::cout << "call RaiseSegmentFaultException" << std::endl;
257 raise(SIGSEGV);
258 return 0;
259 }
260
RaiseTrapException()261 NOINLINE int DfxCrasher::RaiseTrapException()
262 {
263 raise(SIGTRAP);
264 return 0;
265 }
266
RaiseAbort()267 NOINLINE int DfxCrasher::RaiseAbort()
268 {
269 HILOG_FATAL(LOG_CORE, "Test Trigger ABORT!");
270 raise(SIGABRT);
271 return 0;
272 }
273
SetLastFatalMessage()274 NOINLINE int DfxCrasher::SetLastFatalMessage()
275 {
276 const char msg[] = "Test Trigger ABORT!";
277 set_fatal_message(msg);
278 raise(SIGABRT);
279 return 0;
280 }
281
RaiseBusError()282 NOINLINE int DfxCrasher::RaiseBusError()
283 {
284 raise(SIGBUS);
285 return 0;
286 }
287
IllegalInstructionException(void)288 NOINLINE int DfxCrasher::IllegalInstructionException(void)
289 {
290 IllegalVolatile();
291 return 0;
292 }
293
TriggerSegmentFaultException()294 NOINLINE int DfxCrasher::TriggerSegmentFaultException()
295 {
296 std::cout << "test TriggerSegmentFaultException" << std::endl;
297 // for crash test force cast the type
298 int *a = reinterpret_cast<int *>(&TestFunc70);
299 *a = SIGSEGV;
300 return 0;
301 }
302
TriggerTrapException()303 NOINLINE int DfxCrasher::TriggerTrapException()
304 {
305 #ifndef __x86_64__
306 __asm__ volatile(".inst 0xde01");
307 #endif
308 return 0;
309 }
310
Abort(void)311 NOINLINE int DfxCrasher::Abort(void)
312 {
313 HILOG_FATAL(LOG_CORE, "Test Trigger ABORT!");
314 abort();
315 return 0;
316 }
317
SegmentFaultException(void)318 NOINLINE int DfxCrasher::SegmentFaultException(void)
319 {
320 volatile char *ptr = nullptr;
321 *ptr;
322 return 0;
323 }
324
MaxStackDepth()325 NOINLINE int DfxCrasher::MaxStackDepth()
326 {
327 return TestFunc1();
328 }
329
MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC()330 NOINLINE int DfxCrasher::MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC()
331 {
332 std::cout << "call MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC" << std::endl;
333 raise(SIGSEGV);
334 return 0;
335 }
336
DoStackOverflow(void * inputArg)337 static void *DoStackOverflow(void * inputArg)
338 {
339 int b[10] = {1};
340 int *c = nullptr;
341 (void)memcpy_s(c, sizeof(int), b, sizeof(int));
342 if (b[0] == 0) {
343 return static_cast<void*>(b + 9); // 9: last element of array
344 }
345 DoStackOverflow(inputArg);
346 return static_cast<void*>(b + 9); // 9: last element of array
347 }
348
StackOverflow()349 NOINLINE int DfxCrasher::StackOverflow()
350 {
351 pthread_t tid;
352 pthread_attr_t attr;
353 int err = pthread_attr_init(&attr);
354 if (err != 0) {
355 return err;
356 }
357
358 constexpr int maxStackSize = 1024 * 10;
359 if (pthread_attr_setstacksize(&attr, maxStackSize) == 0) {
360 pthread_create(&tid, &attr, DoStackOverflow, nullptr);
361 pthread_join(tid, nullptr);
362 } else {
363 std::cout << "failed" << std::endl;
364 }
365 return 0;
366 }
367
Oom()368 NOINLINE int DfxCrasher::Oom()
369 {
370 std::cout << "test oom" << std::endl;
371 struct rlimit oldRlimit;
372 if (getrlimit(RLIMIT_AS, &oldRlimit) != 0) {
373 std::cout << "getrlimit failed" << std::endl;
374 raise(SIGINT);
375 }
376 std::cout << std::hex << "old rlimit, cur:0x" << oldRlimit.rlim_cur << std::endl;
377 std::cout << std::hex << "old rlimit, max:0x" << oldRlimit.rlim_max << std::endl;
378
379 struct rlimit rlim = {
380 .rlim_cur = ARG128 * ARG1024 * ARG1024,
381 .rlim_max = ARG128 * ARG1024 * ARG1024,
382 };
383
384 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
385 std::cout << "setrlimit failed" << std::endl;
386 raise(SIGINT);
387 }
388
389 std::vector<void*> vec;
390 for (int i = 0; i < ARG128; i++) {
391 char* buf = static_cast<char*>(mmap(nullptr, (ARG1024 * ARG1024), PROT_READ | PROT_WRITE,
392 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
393 if (buf == (char*)MAP_FAILED) {
394 std::cout << "malloc return null" << std::endl;
395 if (setrlimit(RLIMIT_AS, &oldRlimit) != 0) {
396 std::cout << "restore rlimit failed" << std::endl;
397 }
398 std::cout << "restore rlimit ok" << std::endl;
399 abort();
400 }
401
402 (void)memset_s(buf, ARG1024 * ARG1024, 0xff, ARG1024 * ARG1024);
403 vec.push_back(buf);
404 }
405 return 0;
406 }
407
ProgramCounterZero()408 NOINLINE int DfxCrasher::ProgramCounterZero()
409 {
410 std::cout << "test PCZero" << std::endl;
411 ProgramVolatile();
412 return 0;
413 }
414
MultiThreadCrash()415 NOINLINE int DfxCrasher::MultiThreadCrash()
416 {
417 std::cout << "test MultiThreadCrash" << std::endl;
418
419 std::thread ([] {
420 SleepThread(NUMBER_ONE);
421 }).detach();
422 std::thread ([] {
423 SleepThread(NUMBER_TWO);
424 }).detach();
425 sleep(1);
426
427 raise(SIGSEGV);
428
429 return 0;
430 }
431
StackOver64()432 NOINLINE int DfxCrasher::StackOver64()
433 {
434 std::cout << "test StackOver64" << std::endl;
435
436 return TestFunc1();
437 }
438
SleepThread(int threadID)439 int SleepThread(int threadID)
440 {
441 std::cout << "create MultiThread " << threadID << std::endl;
442
443 int sleepTime = 10;
444 sleep(sleepTime);
445
446 return 0;
447 }
448
StackTop()449 NOINLINE int DfxCrasher::StackTop()
450 {
451 std::cout << "test StackTop" << std::endl;
452 #if defined(__arm__)
453 unsigned int stackTop;
454 __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
455 #elif defined(__aarch64__)
456 uint64_t stackTop;
457 __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
458 #else
459 uint64_t stackTop = 0; // for fixing compile error on x64
460 #endif
461 std::cout << "crasher_c: stack top is = " << std::hex << stackTop << std::endl;
462
463 std::ofstream fout;
464 fout.open("/data/sp");
465 fout << std::hex << stackTop << std::endl;
466 fout.close();
467
468 #if defined(__arm__)
469 __asm__ volatile ("mov r1, #0\nldr r2, [r1]\n");
470 #elif defined(__aarch64__)
471 __asm__ volatile ("mov x1, #0\nldr x2, [x1]\n");
472 #endif
473
474 return 0;
475 }
476
PrintUsage() const477 void DfxCrasher::PrintUsage() const
478 {
479 std::cout << " usage: crasher CMD" << std::endl;
480 std::cout << "\n";
481 std::cout << " where CMD support:" << std::endl;
482 for (auto& item : CMDLINE_TABLE) {
483 std::cout << " " << item.cmdline << " : " << item.description << std::endl;
484 }
485 std::cout << " if you want the command execute in a sub thread" << std::endl;
486 std::cout << " add thread Prefix, e.g crasher thread-SIGFPE" << std::endl;
487 std::cout << "\n";
488 }
489
CrashInLambda()490 NOINLINE int DfxCrasher::CrashInLambda()
491 {
492 std::function<void()> lambda = TestFunc50;
493 lambda();
494 return 0;
495 }
496
DoDumpCrash()497 NOINLINE int DfxCrasher::DoDumpCrash()
498 {
499 std::thread t([] {
500 TestFunc1();
501 });
502 raise(SIGDUMP);
503 t.join();
504 return 0;
505 }
506
TestExitHook()507 NOINLINE int DfxCrasher::TestExitHook()
508 {
509 exit(1);
510 return 0;
511 }
512
SigHookHandler(int signo)513 static void SigHookHandler(int signo)
514 {
515 printf("SigHookHandler:%d\n", signo);
516 }
517
TestSigHook()518 NOINLINE int DfxCrasher::TestSigHook()
519 {
520 signal(SIGSEGV, SigHookHandler);
521 return 0;
522 }
523
PrintFatalMessageInLibc()524 NOINLINE int DfxCrasher::PrintFatalMessageInLibc()
525 {
526 set_fatal_message("TestPrintFatalMessageInLibc");
527 RaiseAbort();
528 return 0;
529 }
530
TestGetCrashObjInner()531 NOINLINE static void TestGetCrashObjInner()
532 {
533 uintptr_t val = 0;
534 if (DFX_SetCrashObj != nullptr) {
535 uint8_t type = 0;
536 std::string msg = "test get crashObjectInner.";
537 val = DFX_SetCrashObj(type, reinterpret_cast<uintptr_t>(msg.c_str()));
538 }
539 if (DFX_ResetCrashObj != nullptr) {
540 DFX_ResetCrashObj(val);
541 }
542 }
543
TestGetCrashObj()544 NOINLINE int DfxCrasher::TestGetCrashObj()
545 {
546 uintptr_t crashObj = 0;
547 if (DFX_SetCrashObj != nullptr) {
548 uint8_t type = 0;
549 std::string msg = "test get crashObject.";
550 crashObj = DFX_SetCrashObj(type, reinterpret_cast<uintptr_t>(msg.c_str()));
551 }
552 TestGetCrashObjInner();
553 raise(SIGSEGV);
554 if (DFX_ResetCrashObj != nullptr) {
555 DFX_ResetCrashObj(crashObj);
556 }
557 return 0;
558 }
559
TestGetCrashObjMemoryInner()560 NOINLINE static void TestGetCrashObjMemoryInner()
561 {
562 uint8_t type = 1;
563 uintptr_t val = 0;
564 constexpr size_t bufSize = 4096;
565 uintptr_t memory[bufSize] = {2};
566 if (DFX_SetCrashObj != nullptr) {
567 val = DFX_SetCrashObj(type, reinterpret_cast<uintptr_t>(memory));
568 }
569 if (DFX_ResetCrashObj != nullptr) {
570 DFX_ResetCrashObj(val);
571 }
572 }
573
TestGetCrashObjMemory()574 NOINLINE int DfxCrasher::TestGetCrashObjMemory()
575 {
576 uint8_t type = 5;
577 uintptr_t crashObj = 0;
578 constexpr size_t bufSize = 4096;
579 uintptr_t memory[bufSize];
580 for (size_t i = 0; i < bufSize; i++) {
581 memory[i] = i;
582 }
583 if (DFX_SetCrashObj != nullptr) {
584 crashObj = DFX_SetCrashObj(type, reinterpret_cast<uintptr_t>(memory));
585 }
586 TestGetCrashObjMemoryInner();
587 raise(SIGSEGV);
588 if (DFX_ResetCrashObj != nullptr) {
589 DFX_ResetCrashObj(crashObj);
590 }
591 return 0;
592 }
593
CrashInSubThread(void * stackIdPtr)594 static void* CrashInSubThread(void* stackIdPtr)
595 {
596 uint64_t value = *reinterpret_cast<uint64_t *>(stackIdPtr);
597 SetStackId(value);
598 printf("CrashInSubThread stackId:%p value:%p.\n", stackIdPtr, reinterpret_cast<void*>(value));
599 raise(SIGSEGV);
600 return nullptr;
601 }
602
603 #ifndef is_ohos_lite
AsyncStacktrace()604 NOINLINE int DfxCrasher::AsyncStacktrace()
605 {
606 #ifdef __aarch64__
607 uint64_t stackId = CollectAsyncStack();
608 printf("Current stackId:%p.\n", (void*)stackId);
609 pthread_t thread;
610 pthread_create(&thread, NULL, CrashInSubThread, (void*)&stackId);
611 void *result = nullptr;
612 pthread_join(thread, &result);
613 return reinterpret_cast<uint64_t>(result);
614 #else
615 printf("Unsupported arch.\n");
616 return 0;
617 #endif
618 }
619
FFRTTaskSubmit1(int i)620 NOINLINE static int FFRTTaskSubmit1(int i)
621 {
622 int inner = i + 1;
623 printf("FFRTTaskSubmit1:current %d\n", inner);
624 ffrt::submit(
625 [&]() {
626 inner = 2; // 2 : inner count
627 raise(SIGSEGV);
628 },
629 {},
630 {&inner});
631 return inner;
632 }
633
FFRTTaskSubmit0(int i)634 NOINLINE static int FFRTTaskSubmit0(int i)
635 {
636 int inner = i + 1;
637 printf("FFRTTaskSubmit0:current %d\n", inner);
638 return FFRTTaskSubmit1(i);
639 }
640
CrashInFFRT(const std::string & debug)641 NOINLINE int DfxCrasher::CrashInFFRT(const std::string &debug)
642 {
643 if (debug == "true") {
644 setenv("HAP_DEBUGGABLE", "true", 1);
645 }
646 int i = FFRTTaskSubmit0(10);
647 ffrt::wait();
648 return i;
649 }
650
651 static bool g_done = 0;
652 static unsigned g_events = 0;
653 static unsigned g_result;
654
WorkCallback(uv_work_t * req)655 NOINLINE static void WorkCallback(uv_work_t* req)
656 {
657 req->data = &g_result;
658 raise(SIGSEGV);
659 }
660
AfterWorkCallback(uv_work_t * req,int status)661 NOINLINE static void AfterWorkCallback(uv_work_t* req, int status)
662 {
663 g_events++;
664 if (!g_done) {
665 uv_queue_work(req->loop, req, WorkCallback, AfterWorkCallback);
666 }
667 }
668
TimerCallback(uv_timer_t * handle)669 static void TimerCallback(uv_timer_t* handle)
670 {
671 g_done = true;
672 }
673
CrashInLibuvWork(const std::string & debug)674 NOINLINE int DfxCrasher::CrashInLibuvWork(const std::string &debug)
675 {
676 if (debug == "true") {
677 setenv("HAP_DEBUGGABLE", "true", 1);
678 }
679 uv_timer_t timerHandle;
680 uv_work_t work;
681 uv_loop_t* loop = uv_default_loop();
682 int timeout = 5000;
683 uv_timer_init(loop, &timerHandle);
684 uv_timer_start(&timerHandle, TimerCallback, timeout, 0);
685 uv_queue_work(loop, &work, WorkCallback, AfterWorkCallback);
686 uv_run(loop, UV_RUN_DEFAULT);
687 printf("END in CrashInLibuvWork\n");
688 return 0;
689 }
690
TimerCallback2(uv_timer_t * handle)691 static void TimerCallback2(uv_timer_t* handle)
692 {
693 raise(SIGSEGV);
694 }
695
CrashInLibuvTimer(const std::string & debug)696 NOINLINE int DfxCrasher::CrashInLibuvTimer(const std::string &debug)
697 {
698 if (debug == "true") {
699 setenv("HAP_DEBUGGABLE", "true", 1);
700 }
701 uv_timer_t timerHandle;
702 uv_work_t work;
703 uv_loop_t* loop = uv_default_loop();
704 int timeout = 5000;
705 uv_timer_init(loop, &timerHandle);
706 uv_timer_start(&timerHandle, TimerCallback2, timeout, 0);
707 uv_queue_work(loop, &work, WorkCallback, AfterWorkCallback);
708 uv_run(loop, UV_RUN_DEFAULT);
709 printf("END in CrashInLibuvTimer\n");
710 return 0;
711 }
712
WorkCallback2(uv_work_t * req)713 NOINLINE static void WorkCallback2(uv_work_t* req)
714 {
715 req->data = &g_result;
716 }
717
CrashAfterWorkCallback(uv_work_t * req,int status)718 NOINLINE static void CrashAfterWorkCallback(uv_work_t* req, int status)
719 {
720 raise(SIGSEGV);
721 }
722
CrashInLibuvWorkDone(const std::string & debug)723 NOINLINE int DfxCrasher::CrashInLibuvWorkDone(const std::string &debug)
724 {
725 if (debug == "true") {
726 setenv("HAP_DEBUGGABLE", "true", 1);
727 }
728 uv_work_t work;
729 uv_loop_t* loop = uv_default_loop();
730 uv_queue_work(loop, &work, WorkCallback2, CrashAfterWorkCallback);
731 uv_run(loop, UV_RUN_DEFAULT);
732 printf("END in CrashInLibuvWorkDone\n");
733 return 0;
734 }
735 #endif
736
DoCrashInThread(void * inputArg)737 void* DfxCrasher::DoCrashInThread(void * inputArg)
738 {
739 prctl(PR_SET_NAME, "SubTestThread");
740 const char* arg = (const char *)(inputArg);
741 return reinterpret_cast<void*>(DfxCrasher::GetInstance().ParseAndDoCrash(arg));
742 }
743
DoActionOnSubThread(const char * arg) const744 uint64_t DfxCrasher::DoActionOnSubThread(const char *arg) const
745 {
746 pthread_t t;
747 pthread_create(&t, nullptr, DfxCrasher::DoCrashInThread, const_cast<char*>(arg));
748 void *result = nullptr;
749 pthread_join(t, &result);
750 return reinterpret_cast<uint64_t>(result);
751 }
752
Loop()753 int DfxCrasher::Loop()
754 {
755 int i = 0;
756 while (1) {
757 usleep(10000); // 10000:sleep 0.01 second
758 i++;
759 }
760 return 0;
761 }
762
ParseAndDoCrash(const char * arg) const763 uint64_t DfxCrasher::ParseAndDoCrash(const char *arg) const
764 {
765 // Prefix
766 if (!strncmp(arg, "thread-", strlen("thread-"))) {
767 return DoActionOnSubThread(arg + strlen("thread-"));
768 }
769 #ifdef HAS_HITRACE
770 auto beginId = HiTraceChain::Begin("test", HITRACE_FLAG_NO_BE_INFO);
771 #endif
772 std::istringstream str(arg);
773 std::string out;
774 str >> out;
775 // Actions
776 for (auto& item : CMDLINE_TABLE) {
777 if (!strcasecmp(out.c_str(), item.cmdline)) {
778 return item.func();
779 }
780 }
781 for (auto& item : CMDLINE_TABLE_PARAM) {
782 if (!strcasecmp(out.c_str(), item.cmdline)) {
783 if (str >> out) {
784 return item.func(out);
785 }
786 }
787 }
788 #ifdef HAS_HITRACE
789 HiTraceChain::End(beginId);
790 #endif
791 return 0;
792 }
793
TestFunc70()794 NOINLINE int TestFunc70()
795 {
796 raise(SIGSEGV);
797 return 0;
798 }
799
main(int argc,char * argv[])800 int main(int argc, char *argv[])
801 {
802 DfxCrasher::GetInstance().PrintUsage();
803 if (argc <= 1) {
804 std::cout << "wrong usage!";
805 DfxCrasher::GetInstance().PrintUsage();
806 return 0;
807 }
808
809 std::cout << "ParseAndDoCrash done:" << DfxCrasher::GetInstance().ParseAndDoCrash(argv[1]) << "!\n";
810 return 0;
811 }
812