• 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 #ifndef is_ohos_lite
38 #include "async_stack.h"
39 #endif
40 #include "dfx_crash.h"
41 #include "dfx_define.h"
42 #include "dfx_unique_crash_obj.h"
43 #ifndef is_ohos_lite
44 #include "ffrt_inner.h"
45 #include "uv.h"
46 #endif // !is_ohos_lite
47 
48 #include "info/fatal_message.h"
49 #include "securec.h"
50 
51 #ifdef HAS_HITRACE
52 #include <hitrace/hitracechain.h>
53 #endif
54 
55 #ifdef HAS_CRASH_EXAMPLES
56 #include "faults/nullpointer_dereference.h"
57 #include "faults/multi_thread_container_access.h"
58 #include "faults/ipc_issues.h"
59 #endif
60 
61 #ifdef LOG_TAG
62 #undef LOG_TAG
63 #define LOG_TAG "Unwind"
64 #endif
65 
66 #ifdef LOG_DOMAIN
67 #undef LOG_DOMAIN
68 #define LOG_DOMAIN 0xD002D11
69 #endif
70 
71 static const int CMD_SZ = 32;
72 static const int CMD_DESC_SZ = 128;
73 
74 static const int NUMBER_TWO = 2;
75 static const int NUMBER_ONE = 1;
76 
77 using namespace OHOS::HiviewDFX;
78 using CommandFunc = int(*)();
79 using CommandFuncParam = int(*)(const std::string &);
80 struct CrasherCommandLine {
81     char cmdline[CMD_SZ];
82     char description[CMD_DESC_SZ];
83     CommandFunc func;
84 };
85 
86 struct CrasherCommandLineParam {
87     char cmdline[CMD_SZ];
88     char description[CMD_DESC_SZ];
89     CommandFuncParam func;
90 };
91 
92 constexpr static CrasherCommandLine CMDLINE_TABLE[] = {
93     {"SIGFPE", "raise a SIGFPE", &DfxCrasher::RaiseFloatingPointException},
94     {"SIGILL", "raise a SIGILL", &DfxCrasher::RaiseIllegalInstructionException},
95     {"SIGSEGV", "raise a SIGSEGV", &DfxCrasher::RaiseSegmentFaultException},
96     {"SIGTRAP", "raise a SIGTRAP", &DfxCrasher::RaiseTrapException},
97     {"SIGABRT", "raise a SIGABRT", &DfxCrasher::RaiseAbort},
98     {"SetLastFatalMessage", "raise a SIGABRT", &DfxCrasher::SetLastFatalMessage},
99     {"SIGBUS", "raise a SIGBUS", &DfxCrasher::RaiseBusError},
100 
101     {"triSIGILL", "trigger a SIGILL", &DfxCrasher::IllegalInstructionException},
102     {"triSIGSEGV", "trigger a SIGSEGV", &DfxCrasher::SegmentFaultException},
103     {"triSIGTRAP", "trigger a SIGTRAP", &DfxCrasher::TriggerTrapException},
104     {"triSIGABRT", "trigger a SIGABRT", &DfxCrasher::Abort},
105 
106     {"Loop", "trigger a ForeverLoop", &DfxCrasher::Loop},
107     {"MaxStack", "trigger SIGSEGV after 64 function call", &DfxCrasher::MaxStackDepth},
108     {"MaxMethod", "trigger SIGSEGV after call a function with longer name",
109         &DfxCrasher::MaxMethodNameTest12345678901234567890123456789012345678901234567890ABC},
110 
111     {"STACKOF", "trigger a stack overflow", &DfxCrasher::StackOverflow},
112     {"OOM", "trigger out of memory", &DfxCrasher::Oom},
113     {"PCZero", "trigger a crash with pc equal zero", &DfxCrasher::ProgramCounterZero},
114     {"MTCrash", "trigger a multi-thread crash", &DfxCrasher::MultiThreadCrash},
115     {"StackOver64", "trigger SIGSEGV after 70 function call", &DfxCrasher::StackOver64},
116     {"StackTop", "trigger SIGSEGV to make sure stack top", &DfxCrasher::StackTop},
117     {"DumpCrash", "trigger a SIGDUMP", &DfxCrasher::DoDumpCrash},
118     {"CrashInLambda", "trigger a crash in lambda", &DfxCrasher::CrashInLambda},
119     {"ExitHook", "trigger a process exit using exit(0)", &DfxCrasher::TestExitHook},
120     {"SigHook", "register sigsegv signal handler", &DfxCrasher::TestSigHook},
121     {"StackCorruption", "reset values stored on stack", &DfxCrasher::StackCorruption},
122     {"StackCorruption2", "reset values stored in the middle of the stack", &DfxCrasher::StackCorruption2},
123 
124 #ifdef HAS_CRASH_EXAMPLES
125     {"NullPointerDeref0", "nullpointer fault testcase 0", &TestNullPointerDereferenceCrash0},
126     {"NullPointerDeref1", "nullpointer fault testcase 1", &TestNullPointerDereferenceCrash1},
127     {"NullPointerDeref2", "nullpointer fault testcase 2", &TestNullPointerDereferenceCrash2},
128     {"NullPointerDeref3", "nullpointer fault testcase 3", &TestNullPointerDereferenceCrash3},
129 
130     {"MultiThreadList", "manipulate list without lock in multithread case", &MultiThreadListAccess},
131     {"MultiThreadVector", "manipulate vector without lock in multithread case", &MultiThreadVectorAccess},
132     {"MultiThreadMap", "manipulate map without lock in multithread case", &MultiThreadMapAccess},
133 
134     {"SptrMismatch", "mix use sptr and raw pointer", &IPCIssues::SptrMismatch},
135     {"SptrAndSharedPtrMixUsage", "miss match parcel marshalling and unmarshalling",
136         &IPCIssues::SptrAndSharedPtrMixUsage},
137     {"ParcelReadWriteMismatch", "miss match parcel marshalling and unmarshalling",
138         &IPCIssues::ParcelReadWriteMismatch},
139 #endif
140     {"FatalMessage", "PrintFatalMessageInLibc",
141         &DfxCrasher::PrintFatalMessageInLibc},
142     {"TestGetCrashObj", "Test get object when crash",
143         &DfxCrasher::TestGetCrashObj},
144     {"TestGetCrashObjMemory", "Test get memory info when crash",
145         &DfxCrasher::TestGetCrashObjMemory},
146 #ifndef is_ohos_lite
147     {"AsyncStack", "Test async stacktrace in nomal thread crash case",
148         &DfxCrasher::AsyncStacktrace},
149 #endif
150     {"Deadlock", "Test deadlock and parse lock owner",
151         &DfxCrasher::TestDeadlock},
152 };
153 
154 constexpr static CrasherCommandLineParam CMDLINE_TABLE_PARAM[] = {
155 #ifndef is_ohos_lite
156     {"CrashInFFRT", "Test async-stacktrace api in ffrt crash case",
157         &DfxCrasher::CrashInFFRT},
158     {"CrashInLibuvWork", "Test async-stacktrace api in work callback crash case",
159         &DfxCrasher::CrashInLibuvWork},
160     {"CrashInLibuvTimer", "Test async-stacktrace api in timer callback crash case",
161         &DfxCrasher::CrashInLibuvTimer},
162     {"CrashInLibuvWorkDone", "Test async-stacktrace api in work callback done crash case",
163         &DfxCrasher::CrashInLibuvWorkDone},
164 #endif
165 };
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) __attribute__((optnone))
338 {
339     int b[10] = {1};
340     if (b[0] == 0) {
341         return static_cast<void*>(b + 9); // 9: last element of array
342     }
343     DoStackOverflow(inputArg);
344     return static_cast<void*>(b + 9); // 9: last element of array
345 }
346 
StackOverflow()347 NOINLINE int DfxCrasher::StackOverflow()
348 {
349     pthread_t tid;
350     pthread_attr_t attr;
351     int err = pthread_attr_init(&attr);
352     if (err != 0) {
353         return err;
354     }
355 
356     constexpr int maxStackSize = 1024 * 10;
357     if (pthread_attr_setstacksize(&attr, maxStackSize) == 0) {
358         pthread_create(&tid, &attr, DoStackOverflow, nullptr);
359         pthread_join(tid, nullptr);
360     } else {
361         std::cout << "failed" << std::endl;
362     }
363     return 0;
364 }
365 
Oom()366 NOINLINE int DfxCrasher::Oom()
367 {
368     std::cout << "test oom" << std::endl;
369     struct rlimit oldRlimit;
370     if (getrlimit(RLIMIT_AS, &oldRlimit) != 0) {
371         std::cout << "getrlimit failed" << std::endl;
372         raise(SIGINT);
373     }
374     std::cout << std::hex << "old rlimit, cur:0x" << oldRlimit.rlim_cur << std::endl;
375     std::cout << std::hex << "old rlimit, max:0x" << oldRlimit.rlim_max << std::endl;
376 
377     struct rlimit rlim = {
378         .rlim_cur = ARG128 * ARG1024 * ARG1024,
379         .rlim_max = ARG128 * ARG1024 * ARG1024,
380     };
381 
382     if (setrlimit(RLIMIT_AS, &rlim) != 0) {
383         std::cout << "setrlimit failed" << std::endl;
384         raise(SIGINT);
385     }
386 
387     std::vector<void*> vec;
388     for (int i = 0; i < ARG128; i++) {
389         char* buf = static_cast<char*>(mmap(nullptr, (ARG1024 * ARG1024), PROT_READ | PROT_WRITE,
390                                             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
391         if (buf == (char*)MAP_FAILED) {
392             std::cout << "malloc return null" << std::endl;
393             if (setrlimit(RLIMIT_AS, &oldRlimit) != 0) {
394                 std::cout << "restore rlimit failed" << std::endl;
395             }
396             std::cout << "restore rlimit ok" << std::endl;
397             abort();
398         }
399 
400         (void)memset_s(buf, ARG1024 * ARG1024, 0xff, ARG1024 * ARG1024);
401         vec.push_back(buf);
402     }
403     return 0;
404 }
405 
ProgramCounterZero()406 NOINLINE int DfxCrasher::ProgramCounterZero()
407 {
408     std::cout << "test PCZero" << std::endl;
409     ProgramVolatile();
410     return 0;
411 }
412 
MultiThreadCrash()413 NOINLINE int DfxCrasher::MultiThreadCrash()
414 {
415     std::cout << "test MultiThreadCrash" << std::endl;
416 
417     std::thread ([] {
418         SleepThread(NUMBER_ONE);
419     }).detach();
420     std::thread ([] {
421         SleepThread(NUMBER_TWO);
422     }).detach();
423     sleep(1);
424 
425     raise(SIGSEGV);
426 
427     return 0;
428 }
429 
StackOver64()430 NOINLINE int DfxCrasher::StackOver64()
431 {
432     std::cout << "test StackOver64" << std::endl;
433 
434     return TestFunc1();
435 }
436 
SleepThread(int threadID)437 int SleepThread(int threadID)
438 {
439     std::cout << "create MultiThread " <<  threadID << std::endl;
440 
441     int sleepTime = 10;
442     sleep(sleepTime);
443 
444     return 0;
445 }
446 
StackTop()447 NOINLINE int DfxCrasher::StackTop()
448 {
449     std::cout << "test StackTop" << std::endl;
450 #if defined(__arm__)
451     unsigned int stackTop;
452     __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
453 #elif defined(__aarch64__)
454     uint64_t stackTop;
455     __asm__ volatile ("mov %0, sp":"=r"(stackTop)::);
456 #else
457     uint64_t stackTop = 0; // for fixing compile error on x64
458 #endif
459     std::cout << "crasher_c: stack top is = " << std::hex << stackTop << std::endl;
460 
461     std::ofstream fout;
462     fout.open("/data/sp");
463     fout << std::hex << stackTop << std::endl;
464     fout.close();
465 
466 #if defined(__arm__)
467     __asm__ volatile ("mov r1, #0\nldr r2, [r1]\n");
468 #elif defined(__aarch64__)
469     __asm__ volatile ("mov x1, #0\nldr x2, [x1]\n");
470 #endif
471 
472     return 0;
473 }
474 
PrintUsage() const475 void DfxCrasher::PrintUsage() const
476 {
477     std::cout << "  usage: crasher CMD" << std::endl;
478     std::cout << "\n";
479     std::cout << "  where CMD support:" << std::endl;
480     for (auto& item : CMDLINE_TABLE) {
481         std::cout << "  " << item.cmdline << " : " << item.description << std::endl;
482     }
483     std::cout << "  if you want the command execute in a sub thread" << std::endl;
484     std::cout << "  add thread Prefix, e.g crasher thread-SIGFPE" << std::endl;
485     std::cout << "\n";
486 }
487 
CrashInLambda()488 NOINLINE int DfxCrasher::CrashInLambda()
489 {
490     std::function<void()> lambda = TestFunc50;
491     lambda();
492     return 0;
493 }
494 
DoDumpCrash()495 NOINLINE int DfxCrasher::DoDumpCrash()
496 {
497     std::thread t([] {
498         TestFunc1();
499     });
500     raise(SIGDUMP);
501     t.join();
502     return 0;
503 }
504 
TestExitHook()505 NOINLINE int DfxCrasher::TestExitHook()
506 {
507     exit(1);
508     return 0;
509 }
510 
SigHookHandler(int signo)511 static void SigHookHandler(int signo)
512 {
513     printf("SigHookHandler:%d\n", signo);
514 }
515 
TestSigHook()516 NOINLINE int DfxCrasher::TestSigHook()
517 {
518     signal(SIGSEGV, SigHookHandler);
519     return 0;
520 }
521 
PrintFatalMessageInLibc()522 NOINLINE int DfxCrasher::PrintFatalMessageInLibc()
523 {
524     set_fatal_message("TestPrintFatalMessageInLibc");
525     RaiseAbort();
526     return 0;
527 }
528 
TestGetCrashObjInner()529 NOINLINE static void TestGetCrashObjInner()
530 {
531     std::string msg = "test get crashObjectInner.";
532     UniqueCrashObj obj(OBJ_STRING, reinterpret_cast<uintptr_t>(msg.c_str()));
533 }
534 
TestGetCrashObj()535 NOINLINE int DfxCrasher::TestGetCrashObj()
536 {
537     std::string msg = "test get crashObject.";
538     UniqueCrashObj obj(OBJ_STRING, reinterpret_cast<uintptr_t>(msg.c_str()));
539     TestGetCrashObjInner();
540     raise(SIGSEGV);
541     return 0;
542 }
543 
TestGetCrashObjMemoryInner()544 NOINLINE static void TestGetCrashObjMemoryInner()
545 {
546     constexpr size_t bufSize = 4096;
547     uintptr_t memory[bufSize] = {2};
548     UniqueCrashObj obj(OBJ_MEMORY_64B, reinterpret_cast<uintptr_t>(memory));
549 }
550 
TestGetCrashObjMemory()551 NOINLINE int DfxCrasher::TestGetCrashObjMemory()
552 {
553     constexpr size_t bufSize = 4096;
554     uintptr_t memory[bufSize];
555     for (size_t i = 0; i < bufSize; i++) {
556         memory[i] = i;
557     }
558     UniqueCrashObj obj(OBJ_MEMORY_4096B, reinterpret_cast<uintptr_t>(memory));
559 
560     TestGetCrashObjMemoryInner();
561     raise(SIGSEGV);
562     return 0;
563 }
564 
565 #ifndef is_ohos_lite
CrashInSubThread(void * stackIdPtr)566 static void* CrashInSubThread(void* stackIdPtr)
567 {
568     uint64_t value = *reinterpret_cast<uint64_t *>(stackIdPtr);
569     SetStackId(value);
570     printf("CrashInSubThread stackId:%p value:%p.\n", stackIdPtr, reinterpret_cast<void*>(value));
571     raise(SIGSEGV);
572     return nullptr;
573 }
574 
AsyncStacktrace()575 NOINLINE int DfxCrasher::AsyncStacktrace()
576 {
577 #ifdef __aarch64__
578     uint64_t stackId = CollectAsyncStack();
579     printf("Current stackId:%p.\n", (void*)stackId);
580     pthread_t thread;
581     pthread_create(&thread, NULL, CrashInSubThread, (void*)&stackId);
582     void *result = nullptr;
583     pthread_join(thread, &result);
584     return reinterpret_cast<uint64_t>(result);
585 #else
586     printf("Unsupported arch.\n");
587     return 0;
588 #endif
589 }
590 
FFRTTaskSubmit1(int i)591 NOINLINE static int FFRTTaskSubmit1(int i)
592 {
593     int inner = i + 1;
594     printf("FFRTTaskSubmit1:current %d\n", inner);
595     ffrt::submit(
596         [&]() {
597             inner = 2; // 2 : inner count
598             raise(SIGSEGV);
599         },
600         {},
601         {&inner});
602     return inner;
603 }
604 
FFRTTaskSubmit0(int i)605 NOINLINE static int FFRTTaskSubmit0(int i)
606 {
607     int inner = i + 1;
608     printf("FFRTTaskSubmit0:current %d\n", inner);
609     return FFRTTaskSubmit1(i);
610 }
611 
CrashInFFRT(const std::string & debug)612 NOINLINE int DfxCrasher::CrashInFFRT(const std::string &debug)
613 {
614     if (debug == "true") {
615         setenv("HAP_DEBUGGABLE", "true", 1);
616     }
617     int i = FFRTTaskSubmit0(10);
618     ffrt::wait();
619     return i;
620 }
621 
622 static bool g_done = 0;
623 static unsigned g_events = 0;
624 static unsigned g_result;
625 
WorkCallback(uv_work_t * req)626 NOINLINE static void WorkCallback(uv_work_t* req)
627 {
628     req->data = &g_result;
629     raise(SIGSEGV);
630 }
631 
AfterWorkCallback(uv_work_t * req,int status)632 NOINLINE static void AfterWorkCallback(uv_work_t* req, int status)
633 {
634     g_events++;
635     if (!g_done) {
636         uv_queue_work(req->loop, req, WorkCallback, AfterWorkCallback);
637     }
638 }
639 
TimerCallback(uv_timer_t * handle)640 static void TimerCallback(uv_timer_t* handle)
641 {
642     g_done = true;
643 }
644 
CrashInLibuvWork(const std::string & debug)645 NOINLINE int DfxCrasher::CrashInLibuvWork(const std::string &debug)
646 {
647     if (debug == "true") {
648         setenv("HAP_DEBUGGABLE", "true", 1);
649     }
650     uv_timer_t timerHandle;
651     uv_work_t work;
652     uv_loop_t* loop = uv_default_loop();
653     int timeout = 5000;
654     uv_timer_init(loop, &timerHandle);
655     uv_timer_start(&timerHandle, TimerCallback, timeout, 0);
656     uv_queue_work(loop, &work, WorkCallback, AfterWorkCallback);
657     uv_run(loop, UV_RUN_DEFAULT);
658     printf("END in CrashInLibuvWork\n");
659     return 0;
660 }
661 
TimerCallback2(uv_timer_t * handle)662 static void TimerCallback2(uv_timer_t* handle)
663 {
664     raise(SIGSEGV);
665 }
666 
CrashInLibuvTimer(const std::string & debug)667 NOINLINE int DfxCrasher::CrashInLibuvTimer(const std::string &debug)
668 {
669     if (debug == "true") {
670         setenv("HAP_DEBUGGABLE", "true", 1);
671     }
672     uv_timer_t timerHandle;
673     uv_work_t work;
674     uv_loop_t* loop = uv_default_loop();
675     int timeout = 5000;
676     uv_timer_init(loop, &timerHandle);
677     uv_timer_start(&timerHandle, TimerCallback2, timeout, 0);
678     uv_queue_work(loop, &work, WorkCallback, AfterWorkCallback);
679     uv_run(loop, UV_RUN_DEFAULT);
680     printf("END in CrashInLibuvTimer\n");
681     return 0;
682 }
683 
WorkCallback2(uv_work_t * req)684 NOINLINE static void WorkCallback2(uv_work_t* req)
685 {
686     req->data = &g_result;
687 }
688 
CrashAfterWorkCallback(uv_work_t * req,int status)689 NOINLINE static void CrashAfterWorkCallback(uv_work_t* req, int status)
690 {
691     raise(SIGSEGV);
692 }
693 
CrashInLibuvWorkDone(const std::string & debug)694 NOINLINE int DfxCrasher::CrashInLibuvWorkDone(const std::string &debug)
695 {
696     if (debug == "true") {
697         setenv("HAP_DEBUGGABLE", "true", 1);
698     }
699     uv_work_t work;
700     uv_loop_t* loop = uv_default_loop();
701     uv_queue_work(loop, &work, WorkCallback2, CrashAfterWorkCallback);
702     uv_run(loop, UV_RUN_DEFAULT);
703     printf("END in CrashInLibuvWorkDone\n");
704     return 0;
705 }
706 #endif
707 
DoCrashInThread(void * inputArg)708 void* DfxCrasher::DoCrashInThread(void * inputArg)
709 {
710     prctl(PR_SET_NAME, "SubTestThread");
711     const char* arg = (const char *)(inputArg);
712     return reinterpret_cast<void*>(DfxCrasher::GetInstance().ParseAndDoCrash(arg));
713 }
714 
DoActionOnSubThread(const char * arg) const715 uint64_t DfxCrasher::DoActionOnSubThread(const char *arg) const
716 {
717     pthread_t t;
718     pthread_create(&t, nullptr, DfxCrasher::DoCrashInThread, const_cast<char*>(arg));
719     void *result = nullptr;
720     pthread_join(t, &result);
721     return reinterpret_cast<uint64_t>(result);
722 }
723 
Loop()724 int DfxCrasher::Loop()
725 {
726     int i = 0;
727     while (1) {
728         usleep(10000); // 10000:sleep 0.01 second
729         i++;
730     }
731     return 0;
732 }
733 
ParseAndDoCrash(const char * arg) const734 uint64_t DfxCrasher::ParseAndDoCrash(const char *arg) const
735 {
736     // Prefix
737     if (!strncmp(arg, "thread-", strlen("thread-"))) {
738         return DoActionOnSubThread(arg + strlen("thread-"));
739     }
740 #ifdef HAS_HITRACE
741     auto beginId = HiTraceChain::Begin("test", HITRACE_FLAG_NO_BE_INFO);
742 #endif
743     std::istringstream str(arg);
744     std::string out;
745     str >> out;
746     // Actions
747     for (auto& item : CMDLINE_TABLE) {
748         if (!strcasecmp(out.c_str(), item.cmdline)) {
749             return item.func();
750         }
751     }
752     for (auto& item : CMDLINE_TABLE_PARAM) {
753         if (!strcasecmp(out.c_str(), item.cmdline)) {
754             if (str >> out) {
755                 return item.func(out);
756             }
757         }
758     }
759 #ifdef HAS_HITRACE
760     HiTraceChain::End(beginId);
761 #endif
762     return 0;
763 }
764 
TestFunc70()765 NOINLINE int TestFunc70()
766 {
767     raise(SIGSEGV);
768     return 0;
769 }
770 
main(int argc,char * argv[])771 int main(int argc, char *argv[])
772 {
773     DfxCrasher::GetInstance().PrintUsage();
774     if (argc <= 1) {
775         std::cout << "wrong usage!";
776         DfxCrasher::GetInstance().PrintUsage();
777         return 0;
778     }
779 
780     std::cout << "ParseAndDoCrash done:" << DfxCrasher::GetInstance().ParseAndDoCrash(argv[1]) << "!\n";
781     return 0;
782 }
783