1 /*
2 * Copyright (c) 2021-2025 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 "process_dumper.h"
17
18 #include <algorithm>
19 #include <cerrno>
20 #include <chrono>
21 #include <cinttypes>
22 #include <csignal>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <memory>
29 #include <pthread.h>
30 #include <securec.h>
31 #include <string>
32 #include <syscall.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/ptrace.h>
36 #include <sys/wait.h>
37 #include <ucontext.h>
38 #include <unistd.h>
39
40 #include "reporter.h"
41 #include "crash_exception.h"
42 #include "process_dump_config.h"
43 #include "dump_info_factory.h"
44 #include "dump_utils.h"
45 #include "dfx_define.h"
46 #include "dfx_dump_request.h"
47 #include "dfx_dump_res.h"
48
49 #include "dfx_ptrace.h"
50 #include "dfx_process.h"
51 #include "dfx_regs.h"
52 #if defined(DEBUG_CRASH_LOCAL_HANDLER)
53 #include "dfx_signal_local_handler.h"
54 #endif
55 #include "dfx_buffer_writer.h"
56 #include "dump_info_json_formatter.h"
57 #include "dfx_thread.h"
58 #include "dfx_util.h"
59 #include "dfx_trace.h"
60 #include "directory_ex.h"
61 #include "elapsed_time.h"
62 #include "faultloggerd_client.h"
63 #ifndef HISYSEVENT_DISABLE
64 #include "hisysevent.h"
65 #endif
66 #include "info/fatal_message.h"
67 #include "procinfo.h"
68 #include "reporter.h"
69 #include "unwinder_config.h"
70 #ifndef is_ohos_lite
71 #include "hitrace/hitracechainc.h"
72 #include "parameters.h"
73 #endif // !is_ohos_lite
74 #include "info/fatal_message.h"
75
76 namespace OHOS {
77 namespace HiviewDFX {
78 namespace {
79 #undef LOG_DOMAIN
80 #undef LOG_TAG
81 #define LOG_DOMAIN 0xD002D11
82 #define LOG_TAG "DfxProcessDump"
83 const char *const BLOCK_CRASH_PROCESS = "faultloggerd.priv.block_crash_process.enabled";
84 MAYBE_UNUSED const char *const MIXSTACK_ENABLE = "faultloggerd.priv.mixstack.enabled";
85 const char * const OTHER_THREAD_DUMP_INFO = "OtherThreadDumpInfo";
86
87 #if defined(DEBUG_CRASH_LOCAL_HANDLER)
SigAlarmCallBack()88 void SigAlarmCallBack()
89 {
90 ProcessDumper::GetInstance().ReportSigDumpStats();
91 }
92 #endif
93
IsBlockCrashProcess()94 static bool IsBlockCrashProcess()
95 {
96 #ifndef is_ohos_lite
97 static bool isBlockCrash = OHOS::system::GetParameter(BLOCK_CRASH_PROCESS, "false") == "true";
98 return isBlockCrash;
99 #else
100 return false;
101 #endif
102 }
103
WaitForFork(unsigned long pid,unsigned long & childPid)104 void WaitForFork(unsigned long pid, unsigned long& childPid)
105 {
106 DFXLOGI("start wait fork event happen");
107 int waitStatus = 0;
108 waitpid(pid, &waitStatus, 0); // wait fork event
109 DFXLOGI("wait for fork status %{public}d", waitStatus);
110 if (static_cast<unsigned int>(waitStatus) >> 8 == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) { // 8 : get fork event
111 ptrace(PTRACE_GETEVENTMSG, pid, NULL, &childPid);
112 DFXLOGI("next child pid %{public}lu", childPid);
113 waitpid(childPid, &waitStatus, 0); // wait child stop event
114 }
115 }
116
GetVmProcessRealPid(const ProcessDumpRequest & request,unsigned long vmPid,int & realPid)117 void GetVmProcessRealPid(const ProcessDumpRequest& request, unsigned long vmPid, int& realPid)
118 {
119 int waitStatus = 0;
120 ptrace(PTRACE_SETOPTIONS, vmPid, NULL, PTRACE_O_TRACEEXIT); // block son exit
121 ptrace(PTRACE_CONT, vmPid, NULL, NULL);
122
123 DFXLOGI("start wait exit event happen");
124 waitpid(vmPid, &waitStatus, 0); // wait exit stop
125 long data = ptrace(PTRACE_PEEKDATA, vmPid, reinterpret_cast<void *>(request.vmProcRealPidAddr), nullptr);
126 if (data < 0) {
127 DFXLOGI("ptrace peek data error %{public}lu %{public}d", vmPid, errno);
128 }
129 realPid = static_cast<int>(data);
130 }
131
ReadPids(const ProcessDumpRequest & request,int & realPid,int & vmPid,DfxProcess process)132 void ReadPids(const ProcessDumpRequest& request, int& realPid, int& vmPid, DfxProcess process)
133 {
134 unsigned long childPid = 0;
135 DFX_TRACE_SCOPED("ReadPids");
136 WaitForFork(request.tid, childPid);
137 ptrace(PTRACE_CONT, childPid, NULL, NULL);
138
139 // freeze detach after fork child to fork vm process
140 if (request.type == ProcessDumpType::DUMP_TYPE_DUMP_CATCH ||
141 #if defined(__aarch64__)
142 CoreDumpService::IsCoredumpSignal(request)
143 #else
144 false
145 #endif
146 ) {
147 process.Detach();
148 DFXLOGI("ptrace detach all tids");
149 }
150
151 unsigned long sonPid = 0;
152 WaitForFork(childPid, sonPid);
153 vmPid = static_cast<int>(sonPid);
154
155 ptrace(PTRACE_DETACH, childPid, 0, 0);
156 GetVmProcessRealPid(request, sonPid, realPid);
157
158 DFXLOGI("procecdump get real pid is %{public}d vm pid is %{public}d", realPid, vmPid);
159 }
160
NotifyOperateResult(ProcessDumpRequest & request,int result)161 void NotifyOperateResult(ProcessDumpRequest& request, int result)
162 {
163 if (request.childPipeFd[0] != -1) {
164 close(request.childPipeFd[0]);
165 request.childPipeFd[0] = -1;
166 }
167 if (OHOS_TEMP_FAILURE_RETRY(write(request.childPipeFd[1], &result, sizeof(result))) < 0) {
168 DFXLOGE("write to child process fail %{public}d", errno);
169 }
170 }
171
BlockCrashProcExit(const ProcessDumpRequest & request)172 void BlockCrashProcExit(const ProcessDumpRequest& request)
173 {
174 if (!IsBlockCrashProcess()) {
175 return;
176 }
177 DFXLOGI("start block crash process pid %{public}d nspid %{public}d", request.pid, request.nsPid);
178 if (ptrace(PTRACE_POKEDATA, request.nsPid, reinterpret_cast<void*>(request.blockCrashExitAddr),
179 CRASH_BLOCK_EXIT_FLAG) < 0) {
180 DFXLOGE("pok block falg to nsPid %{public}d fail %{public}s", request.nsPid, strerror(errno));
181 }
182 }
183 }
184
GetInstance()185 ProcessDumper &ProcessDumper::GetInstance()
186 {
187 static ProcessDumper ins;
188 return ins;
189 }
190
Dump()191 void ProcessDumper::Dump()
192 {
193 startTime_ = GetTimeMillisec();
194 int resDump = DumpProcess();
195 FormatJsonInfoIfNeed();
196 WriteDumpResIfNeed(resDump);
197 finishTime_ = GetTimeMillisec();
198
199 ReportSigDumpStats();
200 DfxBufferWriter::GetInstance().PrintBriefDumpInfo();
201 DfxBufferWriter::GetInstance().Finish();
202 DFXLOGI("Finish dump stacktrace for %{public}s(%{public}d:%{public}d).",
203 request_.processName, request_.pid, request_.tid);
204 // if the process no longer exists before dumping, do not report sysevent
205 if (process_ != nullptr && resDump != DumpErrorCode::DUMP_ENOMAP &&
206 resDump != DumpErrorCode::DUMP_EREADPID) {
207 SysEventReporter reporter(request_.type);
208 reporter.Report(*process_, request_);
209 }
210
211 if (request_.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH) {
212 DumpUtils::InfoCrashUnwindResult(request_, resDump == DumpErrorCode::DUMP_ESUCCESS);
213 BlockCrashProcExit(request_);
214 }
215 if (process_ != nullptr) {
216 process_->Detach();
217 }
218 }
219
DumpProcess()220 int ProcessDumper::DumpProcess()
221 {
222 DFX_TRACE_SCOPED("DumpProcess");
223 int dumpRes = ReadRequestAndCheck();
224 if (dumpRes != DumpErrorCode::DUMP_ESUCCESS) {
225 return dumpRes;
226 }
227 #ifndef is_ohos_lite
228 if (sizeof(HiTraceIdStruct) == sizeof(DumpHiTraceIdStruct)) {
229 HiTraceIdStruct* hitraceIdPtr = reinterpret_cast<HiTraceIdStruct*>(&request_.hitraceId);
230 hitraceIdPtr->flags |= HITRACE_FLAG_INCLUDE_ASYNC;
231 HiTraceChainSetId(hitraceIdPtr);
232 } else {
233 DFXLOGE("No invalid hitraceId struct size!");
234 }
235 #endif
236 DFXLOGI("Processdump SigVal(%{public}d), TargetPid(%{public}d:%{public}d), TargetTid(%{public}d), " \
237 "threadname(%{public}s).",
238 request_.siginfo.si_value.sival_int, request_.pid, request_.nsPid, request_.tid, request_.threadName);
239 SetProcessdumpTimeout(request_.siginfo);
240 UpdateConfigByRequest();
241 if (!InitDfxProcess()) {
242 DFXLOGE("Failed to init crash process info.");
243 dumpRes = DumpErrorCode::DUMP_EATTACH;
244 return dumpRes;
245 }
246 if (!InitUnwinder(dumpRes)) {
247 return dumpRes;
248 }
249 if (!InitBufferWriter()) {
250 DFXLOGE("Failed to init buffer writer.");
251 dumpRes = DumpErrorCode::DUMP_EGETFD;
252 }
253 PrintDumpInfo(dumpRes);
254 UnwindWriteJit();
255 DfxPtrace::Detach(process_->GetVmPid());
256 return dumpRes;
257 }
258
SetProcessdumpTimeout(siginfo_t & si)259 void ProcessDumper::SetProcessdumpTimeout(siginfo_t &si)
260 {
261 if (si.si_signo != SIGDUMP) {
262 return;
263 }
264
265 int tid;
266 ParseSiValue(si, expectedDumpFinishTime_, tid);
267
268 if (tid == 0) {
269 DFXLOGI("reset, prevent incorrect reading sival_int for tid");
270 si.si_value.sival_int = 0;
271 }
272
273 if (expectedDumpFinishTime_ == 0) {
274 DFXLOGI("end time is zero, not set new alarm");
275 return;
276 }
277
278 uint64_t curTime = GetAbsTimeMilliSeconds();
279 if (curTime >= expectedDumpFinishTime_) {
280 DFXLOGI("now has timeout, processdump exit");
281 ReportSigDumpStats();
282 #ifndef CLANG_COVERAGE
283 _exit(0);
284 #endif
285 }
286 uint64_t diffTime = expectedDumpFinishTime_ - curTime;
287
288 DFXLOGI("processdump remain time%{public}" PRIu64 "ms", diffTime);
289 if (diffTime > PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
290 DFXLOGE("dump remain time is invalid, not set timer");
291 return;
292 }
293
294 struct itimerval timer{};
295 timer.it_value.tv_sec = static_cast<int64_t>(diffTime / NUMBER_ONE_THOUSAND);
296 timer.it_value.tv_usec = static_cast<int64_t>(diffTime * NUMBER_ONE_THOUSAND % NUMBER_ONE_MILLION);
297 timer.it_interval.tv_sec = 0;
298 timer.it_interval.tv_usec = 0;
299
300 if (setitimer(ITIMER_REAL, &timer, nullptr) != 0) {
301 DFXLOGE("start processdump timer fail %{public}d", errno);
302 }
303 }
304
FormatJsonInfoIfNeed()305 void ProcessDumper::FormatJsonInfoIfNeed()
306 {
307 if (!isJsonDump_ && request_.type != ProcessDumpType::DUMP_TYPE_CPP_CRASH) {
308 return;
309 }
310 if (process_ == nullptr) {
311 return;
312 }
313 std::string jsonInfo;
314 DumpInfoJsonFormatter stackInfoFormatter;
315 stackInfoFormatter.GetJsonFormatInfo(request_, *process_, jsonInfo);
316 if (request_.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH) {
317 process_->SetCrashInfoJson(jsonInfo);
318 } else if (request_.type == ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
319 DfxBufferWriter::GetInstance().WriteMsg(jsonInfo);
320 }
321 DFXLOGI("Finish GetJsonFormatInfo len %{public}" PRIuPTR "", jsonInfo.length());
322 }
323
WriteDumpResIfNeed(int32_t resDump)324 void ProcessDumper::WriteDumpResIfNeed(int32_t resDump)
325 {
326 DFXLOGI("dump result: %{public}s", DfxDumpRes::ToString(resDump).c_str());
327 if (request_.siginfo.si_signo != SIGDUMP) {
328 return;
329 }
330 if (!DfxBufferWriter::GetInstance().WriteDumpRes(resDump)) { // write dump res, retry request_ pipefd
331 int pipeWriteFd[] = { -1, -1 };
332 if (RequestPipeFd(request_.pid, FaultLoggerPipeType::PIPE_FD_WRITE, pipeWriteFd) == -1) {
333 DFXLOGE("%{public}s request_ pipe failed, err:%{public}d", __func__, errno);
334 return;
335 }
336 SmartFd bufFd(pipeWriteFd[PIPE_BUF_INDEX]);
337 SmartFd resFd(pipeWriteFd[PIPE_RES_INDEX]);
338 DfxBufferWriter::GetInstance().SetWriteResFd(std::move(resFd));
339 DfxBufferWriter::GetInstance().WriteDumpRes(resDump);
340 }
341 }
342
ReadRequestAndCheck()343 int32_t ProcessDumper::ReadRequestAndCheck()
344 {
345 DFX_TRACE_SCOPED("ReadRequestAndCheck");
346 ElapsedTime counter("ReadRequestAndCheck", 20); // 20 : limit cost time 20 ms
347 ssize_t readCount = OHOS_TEMP_FAILURE_RETRY(read(STDIN_FILENO, &request_, sizeof(ProcessDumpRequest)));
348 request_.threadName[NAME_BUF_LEN - 1] = '\0';
349 request_.processName[NAME_BUF_LEN - 1] = '\0';
350 request_.msg.body[MAX_FATAL_MSG_SIZE - 1] = '\0';
351 request_.appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN - 1] = '\0';
352 auto processName = std::string(request_.processName);
353 SetCrashProcInfo(request_.type, processName, request_.pid, request_.uid);
354 if (readCount != static_cast<long>(sizeof(ProcessDumpRequest))) {
355 DFXLOGE("Failed to read DumpRequest(%{public}d), readCount(%{public}zd).", errno, readCount);
356 ReportCrashException(CrashExceptionCode::CRASH_DUMP_EREADREQ);
357 return DumpErrorCode::DUMP_EREADREQUEST;
358 }
359 #if defined(DEBUG_CRASH_LOCAL_HANDLER)
360 DFX_SetSigAlarmCallBack(SigAlarmCallBack);
361 #endif
362 return DumpErrorCode::DUMP_ESUCCESS;
363 }
364
365
UpdateConfigByRequest()366 void ProcessDumper::UpdateConfigByRequest()
367 {
368 if (request_.type == ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
369 if (request_.siginfo.si_value.sival_int != 0) { // if not equal 0, need not dump other thread info
370 DFXLOGI("updateconfig.");
371 auto dumpInfoComponent = FindDumpInfoByType(request_.type);
372 dumpInfoComponent.erase(std::remove(dumpInfoComponent.begin(), dumpInfoComponent.end(),
373 OTHER_THREAD_DUMP_INFO), dumpInfoComponent.end());
374 auto config = ProcessDumpConfig::GetInstance().GetConfig();
375 config.dumpInfo[request_.type] = dumpInfoComponent;
376 for (const auto& info : dumpInfoComponent) {
377 DFXLOGI("component%{public}s.", info.c_str());
378 }
379 ProcessDumpConfig::GetInstance().SetConfig(std::move(config));
380 }
381 isJsonDump_ = request_.siginfo.si_code == DUMP_TYPE_REMOTE_JSON;
382 }
383 }
384
UnwindWriteJit()385 void ProcessDumper::UnwindWriteJit()
386 {
387 if (request_.type != ProcessDumpType::DUMP_TYPE_CPP_CRASH || !unwinder_) {
388 return;
389 }
390
391 const auto& jitCache = unwinder_->GetJitCache();
392 if (jitCache.empty()) {
393 return;
394 }
395 struct FaultLoggerdRequest jitRequest{
396 .pid = request_.pid,
397 .type = FaultLoggerType::JIT_CODE_LOG,
398 .tid = request_.tid,
399 .time = request_.timeStamp
400 };
401 SmartFd fd(RequestFileDescriptorEx(&jitRequest));
402 if (!fd) {
403 DFXLOGE("request_ jitlog fd failed.");
404 return;
405 }
406
407 if (unwinder_->ArkWriteJitCodeToFile(fd.GetFd()) < 0) {
408 DFXLOGE("jit code write file failed.");
409 }
410 }
411
PrintDumpInfo(int & dumpRes)412 void ProcessDumper::PrintDumpInfo(int& dumpRes)
413 {
414 DFX_TRACE_SCOPED("PrintDumpInfo");
415 if (process_ == nullptr || unwinder_ == nullptr) {
416 return;
417 }
418 auto dumpInfoComponent = FindDumpInfoByType(request_.type);
419 if (dumpInfoComponent.empty()) {
420 return;
421 }
422 // Create objects using reflection
423 auto threadDumpInfo = DumpInfoFactory::GetInstance().CreateObject(dumpInfoComponent[0]);
424 auto prevDumpInfo = threadDumpInfo;
425 auto dumpInfo = threadDumpInfo;
426 for (size_t index = 1; index < dumpInfoComponent.size(); index++) {
427 auto tempDumpInfo = DumpInfoFactory::GetInstance().CreateObject(dumpInfoComponent[index]);
428 if (tempDumpInfo == nullptr) {
429 DFXLOGE("Failed to crreate object%{public}s.", dumpInfoComponent[index].c_str());
430 continue;
431 }
432 dumpInfo = tempDumpInfo;
433 dumpInfo->SetDumpInfo(prevDumpInfo);
434 if (dumpInfoComponent[index] == OTHER_THREAD_DUMP_INFO) {
435 threadDumpInfo = dumpInfo;
436 }
437 prevDumpInfo = dumpInfo;
438 }
439 if (threadDumpInfo != nullptr) {
440 int unwindSuccessCnt = threadDumpInfo->UnwindStack(*process_, request_, *unwinder_);
441 DFXLOGI("unwind success thread count(%{public}d)", unwindSuccessCnt);
442 if (unwindSuccessCnt > 0) {
443 dumpRes = ParseSymbols(threadDumpInfo);
444 } else {
445 dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
446 DFXLOGE("Failed to unwind process.");
447 }
448 }
449
450 if (dumpInfo != nullptr && !isJsonDump_) { // isJsonDump_ will print after format json
451 dumpInfo->Print(*process_, request_, *unwinder_);
452 }
453 }
454
ParseSymbols(std::shared_ptr<DumpInfo> threadDumpInfo)455 int ProcessDumper::ParseSymbols(std::shared_ptr<DumpInfo> threadDumpInfo)
456 {
457 uint64_t curTime = GetAbsTimeMilliSeconds();
458 uint32_t lessRemainTimeMs =
459 static_cast<uint32_t>(ProcessDumpConfig::GetInstance().GetConfig().reservedParseSymbolTime);
460 int dumpRes = 0;
461 if (request_.type != ProcessDumpType::DUMP_TYPE_DUMP_CATCH || expectedDumpFinishTime_ == 0) {
462 threadDumpInfo->Symbolize(*process_, *unwinder_);
463 } else if (expectedDumpFinishTime_ > curTime && expectedDumpFinishTime_ - curTime > lessRemainTimeMs) {
464 parseSymbolTask_ = std::async(std::launch::async, [threadDumpInfo, this]() {
465 DFX_TRACE_SCOPED("parse symbol task");
466 threadDumpInfo->Symbolize(*process_, *unwinder_);
467 });
468 uint64_t waitTime = expectedDumpFinishTime_ - curTime - lessRemainTimeMs;
469 if (parseSymbolTask_.wait_for(std::chrono::milliseconds(waitTime)) != std::future_status::ready) {
470 DFXLOGW("Parse symbol timeout");
471 dumpRes = DumpErrorCode::DUMP_ESYMBOL_PARSE_TIMEOUT;
472 }
473 } else {
474 DFXLOGW("do not parse symbol, remain %{public}" PRId64 "ms", expectedDumpFinishTime_ - curTime);
475 dumpRes = DumpErrorCode::DUMP_ESYMBOL_NO_PARSE;
476 }
477 finishParseSymbolTime_ = GetTimeMillisec();
478 return dumpRes;
479 }
480
InitUnwinder(int & dumpRes)481 bool ProcessDumper::InitUnwinder(int &dumpRes)
482 {
483 DFX_TRACE_SCOPED("InitUnwinder");
484 if (process_ == nullptr) {
485 DFXLOGE("Failed to read real pid!");
486 return false;
487 }
488 pid_t realPid = 0;
489 pid_t vmPid = 0;
490 ReadPids(request_, realPid, vmPid, *process_);
491 if (realPid <= 0 || vmPid <= 0) {
492 ReportCrashException(CrashExceptionCode::CRASH_DUMP_EREADPID);
493 DFXLOGE("Failed to read real pid!");
494 dumpRes = DumpErrorCode::DUMP_EREADPID;
495 return false;
496 }
497 #if defined(__aarch64__)
498 if (coreDumpService_) {
499 coreDumpService_->StartSecondStageDump(vmPid, request_);
500 }
501 #endif
502 process_->SetVmPid(vmPid);
503 #if defined(PROCESSDUMP_MINIDEBUGINFO)
504 UnwinderConfig::SetEnableMiniDebugInfo(true);
505 UnwinderConfig::SetEnableLoadSymbolLazily(true);
506 #endif
507 unwinder_ = std::make_shared<Unwinder>(realPid, vmPid, request_.type != ProcessDumpType::DUMP_TYPE_DUMP_CATCH);
508 unwinder_->EnableParseNativeSymbol(false);
509 if (unwinder_->GetMaps() == nullptr) {
510 ReportCrashException(CrashExceptionCode::CRASH_LOG_EMAPLOS);
511 DFXLOGE("Mapinfo of crashed process is not exist!");
512 dumpRes = DumpErrorCode::DUMP_ENOMAP;
513 return false;
514 }
515 return true;
516 }
517
FindDumpInfoByType(const ProcessDumpType & dumpType)518 std::vector<std::string> ProcessDumper::FindDumpInfoByType(const ProcessDumpType& dumpType)
519 {
520 std::vector<std::string> dumpInfoComponent;
521 auto dumpInfo = ProcessDumpConfig::GetInstance().GetConfig().dumpInfo;
522 if (dumpInfo.find(dumpType) != dumpInfo.end()) {
523 dumpInfoComponent = dumpInfo.find(dumpType)->second;
524 }
525 return dumpInfoComponent;
526 }
527
InitDfxProcess()528 bool ProcessDumper::InitDfxProcess()
529 {
530 DFX_TRACE_SCOPED("InitDfxProcess");
531 if (request_.pid <= 0) {
532 return false;
533 }
534 process_ = std::make_shared<DfxProcess>();
535 process_->InitProcessInfo(request_.pid, request_.nsPid, request_.uid, std::string(request_.processName));
536 if (!process_->InitKeyThread(request_)) {
537 NotifyOperateResult(request_, OPE_FAIL);
538 return false;
539 }
540 #if defined(__aarch64__)
541 if (CoreDumpService::IsCoredumpAllowed(request_)) {
542 coreDumpService_ = std::unique_ptr<CoreDumpService>(new CoreDumpService());
543 }
544 if (coreDumpService_) {
545 coreDumpService_->GetKeyThreadData(request_);
546 }
547 #endif
548 DFXLOGI("Init key thread successfully.");
549 NotifyOperateResult(request_, OPE_SUCCESS);
550 ptrace(PTRACE_SETOPTIONS, request_.tid, NULL, PTRACE_O_TRACEFORK);
551 ptrace(PTRACE_CONT, request_.tid, 0, 0);
552
553 auto dumpInfoComp = FindDumpInfoByType(request_.type);
554 if (std::find(dumpInfoComp.begin(), dumpInfoComp.end(), OTHER_THREAD_DUMP_INFO) != dumpInfoComp.end()) {
555 process_->InitOtherThreads(request_.tid);
556 }
557 DFXLOGI("Finish create all thread.");
558 #if defined(__aarch64__)
559 if (coreDumpService_) {
560 coreDumpService_->StartFirstStageDump(request_);
561 }
562 #endif
563 return true;
564 }
565
GeFaultloggerdRequestType()566 int ProcessDumper::GeFaultloggerdRequestType()
567 {
568 switch (request_.siginfo.si_signo) {
569 case SIGLEAK_STACK:
570 switch (request_.siginfo.si_code) {
571 case SIGLEAK_STACK_FDSAN:
572 FALLTHROUGH_INTENDED;
573 case SIGLEAK_STACK_JEMALLOC:
574 FALLTHROUGH_INTENDED;
575 case SIGLEAK_STACK_BADFD:
576 return FaultLoggerType::CPP_STACKTRACE;
577 default:
578 return FaultLoggerType::LEAK_STACKTRACE;
579 }
580 case SIGDUMP:
581 return FaultLoggerType::CPP_STACKTRACE;
582 default:
583 return FaultLoggerType::CPP_CRASH;
584 }
585 }
586
InitBufferWriter()587 bool ProcessDumper::InitBufferWriter()
588 {
589 DFX_TRACE_SCOPED("InitBufferWriter");
590 SmartFd bufferFd;
591 if (request_.type == ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
592 int pipeWriteFd[] = { -1, -1 };
593 if (RequestPipeFd(request_.pid, FaultLoggerPipeType::PIPE_FD_WRITE, pipeWriteFd) == 0) {
594 bufferFd = SmartFd{pipeWriteFd[PIPE_BUF_INDEX]};
595 DfxBufferWriter::GetInstance().SetWriteResFd(SmartFd{pipeWriteFd[PIPE_RES_INDEX]});
596 }
597 } else {
598 struct FaultLoggerdRequest faultloggerdRequest{
599 .pid = request_.pid,
600 .type = GeFaultloggerdRequestType(),
601 .tid = request_.tid,
602 .time = request_.timeStamp
603 };
604 bufferFd = SmartFd {RequestFileDescriptorEx(&faultloggerdRequest)};
605 if (!bufferFd) {
606 DFXLOGW("Failed to request_ fd from faultloggerd.");
607 ReportCrashException(CrashExceptionCode::CRASH_DUMP_EWRITEFD);
608 bufferFd = SmartFd {CreateFileForCrash(request_.pid, request_.timeStamp)};
609 }
610 }
611
612 bool rst{bufferFd};
613 DfxBufferWriter::GetInstance().SetWriteBufFd(std::move(bufferFd));
614 return rst;
615 }
616
CreateFileForCrash(int32_t pid,uint64_t time) const617 int32_t ProcessDumper::CreateFileForCrash(int32_t pid, uint64_t time) const
618 {
619 const std::string dirPath = "/log/crash";
620 const std::string logFileType = "cppcrash";
621 const int32_t logcrashFileProp = 0644; // 0640:-rw-r--r--
622 if (access(dirPath.c_str(), F_OK) != 0) {
623 DFXLOGE("%{public}s is not exist.", dirPath.c_str());
624 return INVALID_FD;
625 }
626 RemoveFileIfNeed(dirPath);
627 std::string logPath = dirPath + "/" + logFileType + "-" + std::to_string(pid) + "-" + std::to_string(time);
628 int32_t fd = OHOS_TEMP_FAILURE_RETRY(open(logPath.c_str(), O_RDWR | O_CREAT, logcrashFileProp));
629 if (fd == INVALID_FD) {
630 DFXLOGE("create %{public}s failed, errno=%{public}d", logPath.c_str(), errno);
631 } else {
632 DFXLOGI("create crash path %{public}s succ.", logPath.c_str());
633 }
634 return fd;
635 }
636
RemoveFileIfNeed(const std::string & dirPath) const637 void ProcessDumper::RemoveFileIfNeed(const std::string& dirPath) const
638 {
639 const int maxFileCount = 5;
640 std::vector<std::string> files;
641 OHOS::GetDirFiles(dirPath, files);
642 if (files.size() < maxFileCount) {
643 return;
644 }
645
646 std::sort(files.begin(), files.end(),
647 [](const std::string& lhs, const std::string& rhs) {
648 auto lhsSplitPos = lhs.find_last_of("-");
649 auto rhsSplitPos = rhs.find_last_of("-");
650 if (lhsSplitPos == std::string::npos || rhsSplitPos == std::string::npos) {
651 return lhs.compare(rhs) < 0;
652 }
653 return lhs.substr(lhsSplitPos).compare(rhs.substr(rhsSplitPos)) < 0;
654 });
655
656 int deleteNum = static_cast<int>(files.size()) - (maxFileCount - 1);
657 for (int index = 0; index < deleteNum; index++) {
658 DFXLOGI("Now we delete file(%{public}s) due to exceed file max count.", files[index].c_str());
659 OHOS::RemoveFile(files[index]);
660 }
661 }
662
ReportSigDumpStats()663 void ProcessDumper::ReportSigDumpStats()
664 {
665 static std::atomic<bool> hasReportSigDumpStats(false);
666 if (request_.type != ProcessDumpType::DUMP_TYPE_DUMP_CATCH || hasReportSigDumpStats == true) {
667 return;
668 }
669 std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0);
670 auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data());
671 stat->type = PROCESS_DUMP;
672 stat->pid = request_.pid;
673 stat->signalTime = request_.timeStamp;
674 stat->processdumpStartTime = startTime_;
675 stat->processdumpFinishTime = finishTime_ == 0 ? GetTimeMillisec() : finishTime_;
676 stat->writeDumpInfoCost = finishParseSymbolTime_ > 0 ? stat->processdumpFinishTime - finishParseSymbolTime_ : 0;
677 if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess),
678 request_.processName, sizeof(request_.processName)) != 0) {
679 DFXLOGE("Failed to copy target processName (%{public}d)", errno);
680 return;
681 }
682 ReportDumpStats(stat);
683 hasReportSigDumpStats.store(true);
684 }
685 } // namespace HiviewDFX
686 } // namespace OHOS
687