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