• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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