• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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