1 /*
2  * Copyright (c) 2021-2024 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 <cerrno>
19 #include <chrono>
20 #include <cinttypes>
21 #include <csignal>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 #include <dirent.h>
26 #include <fcntl.h>
27 #include <iostream>
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 <ucontext.h>
37 #include <unistd.h>
38 
39 #include "cppcrash_reporter.h"
40 #include "crash_exception.h"
41 #include "dfx_config.h"
42 #include "dfx_define.h"
43 #include "dfx_dump_request.h"
44 #include "dfx_dump_res.h"
45 #include "dfx_fdsan.h"
46 #include "dfx_logger.h"
47 #include "dfx_process.h"
48 #include "dfx_regs.h"
49 #include "dfx_ring_buffer_wrapper.h"
50 #include "dfx_stack_info_formatter.h"
51 #include "dfx_thread.h"
52 #include "dfx_unwind_remote.h"
53 #include "dfx_util.h"
54 #include "dfx_trace.h"
55 #include "directory_ex.h"
56 #include "elapsed_time.h"
57 #include "faultloggerd_client.h"
58 #include "printer.h"
59 #include "procinfo.h"
60 #include "unwinder_config.h"
61 #ifndef is_ohos_lite
62 #include "parameter.h"
63 #include "parameters.h"
64 #endif // !is_ohos_lite
65 
66 namespace OHOS {
67 namespace HiviewDFX {
68 namespace {
69 #undef LOG_DOMAIN
70 #undef LOG_TAG
71 #define LOG_DOMAIN 0xD002D11
72 #define LOG_TAG "DfxProcessDump"
73 const char *const BLOCK_CRASH_PROCESS = "faultloggerd.priv.block_crash_process.enabled";
74 const int MAX_FILE_COUNT = 5;
75 
IsBlockCrashProcess()76 static bool IsBlockCrashProcess()
77 {
78     bool isBlockCrash = false;
79 #ifndef is_ohos_lite
80     isBlockCrash = OHOS::system::GetParameter(BLOCK_CRASH_PROCESS, "false") == "true";
81 #endif
82     return isBlockCrash;
83 }
84 
WriteData(int fd,const std::string & data,size_t blockSize)85 void WriteData(int fd, const std::string& data, size_t blockSize)
86 {
87     size_t dataSize = data.length();
88     size_t index = 0;
89     while (index < dataSize) {
90         size_t writeLength = (index + blockSize) <= dataSize ? blockSize : (dataSize - index);
91         ssize_t nwrite = OHOS_TEMP_FAILURE_RETRY(write(fd, data.substr(index, writeLength).c_str(), writeLength));
92         if (nwrite != static_cast<ssize_t>(writeLength)) {
93             DFXLOG_INFO("%s :: nwrite: %zd, writeLength: %zu", __func__, nwrite, writeLength);
94         }
95         index += writeLength;
96     }
97     DFXLOG_INFO("%s :: needWriteDataSize: %zu, writeDataSize: %zu", __func__, dataSize, index);
98 }
99 
100 #if !defined(__x86_64__)
101 const int ARG_MAX_NUM = 131072;
102 #endif
103 using OpenFilesList = std::map<int, FDInfo>;
104 
ReadLink(std::string & src,std::string & dst)105 bool ReadLink(std::string &src, std::string &dst)
106 {
107     char buf[PATH_MAX];
108     ssize_t count = readlink(src.c_str(), buf, sizeof(buf) - 1);
109     if (count < 0) {
110         return false;
111     }
112     buf[count] = '\0';
113     dst = buf;
114     return true;
115 }
116 
CollectOpenFiles(OpenFilesList & list,pid_t pid)117 void CollectOpenFiles(OpenFilesList &list, pid_t pid)
118 {
119     std::string fdDirName = "/proc/" + std::to_string(pid) + "/fd";
120     std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(fdDirName.c_str()), closedir);
121     if (dir == nullptr) {
122         DFXLOG_ERROR("failed to open directory %s: %s", fdDirName.c_str(), strerror(errno));
123         return;
124     }
125 
126     struct dirent *de;
127     while ((de = readdir(dir.get())) != nullptr) {
128         if (*de->d_name == '.') {
129             continue;
130         }
131 
132         int fd = atoi(de->d_name);
133         std::string path = fdDirName + "/" + std::string(de->d_name);
134         std::string target;
135         if (ReadLink(path, target)) {
136             list[fd].path = target;
137         } else {
138             list[fd].path = "???";
139             DFXLOG_ERROR("failed to readlink %s: %s", path.c_str(), strerror(errno));
140         }
141     }
142 }
143 
144 #if !defined(__x86_64__)
FillFdsaninfo(OpenFilesList & list,pid_t nsPid,uint64_t fdTableAddr)145 void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr)
146 {
147     constexpr size_t fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries);
148     size_t entryOffset = offsetof(FdTable, entries);
149     uint64_t addr = fdTableAddr + entryOffset;
150     FdEntry entrys[fds];
151     if (DfxMemory::ReadProcMemByPid(nsPid, addr, entrys, sizeof(FdEntry) * fds) != sizeof(FdEntry) * fds) {
152         DFXLOG_ERROR("read nsPid mem error %s", strerror(errno));
153         return;
154     }
155     for (size_t i = 0; i < fds; i++) {
156         if (entrys[i].close_tag) {
157             list[i].fdsanOwner = entrys[i].close_tag;
158         }
159     }
160 
161     size_t overflowOffset = offsetof(FdTable, overflow);
162     uintptr_t overflow = 0;
163     uint64_t tmp = fdTableAddr + overflowOffset;
164     if (DfxMemory::ReadProcMemByPid(nsPid, tmp, &overflow, sizeof(overflow)) != sizeof(overflow)) {
165         return;
166     }
167     if (!overflow) {
168         return;
169     }
170 
171     size_t overflowLength;
172     if (DfxMemory::ReadProcMemByPid(nsPid, overflow, &overflowLength, sizeof(overflowLength))
173         != sizeof(overflowLength)) {
174         return;
175     }
176     if (overflowLength > ARG_MAX_NUM) {
177         return;
178     }
179 
180     std::vector<FdEntry> overflowFdEntrys(overflowLength);
181     uint64_t address = overflow + offsetof(FdTableOverflow, entries);
182     if (DfxMemory::ReadProcMemByPid(nsPid, address, overflowFdEntrys.data(), sizeof(FdEntry) * overflowLength) !=
183         sizeof(FdEntry) * overflowLength) {
184         DFXLOG_ERROR("read nsPid mem error %s", strerror(errno));
185         return;
186     }
187     size_t fdIndex = fds;
188     for (size_t i = 0; i < overflowLength; i++) {
189         if (overflowFdEntrys[i].close_tag) {
190             list[fdIndex].fdsanOwner = overflowFdEntrys[i].close_tag;
191         }
192         fdIndex++;
193     }
194 }
195 #endif
196 
DumpOpenFiles(OpenFilesList & files)197 std::string DumpOpenFiles(OpenFilesList &files)
198 {
199     std::string openFiles;
200     for (auto &[fd, entry]: files) {
201         const std::string path = entry.path;
202         uint64_t tag = entry.fdsanOwner;
203         const char* type = fdsan_get_tag_type(tag);
204         uint64_t val = fdsan_get_tag_value(tag);
205         if (!path.empty()) {
206             openFiles += std::to_string(fd) + "->" + path + " " + type + " " + std::to_string(val) + "\n";
207         } else {
208             openFiles += "OpenFilesList contain an entry (fd " + std::to_string(fd) + ") with no path or owner\n";
209         }
210     }
211     return openFiles;
212 }
213 
214 
ReadPids(int & realPid,int & vmPid)215 void ReadPids(int& realPid, int& vmPid)
216 {
217     pid_t pids[PID_MAX] = {0};
218     OHOS_TEMP_FAILURE_RETRY(read(STDIN_FILENO, pids, sizeof(pids)));
219     realPid = pids[REAL_PROCESS_PID];
220     vmPid = pids[VIRTUAL_PROCESS_PID];
221     DFXLOG_INFO("procecdump get real pid is %d vm pid is %d", realPid, vmPid);
222 }
223 
InfoRemoteProcessResult(std::shared_ptr<ProcessDumpRequest> request,int result,int type)224 void InfoRemoteProcessResult(std::shared_ptr<ProcessDumpRequest> request, int result, int type)
225 {
226     if (request == nullptr) {
227         return;
228     }
229     if (request->pmPipeFd[0] != -1) {
230         close(request->pmPipeFd[0]);
231         request->pmPipeFd[0] = -1;
232     }
233     switch (type) {
234         case MAIN_PROCESS:
235             OHOS_TEMP_FAILURE_RETRY(write(request->pmPipeFd[1], &result, sizeof(result)));
236             break;
237         case VIRTUAL_PROCESS:
238             OHOS_TEMP_FAILURE_RETRY(write(request->vmPipeFd[1], &result, sizeof(result)));
239             break;
240         default:
241             break;
242     }
243 }
244 
SetProcessdumpTimeout(siginfo_t & si)245 void SetProcessdumpTimeout(siginfo_t &si)
246 {
247     if (si.si_signo != SIGDUMP) {
248         return;
249     }
250 
251     uint64_t endTime;
252     int tid;
253     ParseSiValue(si, endTime, tid);
254 
255     if (tid == 0) {
256         DFXLOG_INFO("%s", "reset, prevent incorrect reading sival_int for tid");
257         si.si_value.sival_int = 0;
258     }
259 
260     if (endTime == 0) {
261         DFXLOG_INFO("%s", "end time is zero, not set new alarm");
262         return;
263     }
264 
265     uint64_t curTime = GetAbsTimeMilliSeconds();
266     if (curTime >= endTime) {
267         DFXLOG_INFO("%s", "now has timeout, processdump exit");
268 #ifndef CLANG_COVERAGE
269         _exit(0);
270 #endif
271     }
272     uint64_t diffTime = endTime - curTime;
273 
274     DFXLOG_INFO("processdump remain time%" PRIu64 "ms", diffTime);
275     if (diffTime > PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
276         DFXLOG_ERROR("%s", "dump remain time is invalid, not set timer");
277         return;
278     }
279 
280     struct itimerval timer;
281     timer.it_value.tv_sec = static_cast<int64_t>(diffTime / NUMBER_ONE_THOUSAND);
282     timer.it_value.tv_usec = static_cast<int64_t>(diffTime * NUMBER_ONE_THOUSAND % NUMBER_ONE_MILLION);
283     timer.it_interval.tv_sec = 0;
284     timer.it_interval.tv_usec = 0;
285 
286     if (setitimer(ITIMER_REAL, &timer, nullptr) != 0) {
287         DFXLOG_ERROR("start processdump timer fail %d", errno);
288     }
289 }
290 }
291 
GetInstance()292 ProcessDumper &ProcessDumper::GetInstance()
293 {
294     static ProcessDumper ins;
295     return ins;
296 }
297 
Dump()298 void ProcessDumper::Dump()
299 {
300     startTime_ = GetTimeMillisec();
301     std::shared_ptr<ProcessDumpRequest> request = std::make_shared<ProcessDumpRequest>();
302     resDump_ = DumpProcess(request);
303     if (process_ == nullptr) {
304         DFXLOG_ERROR("%s", "Dump process failed, please check permission and whether pid is valid.");
305     } else {
306         if (isCrash_ && process_->vmThread_ != nullptr) {
307             process_->vmThread_->Detach();
308         }
309         if (process_->keyThread_ != nullptr) {
310             process_->keyThread_->Detach();
311         }
312         if (isCrash_ && (request->dumpMode == FUSION_MODE) && IsBlockCrashProcess()) {
313             DFXLOG_INFO("start block crash process pid %d nspid %d", request->pid, request->nsPid);
314             if (syscall(SYS_tgkill, request->nsPid, request->tid, SIGSTOP) != 0) {
315                 DFXLOG_ERROR("send signal stop to nsPid %d fail %s", request->nsPid, strerror(errno));
316             }
317         }
318     }
319 
320     std::string jsonInfo;
321     if (isJsonDump_ || isCrash_) {
322         DfxStackInfoFormatter formatter(process_, request);
323         formatter.GetStackInfo(isJsonDump_, jsonInfo);
324         DFXLOG_INFO("Finish GetStackInfo len %" PRIuPTR "", jsonInfo.length());
325         if (isJsonDump_) {
326             WriteData(jsonFd_, jsonInfo, MAX_PIPE_SIZE);
327         }
328     }
329 
330     finishTime_ = GetTimeMillisec();
331     ReportSigDumpStats(request);
332     // After skipping InitPrintThread due to ptrace failure or other reasons,
333     // request resFd_ to write back the result to dumpcatch
334     if (request->siginfo.si_signo == SIGDUMP && resFd_ == -1) {
335         resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES);
336         if (resFd_ < 0) {
337             resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_RES);
338         }
339     }
340     WriteDumpRes(resDump_);
341     // print keythread base info to hilog when carsh
342     DfxRingBufferWrapper::GetInstance().PrintBaseInfo();
343     DfxRingBufferWrapper::GetInstance().StopThread();
344     DFXLOG_INFO("Finish dump stacktrace for %s(%d:%d).", request->processName, request->pid, request->tid);
345     CloseDebugLog();
346     if (resDump_ != DumpErrorCode::DUMP_ENOMAP && resDump_ != DumpErrorCode::DUMP_EREADPID) {
347         ReportCrashInfo(jsonInfo);
348     }
349     if ((request->dumpMode == FUSION_MODE) && isCrash_) {
350         InfoRemoteProcessResult(request, OPE_CONTINUE, MAIN_PROCESS);
351     }
352 }
353 
ReadRequestAndCheck(std::shared_ptr<ProcessDumpRequest> request)354 static int32_t ReadRequestAndCheck(std::shared_ptr<ProcessDumpRequest> request)
355 {
356     DFX_TRACE_SCOPED("ReadRequestAndCheck");
357     ElapsedTime counter("ReadRequestAndCheck", 20); // 20 : limit cost time 20 ms
358     ssize_t readCount = OHOS_TEMP_FAILURE_RETRY(read(STDIN_FILENO, request.get(), sizeof(ProcessDumpRequest)));
359     request->threadName[NAME_BUF_LEN - 1] = '\0';
360     request->processName[NAME_BUF_LEN - 1] = '\0';
361     request->lastFatalMessage[MAX_FATAL_MSG_SIZE - 1] = '\0';
362     request->appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN - 1] = '\0';
363     if (readCount != static_cast<long>(sizeof(ProcessDumpRequest))) {
364         DFXLOG_ERROR("Failed to read DumpRequest(%d), readCount(%zd).", errno, readCount);
365         ReportCrashException(request->processName, request->pid, request->uid,
366                              CrashExceptionCode::CRASH_DUMP_EREADREQ);
367         return DumpErrorCode::DUMP_EREADREQUEST;
368     }
369 
370     return DumpErrorCode::DUMP_ESUCCESS;
371 }
372 
GetOpenFiles(int32_t pid,int nsPid,uint64_t fdTableAddr)373 std::string GetOpenFiles(int32_t pid, int nsPid, uint64_t fdTableAddr)
374 {
375     DFX_TRACE_SCOPED("GetOpenFiles");
376     OpenFilesList openFies;
377     CollectOpenFiles(openFies, pid);
378 #if !defined(__x86_64__)
379     FillFdsaninfo(openFies, nsPid, fdTableAddr);
380 #endif
381     std::string fds = DumpOpenFiles(openFies);
382     DFXLOG_INFO("%s", "get open files info finish");
383     return fds;
384 }
385 
InitRegs(std::shared_ptr<ProcessDumpRequest> request,int & dumpRes)386 void ProcessDumper::InitRegs(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes)
387 {
388     DFX_TRACE_SCOPED("InitRegs");
389     uint32_t opeResult = OPE_SUCCESS;
390     if (request->dumpMode == FUSION_MODE) {
391         if (!DfxUnwindRemote::GetInstance().InitProcessAllThreadRegs(request, process_)) {
392             DFXLOG_ERROR("%s", "Failed to init process regs.");
393             dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
394             opeResult = OPE_FAIL;
395         }
396 
397         InfoRemoteProcessResult(request, opeResult, MAIN_PROCESS);
398         DFXLOG_INFO("%s", "get all tid regs finish");
399     }
400 }
401 
IsTargetProcessAlive(std::shared_ptr<ProcessDumpRequest> request)402 bool ProcessDumper::IsTargetProcessAlive(std::shared_ptr<ProcessDumpRequest> request)
403 {
404     if ((request->dumpMode == SPLIT_MODE) && ((!isCrash_ && (syscall(SYS_getppid) != request->nsPid)) ||
405         (isCrash_ && (syscall(SYS_getppid) != request->vmNsPid)))) {
406         DfxRingBufferWrapper::GetInstance().AppendMsg(
407             "Target process has been killed, the crash log may not be fully generated.");
408         ReportCrashException(request->processName, request->pid, request->uid,
409                              CrashExceptionCode::CRASH_DUMP_EKILLED);
410         return false;
411     }
412     return true;
413 }
414 
UnwindWriteJit(const ProcessDumpRequest & request)415 void ProcessDumper::UnwindWriteJit(const ProcessDumpRequest &request)
416 {
417     if (!isCrash_) {
418         return;
419     }
420 
421     const auto& jitCache = unwinder_->GetJitCache();
422     if (jitCache.empty()) {
423         return;
424     }
425     struct FaultLoggerdRequest jitRequest;
426     (void)memset_s(&jitRequest, sizeof(jitRequest), 0, sizeof(jitRequest));
427     jitRequest.type = FaultLoggerType::JIT_CODE_LOG;
428     jitRequest.pid = request.pid;
429     jitRequest.tid = request.tid;
430     jitRequest.uid = request.uid;
431     jitRequest.time = OHOS::HiviewDFX::GetTimeMilliSeconds();
432     int32_t fd = RequestFileDescriptorEx(&jitRequest);
433     if (fd == -1) {
434         DFXLOG_ERROR("%s", "request jitlog fd failed.");
435         return;
436     }
437     if (unwinder_->ArkWriteJitCodeToFile(fd) < 0) {
438         DFXLOG_ERROR("%s", "jit code write file failed.");
439     }
440     (void)close(fd);
441 }
442 
ReadStringByPtrace(pid_t tid,uintptr_t addr)443 std::string ProcessDumper::ReadStringByPtrace(pid_t tid, uintptr_t addr)
444 {
445     constexpr int bufLen = 256;
446     long buffer[bufLen] = {0};
447     for (int i = 0; i < bufLen - 1; i++) {
448         long ret = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr + sizeof(long) * i), nullptr);
449         if (ret == -1) {
450             DFXLOG_ERROR("read target mem by ptrace failed, errno(%s).", strerror(errno));
451             break;
452         }
453         buffer[i] = ret;
454         if (ret == 0) {
455             break;
456         }
457     }
458     char* val = reinterpret_cast<char*>(buffer);
459     return std::string(val);
460 }
461 
GetCrashObj(std::shared_ptr<ProcessDumpRequest> request)462 void ProcessDumper::GetCrashObj(std::shared_ptr<ProcessDumpRequest> request)
463 {
464 #ifdef __LP64__
465     if (!isCrash_ || request->crashObj == 0) {
466         return;
467     }
468     uintptr_t type = request->crashObj >> 56; // 56 :: Move 56 bit to the right
469     uintptr_t addr = request->crashObj & 0xffffffffffffff;
470     switch (type) {
471         case 0: {
472             if (process_ != nullptr) {
473                 process_->SetFatalMessage(process_->GetFatalMessage() + ReadStringByPtrace(request->nsPid, addr));
474             }
475             break;
476         }
477         default:
478             break;
479     }
480 #endif
481 }
482 
Unwind(std::shared_ptr<ProcessDumpRequest> request,int & dumpRes,pid_t vmPid)483 bool ProcessDumper::Unwind(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes, pid_t vmPid)
484 {
485     // dump unwind should still keep main thread or aim thread is frist unwind
486     if (!isCrash_) {
487         int tid = request->siginfo.si_value.sival_int;
488         tid = tid != 0 ? tid : request->nsPid;
489         for (auto &thread : process_->GetOtherThreads()) {
490             if (thread->threadInfo_.nsTid == tid) {
491                 swap(process_->keyThread_, thread);
492                 break;
493             }
494         }
495     }
496     GetCrashObj(request);
497     if (!DfxUnwindRemote::GetInstance().UnwindProcess(request, process_, unwinder_, vmPid)) {
498         DFXLOG_ERROR("%s", "Failed to unwind process.");
499         dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
500         return false;
501     }
502 
503     UnwindWriteJit(*request);
504     return true;
505 }
506 
DumpProcess(std::shared_ptr<ProcessDumpRequest> request)507 int ProcessDumper::DumpProcess(std::shared_ptr<ProcessDumpRequest> request)
508 {
509     DFX_TRACE_SCOPED("DumpProcess");
510     int dumpRes = DumpErrorCode::DUMP_ESUCCESS;
511     uint32_t opeResult = OPE_SUCCESS;
512     do {
513         if ((dumpRes = ReadRequestAndCheck(request)) != DumpErrorCode::DUMP_ESUCCESS) {
514             break;
515         }
516         SetProcessdumpTimeout(request->siginfo);
517         isCrash_ = request->siginfo.si_signo != SIGDUMP;
518         bool isLeakDump = request->siginfo.si_signo == SIGLEAK_STACK;
519         // We need check pid is same with getppid().
520         // As in signal handler, current process is a child process, and target pid is our parent process.
521         // If pid namespace is enabled, both ppid and pid are equal one.
522         // In this case, we have to parse /proc/self/status
523         if ((request->dumpMode == SPLIT_MODE) && (((!isCrash_) && (syscall(SYS_getppid) != request->nsPid)) ||
524             ((isCrash_ || isLeakDump) && (syscall(SYS_getppid) != request->vmNsPid)))) {
525             DFXLOG_ERROR("Target process(%s:%d) is not parent pid(%ld), exit processdump for signal(%d).",
526                 request->processName, request->nsPid, syscall(SYS_getppid), request->siginfo.si_signo);
527             dumpRes = DumpErrorCode::DUMP_EGETPPID;
528             break;
529         }
530         DFXLOG_INFO("Processdump SigVal(%d), TargetPid(%d:%d), TargetTid(%d), threadname(%s).",
531             request->siginfo.si_value.sival_int, request->pid, request->nsPid, request->tid, request->threadName);
532 
533         if (InitProcessInfo(request) < 0) {
534             DFXLOG_ERROR("%s", "Failed to init crash process info.");
535             dumpRes = DumpErrorCode::DUMP_EATTACH;
536             break;
537         }
538         InitRegs(request, dumpRes);
539         pid_t vmPid = 0;
540         if (!InitUnwinder(request, vmPid, dumpRes) && (isCrash_ && !isLeakDump)) {
541             opeResult = OPE_FAIL;
542             break;
543         }
544         if (InitPrintThread(request) < 0) {
545             DFXLOG_ERROR("%s", "Failed to init print thread.");
546             dumpRes = DumpErrorCode::DUMP_EGETFD;
547         }
548         if (isCrash_ && !isLeakDump) {
549             process_->openFiles = GetOpenFiles(request->pid, request->nsPid, request->fdTableAddr);
550             reporter_ = std::make_shared<CppCrashReporter>(request->timeStamp, process_, request->dumpMode);
551         }
552         if (!Unwind(request, dumpRes, vmPid)) {
553             opeResult = OPE_FAIL;
554         }
555     } while (false);
556     if (request->dumpMode == FUSION_MODE) {
557         InfoRemoteProcessResult(request, opeResult, VIRTUAL_PROCESS);
558     }
559     if (dumpRes == DumpErrorCode::DUMP_ESUCCESS && !IsTargetProcessAlive(request)) {
560         dumpRes = DumpErrorCode::DUMP_EGETPPID;
561     }
562     return dumpRes;
563 }
564 
InitVmThread(std::shared_ptr<ProcessDumpRequest> request)565 bool ProcessDumper::InitVmThread(std::shared_ptr<ProcessDumpRequest> request)
566 {
567     if (request == nullptr || process_ == nullptr) {
568         return false;
569     }
570     if (isCrash_ && request->vmPid != 0) {
571         if (getppid() != request->vmNsPid) {
572             DFXLOG_ERROR("VM process(%d) should be parent pid.", request->vmNsPid);
573             ReportCrashException(request->processName, request->pid, request->uid,
574                                  CrashExceptionCode::CRASH_DUMP_EPARENTPID);
575             return false;
576         }
577         process_->vmThread_ = DfxThread::Create(request->vmPid, request->vmPid, request->vmNsPid);
578         if ((process_->vmThread_ == nullptr) || (!process_->vmThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT))) {
579             DFXLOG_ERROR("Failed to attach vm thread(%d).", request->vmNsPid);
580             return false;
581         }
582 
583         process_->vmThread_->SetThreadRegs(DfxRegs::CreateFromUcontext(request->context));
584         process_->vmThread_->threadInfo_.threadName = std::string(request->threadName);
585     }
586     return true;
587 }
588 
InitKeyThread(std::shared_ptr<ProcessDumpRequest> request)589 bool ProcessDumper::InitKeyThread(std::shared_ptr<ProcessDumpRequest> request)
590 {
591     if (request == nullptr || process_ == nullptr) {
592         return false;
593     }
594     pid_t nsTid = request->tid;
595     pid_t tid = process_->ChangeTid(nsTid, true);
596     process_->keyThread_ = DfxThread::Create(process_->processInfo_.pid, tid, nsTid);
597     if ((process_->keyThread_ == nullptr) || (!process_->keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT))) {
598         DFXLOG_ERROR("Failed to attach key thread(%d).", nsTid);
599         ReportCrashException(request->processName, request->pid, request->uid,
600                              CrashExceptionCode::CRASH_DUMP_EATTACH);
601         if (!isCrash_) {
602             return false;
603         }
604     }
605     if ((process_->keyThread_ != nullptr) && request->dumpMode == FUSION_MODE) {
606         ptrace(PTRACE_CONT, process_->keyThread_->threadInfo_.nsTid, 0, 0);
607     }
608 
609     if ((process_->keyThread_ != nullptr) && (request->dumpMode == SPLIT_MODE) && !isCrash_) {
610         process_->keyThread_->SetThreadRegs(DfxRegs::CreateFromUcontext(request->context));
611     }
612 
613     if ((process_->keyThread_ != nullptr) && process_->keyThread_->threadInfo_.threadName.empty()) {
614         process_->keyThread_->threadInfo_.threadName = std::string(request->threadName);
615     }
616     return true;
617 }
618 
InitUnwinder(std::shared_ptr<ProcessDumpRequest> request,pid_t & vmPid,int & dumpRes)619 bool ProcessDumper::InitUnwinder(std::shared_ptr<ProcessDumpRequest> request, pid_t &vmPid, int &dumpRes)
620 {
621     DFX_TRACE_SCOPED("InitUnwinder");
622     pid_t realPid = 0;
623     if (request->dumpMode == FUSION_MODE) {
624         ReadPids(realPid, vmPid);
625         if (realPid == 0 || vmPid == 0) {
626             ReportCrashException(request->processName, request->pid, request->uid,
627                 CrashExceptionCode::CRASH_DUMP_EREADPID);
628             DFXLOG_ERROR("%s", "Failed to read real pid!");
629             dumpRes = DumpErrorCode::DUMP_EREADPID;
630             return false;
631         }
632     }
633     // frezze detach after vm process create
634     if (!isCrash_) {
635         if (process_->keyThread_ != nullptr) {
636             process_->keyThread_->Detach();
637         }
638         process_->Detach();
639         DFXLOG_INFO("%s", "ptrace detach all tids");
640     }
641 
642     if (request->dumpMode == FUSION_MODE) {
643         unwinder_ = std::make_shared<Unwinder>(realPid, vmPid, isCrash_);
644     } else {
645         if (isCrash_) {
646             unwinder_ = std::make_shared<Unwinder>(process_->vmThread_->threadInfo_.pid);
647         } else {
648             unwinder_ = std::make_shared<Unwinder>(process_->processInfo_.pid, false);
649         }
650     }
651     if (unwinder_ == nullptr) {
652         DFXLOG_ERROR("%s", "unwinder_ is nullptr!");
653         return false;
654     }
655     if (unwinder_->GetMaps() == nullptr) {
656         ReportCrashException(request->processName, request->pid, request->uid,
657             CrashExceptionCode::CRASH_LOG_EMAPLOS);
658         DFXLOG_ERROR("%s", "Mapinfo of crashed process is not exist!");
659         dumpRes = DumpErrorCode::DUMP_ENOMAP;
660         return false;
661     }
662     return true;
663 }
664 
InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)665 int ProcessDumper::InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)
666 {
667     DFX_TRACE_SCOPED("InitProcessInfo");
668     if (request->pid <= 0) {
669         return -1;
670     }
671     process_ = DfxProcess::Create(request->pid, request->nsPid);
672     if (process_ == nullptr) {
673         return -1;
674     }
675     if (process_->processInfo_.processName.empty()) {
676         process_->processInfo_.processName = std::string(request->processName);
677     }
678     process_->processInfo_.uid = request->uid;
679     process_->recycleTid_ = request->recycleTid;
680     process_->SetFatalMessage(request->lastFatalMessage);
681 
682     if (!InitVmThread(request)) {
683         return -1;
684     }
685 
686     if (!InitKeyThread(request)) {
687         return -1;
688     }
689 
690     DFXLOG_INFO("%s", "ptrace attach all tids");
691     bool isLeakDump = request->siginfo.si_signo == SIGLEAK_STACK;
692     if (isCrash_ && !isLeakDump) {
693         process_->InitOtherThreads();
694         process_->Attach();
695     } else {
696         if (!isLeakDump) {
697             process_->InitOtherThreads();
698             if (request->dumpMode == FUSION_MODE) {
699                 process_->Attach();
700             }
701         }
702     }
703 #if defined(PROCESSDUMP_MINIDEBUGINFO)
704     UnwinderConfig::SetEnableMiniDebugInfo(true);
705     UnwinderConfig::SetEnableLoadSymbolLazily(true);
706 #endif
707     return 0;
708 }
709 
GetLogTypeBySignal(int sig)710 int ProcessDumper::GetLogTypeBySignal(int sig)
711 {
712     switch (sig) {
713         case SIGLEAK_STACK:
714             return FaultLoggerType::LEAK_STACKTRACE;
715         case SIGDUMP:
716             return FaultLoggerType::CPP_STACKTRACE;
717         default:
718             return FaultLoggerType::CPP_CRASH;
719     }
720 }
721 
CreateFileForCrash(int32_t pid,uint64_t time) const722 int32_t ProcessDumper::CreateFileForCrash(int32_t pid, uint64_t time) const
723 {
724     const std::string logFilePath = "/log/crash";
725     const std::string logFileType = "cppcrash";
726     const int32_t logcrashFileProp = 0644; // 0640:-rw-r--r--
727     if (access(logFilePath.c_str(), F_OK) != 0) {
728         DFXLOG_ERROR("%s is not exist.", logFilePath.c_str());
729         return INVALID_FD;
730     }
731     std::stringstream ss;
732     ss << logFilePath << "/" << logFileType << "-" << pid << "-" << time;
733     std::string logPath = ss.str();
734     int32_t fd = OHOS_TEMP_FAILURE_RETRY(open(logPath.c_str(), O_RDWR | O_CREAT, logcrashFileProp));
735     if (fd == INVALID_FD) {
736         DFXLOG_ERROR("create %s failed, errno=%d", logPath.c_str(), errno);
737     } else {
738         DFXLOG_INFO("create crash path %s succ.", logPath.c_str());
739     }
740     return fd;
741 }
742 
RemoveFileIfNeed()743 void ProcessDumper::RemoveFileIfNeed()
744 {
745     const std::string logFilePath = "/log/crash";
746     std::vector<std::string> files;
747     OHOS::GetDirFiles(logFilePath, files);
748     if (files.size() < MAX_FILE_COUNT) {
749         return;
750     }
751 
752     std::sort(files.begin(), files.end(),
753         [](const std::string& lhs, const std::string& rhs) {
754         auto lhsSplitPos = lhs.find_last_of("-");
755         auto rhsSplitPos = rhs.find_last_of("-");
756         if (lhsSplitPos == std::string::npos || rhsSplitPos == std::string::npos) {
757             return lhs.compare(rhs) < 0;
758         }
759         return lhs.substr(lhsSplitPos).compare(rhs.substr(rhsSplitPos)) < 0;
760     });
761 
762     int deleteNum = static_cast<int>(files.size()) - (MAX_FILE_COUNT - 1);
763     for (int index = 0; index < deleteNum; index++) {
764         DFXLOG_INFO("Now we delete file(%s) due to exceed file max count.", files[index].c_str());
765         OHOS::RemoveFile(files[index]);
766     }
767 }
768 
InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)769 int ProcessDumper::InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)
770 {
771     DFX_TRACE_SCOPED("InitPrintThread");
772     int fd = -1;
773     struct FaultLoggerdRequest faultloggerdRequest;
774     (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest));
775     faultloggerdRequest.type = ProcessDumper::GetLogTypeBySignal(request->siginfo.si_signo);
776     faultloggerdRequest.pid = request->pid;
777     faultloggerdRequest.tid = request->tid;
778     faultloggerdRequest.uid = request->uid;
779     faultloggerdRequest.time = request->timeStamp;
780     isJsonDump_ = false;
781     jsonFd_ = -1;
782     if (isCrash_ || faultloggerdRequest.type == FaultLoggerType::LEAK_STACKTRACE) {
783         if (DfxConfig::GetConfig().logPersist) {
784             InitDebugLog((int)faultloggerdRequest.type, request->pid, request->tid, request->uid);
785         }
786         fd = RequestFileDescriptorEx(&faultloggerdRequest);
787         if (fd == -1) {
788             ProcessDumper::RemoveFileIfNeed();
789             fd = CreateFileForCrash(request->pid, request->timeStamp);
790         }
791         DfxRingBufferWrapper::GetInstance().SetWriteFunc(ProcessDumper::WriteDumpBuf);
792     } else {
793         jsonFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF);
794         if (jsonFd_ < 0) {
795             // If fd returns -1, we try to obtain the fd that needs to return JSON style
796             fd = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
797             resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_RES);
798             DFXLOG_DEBUG("write buf fd: %d, write res fd: %d", fd, resFd_);
799         } else {
800             resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES);
801             DFXLOG_DEBUG("write json fd: %d, res fd: %d", jsonFd_, resFd_);
802         }
803     }
804     if (jsonFd_ > 0) {
805         isJsonDump_ = true;
806     }
807     if ((fd < 0) && (jsonFd_ < 0)) {
808         DFXLOG_WARN("%s", "Failed to request fd from faultloggerd.");
809         ReportCrashException(request->processName, request->pid, request->uid,
810                              CrashExceptionCode::CRASH_DUMP_EWRITEFD);
811     }
812     if (!isJsonDump_) {
813         DfxRingBufferWrapper::GetInstance().SetWriteBufFd(fd);
814     }
815     DfxRingBufferWrapper::GetInstance().StartThread();
816     return isJsonDump_ ? jsonFd_ : fd;
817 }
818 
WriteDumpBuf(int fd,const char * buf,const int len)819 int ProcessDumper::WriteDumpBuf(int fd, const char* buf, const int len)
820 {
821     if (buf == nullptr) {
822         return -1;
823     }
824     return WriteLog(fd, "%s", buf);
825 }
826 
WriteDumpRes(int32_t res)827 void ProcessDumper::WriteDumpRes(int32_t res)
828 {
829     DFXLOG_INFO("%s :: res: %d", __func__, res);
830     if (resFd_ > 0) {
831         ssize_t nwrite = OHOS_TEMP_FAILURE_RETRY(write(resFd_, &res, sizeof(res)));
832         if (nwrite < 0) {
833             DFXLOG_ERROR("%s write fail, err:%d", __func__, errno);
834         }
835         close(resFd_);
836         resFd_ = -1;
837     } else {
838         if (res != DUMP_ESUCCESS) {
839             DfxRingBufferWrapper::GetInstance().AppendMsg("Result:\n");
840             DfxRingBufferWrapper::GetInstance().AppendMsg(DfxDumpRes::ToString(res) + "\n");
841         }
842     }
843 }
844 
IsCrash() const845 bool ProcessDumper::IsCrash() const
846 {
847     return isCrash_;
848 }
849 
ReportSigDumpStats(const std::shared_ptr<ProcessDumpRequest> & request) const850 void ProcessDumper::ReportSigDumpStats(const std::shared_ptr<ProcessDumpRequest> &request) const
851 {
852     if (isCrash_) {
853         return;
854     }
855 
856     std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0);
857     auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data());
858     stat->type = PROCESS_DUMP;
859     stat->pid = request->pid;
860     stat->signalTime = request->timeStamp;
861     stat->processdumpStartTime = startTime_;
862     stat->processdumpFinishTime = finishTime_;
863     if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess),
864         request->processName, sizeof(request->processName)) != 0) {
865         DFXLOG_ERROR("Failed to copy target processName (%d)", errno);
866         return;
867     }
868 
869     ReportDumpStats(stat);
870 }
871 
ReportCrashInfo(const std::string & jsonInfo)872 void ProcessDumper::ReportCrashInfo(const std::string& jsonInfo)
873 {
874     if (reporter_ != nullptr) {
875         reporter_->SetCppCrashInfo(jsonInfo);
876         reporter_->ReportToHiview();
877         reporter_->ReportToAbilityManagerService();
878     }
879 }
880 } // namespace HiviewDFX
881 } // namespace OHOS
882