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