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