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 <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 <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 "elapsed_time.h"
56 #include "faultloggerd_client.h"
57 #ifndef HISYSEVENT_DISABLE
58 #include "hisysevent.h"
59 #endif
60 #include "printer.h"
61 #include "procinfo.h"
62 #include "unwinder_config.h"
63 #ifndef is_ohos_lite
64 #include "parameter.h"
65 #include "parameters.h"
66 #endif // !is_ohos_lite
67 
68 namespace OHOS {
69 namespace HiviewDFX {
70 namespace {
71 #undef LOG_DOMAIN
72 #undef LOG_TAG
73 #define LOG_DOMAIN 0xD002D11
74 #define LOG_TAG "DfxProcessDump"
75 const char *const BLOCK_CRASH_PROCESS = "faultloggerd.priv.block_crash_process.enabled";
76 
IsBlockCrashProcess()77 static bool IsBlockCrashProcess()
78 {
79     bool isBlockCrash = false;
80 #ifndef is_ohos_lite
81     isBlockCrash = OHOS::system::GetParameter(BLOCK_CRASH_PROCESS, "false") == "true";
82 #endif
83     return isBlockCrash;
84 }
85 
WriteData(int fd, const std::string& data, size_t blockSize)86 void WriteData(int fd, const std::string& data, size_t blockSize)
87 {
88     size_t dataSize = data.length();
89     size_t index = 0;
90     while (index < dataSize) {
91         size_t writeLength = (index + blockSize) <= dataSize ? blockSize : (dataSize - index);
92         ssize_t nwrite = OHOS_TEMP_FAILURE_RETRY(write(fd, data.substr(index, writeLength).c_str(), writeLength));
93         if (nwrite != static_cast<ssize_t>(writeLength)) {
94             DFXLOGI("%{public}s :: nwrite: %{public}zd, writeLength: %{public}zu", __func__, nwrite, writeLength);
95         }
96         index += writeLength;
97     }
98     DFXLOGI("%{public}s :: needWriteDataSize: %{public}zu, writeDataSize: %{public}zu", __func__, dataSize, index);
99 }
100 
101 #if !defined(__x86_64__)
102 const int ARG_MAX_NUM = 131072;
103 #endif
104 using OpenFilesList = std::map<int, FDInfo>;
105 
ReadLink(std::string &src, std::string &dst)106 bool ReadLink(std::string &src, std::string &dst)
107 {
108     char buf[PATH_MAX];
109     ssize_t count = readlink(src.c_str(), buf, sizeof(buf) - 1);
110     if (count < 0) {
111         return false;
112     }
113     buf[count] = '\0';
114     dst = buf;
115     return true;
116 }
117 
CollectOpenFiles(OpenFilesList &list, pid_t pid)118 void CollectOpenFiles(OpenFilesList &list, pid_t pid)
119 {
120     std::string fdDirName = "/proc/" + std::to_string(pid) + "/fd";
121     std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(fdDirName.c_str()), closedir);
122     if (dir == nullptr) {
123         DFXLOGE("failed to open directory %{public}s: %{public}s", fdDirName.c_str(), strerror(errno));
124         return;
125     }
126 
127     struct dirent *de;
128     while ((de = readdir(dir.get())) != nullptr) {
129         if (*de->d_name == '.') {
130             continue;
131         }
132 
133         int fd = atoi(de->d_name);
134         std::string path = fdDirName + "/" + std::string(de->d_name);
135         std::string target;
136         if (ReadLink(path, target)) {
137             list[fd].path = target;
138         } else {
139             list[fd].path = "???";
140             DFXLOGE("failed to readlink %{public}s: %{public}s", path.c_str(), strerror(errno));
141         }
142     }
143 }
144 
145 #if !defined(__x86_64__)
FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr)146 void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr)
147 {
148     constexpr size_t fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries);
149     size_t entryOffset = offsetof(FdTable, entries);
150     uint64_t addr = fdTableAddr + entryOffset;
151     FdEntry entrys[fds];
152     if (DfxMemory::ReadProcMemByPid(nsPid, addr, entrys, sizeof(FdEntry) * fds) != sizeof(FdEntry) * fds) {
153         DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno));
154         return;
155     }
156     for (size_t i = 0; i < fds; i++) {
157         if (entrys[i].close_tag) {
158             list[i].fdsanOwner = entrys[i].close_tag;
159         }
160     }
161 
162     size_t overflowOffset = offsetof(FdTable, overflow);
163     uintptr_t overflow = 0;
164     uint64_t tmp = fdTableAddr + overflowOffset;
165     if (DfxMemory::ReadProcMemByPid(nsPid, tmp, &overflow, sizeof(overflow)) != sizeof(overflow)) {
166         return;
167     }
168     if (!overflow) {
169         return;
170     }
171 
172     size_t overflowLength;
173     if (DfxMemory::ReadProcMemByPid(nsPid, overflow, &overflowLength, sizeof(overflowLength))
174         != sizeof(overflowLength)) {
175         return;
176     }
177     if (overflowLength > ARG_MAX_NUM) {
178         return;
179     }
180 
181     std::vector<FdEntry> overflowFdEntrys(overflowLength);
182     uint64_t address = overflow + offsetof(FdTableOverflow, entries);
183     if (DfxMemory::ReadProcMemByPid(nsPid, address, overflowFdEntrys.data(), sizeof(FdEntry) * overflowLength) !=
184         sizeof(FdEntry) * overflowLength) {
185         DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno));
186         return;
187     }
188     size_t fdIndex = fds;
189     for (size_t i = 0; i < overflowLength; i++) {
190         if (overflowFdEntrys[i].close_tag) {
191             list[fdIndex].fdsanOwner = overflowFdEntrys[i].close_tag;
192         }
193         fdIndex++;
194     }
195 }
196 #endif
197 
DumpOpenFiles(OpenFilesList &files)198 std::string DumpOpenFiles(OpenFilesList &files)
199 {
200     std::string openFiles;
201     for (auto &[fd, entry]: files) {
202         const std::string path = entry.path;
203         uint64_t tag = entry.fdsanOwner;
204         const char* type = fdsan_get_tag_type(tag);
205         uint64_t val = fdsan_get_tag_value(tag);
206         if (!path.empty()) {
207             openFiles += std::to_string(fd) + "->" + path + " " + type + " " + std::to_string(val) + "\n";
208         } else {
209             openFiles += "OpenFilesList contain an entry (fd " + std::to_string(fd) + ") with no path or owner\n";
210         }
211     }
212     return openFiles;
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     DFXLOGW("procecdump get real pid is %{public}d vm pid is %{public}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         DFXLOGI("reset, prevent incorrect reading sival_int for tid");
257         si.si_value.sival_int = 0;
258     }
259 
260     if (endTime == 0) {
261         DFXLOGI("end time is zero, not set new alarm");
262         return;
263     }
264 
265     uint64_t curTime = GetAbsTimeMilliSeconds();
266     if (curTime >= endTime) {
267         DFXLOGI("now has timeout, processdump exit");
268 #ifndef CLANG_COVERAGE
269         _exit(0);
270 #endif
271     }
272     uint64_t diffTime = endTime - curTime;
273 
274     DFXLOGI("processdump remain time%{public}" PRIu64 "ms", diffTime);
275     if (diffTime > PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
276         DFXLOGE("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         DFXLOGE("start processdump timer fail %{public}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         DFXLOGE("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             DFXLOGI("start block crash process pid %{public}d nspid %{public}d", request->pid, request->nsPid);
314             if (syscall(SYS_tgkill, request->nsPid, request->tid, SIGSTOP) != 0) {
315                 DFXLOGE("send signal stop to nsPid %{public}d fail %{public}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         DFXLOGI("Finish GetStackInfo len %{public}" 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     DFXLOGW("Finish dump stacktrace for %{public}s(%{public}d:%{public}d).",
345         request->processName, request->pid, request->tid);
346     Report(request, jsonInfo);
347 }
348 
Report(std::shared_ptr<ProcessDumpRequest> request, std::string &jsonInfo)349 void ProcessDumper::Report(std::shared_ptr<ProcessDumpRequest> request, std::string &jsonInfo)
350 {
351     if (request == nullptr) {
352         DFXLOGE("request is nullptr.");
353         return;
354     }
355     if (request->msg.type == MESSAGE_FDSAN_DEBUG ||
356         request->msg.type == MESSAGE_JEMALLOC ||
357         request->msg.type == MESSAGE_BADFD) {
358         ReportAddrSanitizer(*request, jsonInfo);
359         return;
360     }
361     if (resDump_ != DumpErrorCode::DUMP_ENOMAP && resDump_ != DumpErrorCode::DUMP_EREADPID) {
362         ReportCrashInfo(jsonInfo);
363     }
364     if ((request->dumpMode == FUSION_MODE) && isCrash_) {
365         InfoRemoteProcessResult(request, OPE_CONTINUE, MAIN_PROCESS);
366     }
367 }
368 
ReadRequestAndCheck(std::shared_ptr<ProcessDumpRequest> request)369 static int32_t ReadRequestAndCheck(std::shared_ptr<ProcessDumpRequest> request)
370 {
371     DFX_TRACE_SCOPED("ReadRequestAndCheck");
372     ElapsedTime counter("ReadRequestAndCheck", 20); // 20 : limit cost time 20 ms
373     ssize_t readCount = OHOS_TEMP_FAILURE_RETRY(read(STDIN_FILENO, request.get(), sizeof(ProcessDumpRequest)));
374     request->threadName[NAME_BUF_LEN - 1] = '\0';
375     request->processName[NAME_BUF_LEN - 1] = '\0';
376     request->msg.body[MAX_FATAL_MSG_SIZE - 1] = '\0';
377     request->appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN - 1] = '\0';
378     if (readCount != static_cast<long>(sizeof(ProcessDumpRequest))) {
379         DFXLOGE("Failed to read DumpRequest(%{public}d), readCount(%{public}zd).", errno, readCount);
380         ReportCrashException(request->processName, request->pid, request->uid,
381                              CrashExceptionCode::CRASH_DUMP_EREADREQ);
382         return DumpErrorCode::DUMP_EREADREQUEST;
383     }
384 
385     return DumpErrorCode::DUMP_ESUCCESS;
386 }
387 
GetOpenFiles(int32_t pid, int nsPid, uint64_t fdTableAddr)388 std::string GetOpenFiles(int32_t pid, int nsPid, uint64_t fdTableAddr)
389 {
390     DFX_TRACE_SCOPED("GetOpenFiles");
391     OpenFilesList openFies;
392     CollectOpenFiles(openFies, pid);
393 #if !defined(__x86_64__)
394     FillFdsaninfo(openFies, nsPid, fdTableAddr);
395 #endif
396     std::string fds = DumpOpenFiles(openFies);
397     DFXLOGI("get open files info finish");
398     return fds;
399 }
400 
InitRegs(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes)401 void ProcessDumper::InitRegs(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes)
402 {
403     DFX_TRACE_SCOPED("InitRegs");
404     uint32_t opeResult = OPE_SUCCESS;
405     if (request->dumpMode == FUSION_MODE) {
406         if (!DfxUnwindRemote::GetInstance().InitProcessAllThreadRegs(request, process_)) {
407             DFXLOGE("Failed to init process regs.");
408             dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
409             opeResult = OPE_FAIL;
410         }
411 
412         InfoRemoteProcessResult(request, opeResult, MAIN_PROCESS);
413         DFXLOGI("get all tid regs finish");
414     }
415 }
416 
IsTargetProcessAlive(std::shared_ptr<ProcessDumpRequest> request)417 bool ProcessDumper::IsTargetProcessAlive(std::shared_ptr<ProcessDumpRequest> request)
418 {
419     if ((request->dumpMode == SPLIT_MODE) && ((!isCrash_ && (syscall(SYS_getppid) != request->nsPid)) ||
420         (isCrash_ && (syscall(SYS_getppid) != request->vmNsPid)))) {
421         DfxRingBufferWrapper::GetInstance().AppendMsg(
422             "Target process has been killed, the crash log may not be fully generated.");
423         ReportCrashException(request->processName, request->pid, request->uid,
424                              CrashExceptionCode::CRASH_DUMP_EKILLED);
425         return false;
426     }
427     return true;
428 }
429 
UnwindWriteJit(const ProcessDumpRequest &request)430 void ProcessDumper::UnwindWriteJit(const ProcessDumpRequest &request)
431 {
432     if (!isCrash_) {
433         return;
434     }
435 
436     const auto& jitCache = unwinder_->GetJitCache();
437     if (jitCache.empty()) {
438         return;
439     }
440     struct FaultLoggerdRequest jitRequest;
441     (void)memset_s(&jitRequest, sizeof(jitRequest), 0, sizeof(jitRequest));
442     jitRequest.type = FaultLoggerType::JIT_CODE_LOG;
443     jitRequest.pid = request.pid;
444     jitRequest.tid = request.tid;
445     jitRequest.uid = request.uid;
446     jitRequest.time = OHOS::HiviewDFX::GetTimeMilliSeconds();
447     int32_t fd = RequestFileDescriptorEx(&jitRequest);
448     if (fd == -1) {
449         DFXLOGE("request jitlog fd failed.");
450         return;
451     }
452     if (unwinder_->ArkWriteJitCodeToFile(fd) < 0) {
453         DFXLOGE("jit code write file failed.");
454     }
455     (void)close(fd);
456 }
457 
ReadStringByPtrace(pid_t tid, uintptr_t addr)458 std::string ProcessDumper::ReadStringByPtrace(pid_t tid, uintptr_t addr)
459 {
460     constexpr int bufLen = 256;
461     long buffer[bufLen] = {0};
462     for (int i = 0; i < bufLen - 1; i++) {
463         long ret = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr + sizeof(long) * i), nullptr);
464         if (ret == -1) {
465             DFXLOGE("read target mem by ptrace failed, errno(%{public}s).", strerror(errno));
466             break;
467         }
468         buffer[i] = ret;
469         if (ret == 0) {
470             break;
471         }
472     }
473     char* val = reinterpret_cast<char*>(buffer);
474     return std::string(val);
475 }
476 
GetCrashObj(std::shared_ptr<ProcessDumpRequest> request)477 void ProcessDumper::GetCrashObj(std::shared_ptr<ProcessDumpRequest> request)
478 {
479 #ifdef __LP64__
480     if (!isCrash_ || request->crashObj == 0) {
481         return;
482     }
483     uintptr_t type = request->crashObj >> 56; // 56 :: Move 56 bit to the right
484     uintptr_t addr = request->crashObj & 0xffffffffffffff;
485     switch (type) {
486         case 0: {
487             if (process_ != nullptr) {
488                 process_->SetFatalMessage(process_->GetFatalMessage() + ReadStringByPtrace(request->nsPid, addr));
489             }
490             break;
491         }
492         default:
493             break;
494     }
495 #endif
496 }
497 
Unwind(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes, pid_t vmPid)498 bool ProcessDumper::Unwind(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes, pid_t vmPid)
499 {
500     // dump unwind should still keep main thread or aim thread is frist unwind
501     if (!isCrash_) {
502         int tid = request->siginfo.si_value.sival_int;
503         tid = tid != 0 ? tid : request->nsPid;
504         for (auto &thread : process_->GetOtherThreads()) {
505             if (thread->threadInfo_.nsTid == tid) {
506                 swap(process_->keyThread_, thread);
507                 break;
508             }
509         }
510     }
511     GetCrashObj(request);
512     if (!DfxUnwindRemote::GetInstance().UnwindProcess(request, process_, unwinder_, vmPid)) {
513         DFXLOGE("Failed to unwind process.");
514         dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
515         return false;
516     }
517 
518     UnwindWriteJit(*request);
519     return true;
520 }
521 
DumpProcess(std::shared_ptr<ProcessDumpRequest> request)522 int ProcessDumper::DumpProcess(std::shared_ptr<ProcessDumpRequest> request)
523 {
524     DFX_TRACE_SCOPED("DumpProcess");
525     int dumpRes = DumpErrorCode::DUMP_ESUCCESS;
526     uint32_t opeResult = OPE_SUCCESS;
527     do {
528         if ((dumpRes = ReadRequestAndCheck(request)) != DumpErrorCode::DUMP_ESUCCESS) {
529             break;
530         }
531         SetProcessdumpTimeout(request->siginfo);
532         isCrash_ = request->siginfo.si_signo != SIGDUMP;
533         bool isLeakDump = request->siginfo.si_signo == SIGLEAK_STACK;
534         // We need check pid is same with getppid().
535         // As in signal handler, current process is a child process, and target pid is our parent process.
536         // If pid namespace is enabled, both ppid and pid are equal one.
537         // In this case, we have to parse /proc/self/status
538         if ((request->dumpMode == SPLIT_MODE) && (((!isCrash_) && (syscall(SYS_getppid) != request->nsPid)) ||
539             ((isCrash_ || isLeakDump) && (syscall(SYS_getppid) != request->vmNsPid)))) {
540             DFXLOGE("Target process(%{public}s:%{public}d) is not parent pid(%{public}ld), " \
541                 "exit processdump for signal(%{public}d).",
542                 request->processName, request->nsPid, syscall(SYS_getppid), request->siginfo.si_signo);
543             dumpRes = DumpErrorCode::DUMP_EGETPPID;
544             break;
545         }
546         DFXLOGW("Processdump SigVal(%{public}d), TargetPid(%{public}d:%{public}d), TargetTid(%{public}d), " \
547             "threadname(%{public}s).",
548             request->siginfo.si_value.sival_int, request->pid, request->nsPid, request->tid, request->threadName);
549 
550         if (InitProcessInfo(request) < 0) {
551             DFXLOGE("Failed to init crash process info.");
552             dumpRes = DumpErrorCode::DUMP_EATTACH;
553             break;
554         }
555         InitRegs(request, dumpRes);
556         pid_t vmPid = 0;
557         if (!InitUnwinder(request, vmPid, dumpRes) && (isCrash_ && !isLeakDump)) {
558             opeResult = OPE_FAIL;
559             break;
560         }
561         if (InitPrintThread(request) < 0) {
562             DFXLOGE("Failed to init print thread.");
563             dumpRes = DumpErrorCode::DUMP_EGETFD;
564         }
565         ReadFdTable(*request);
566         if (!Unwind(request, dumpRes, vmPid)) {
567             opeResult = OPE_FAIL;
568         }
569     } while (false);
570     if (request->dumpMode == FUSION_MODE) {
571         InfoRemoteProcessResult(request, opeResult, VIRTUAL_PROCESS);
572     }
573     if (dumpRes == DumpErrorCode::DUMP_ESUCCESS && !IsTargetProcessAlive(request)) {
574         dumpRes = DumpErrorCode::DUMP_EGETPPID;
575     }
576     return dumpRes;
577 }
578 
InitVmThread(std::shared_ptr<ProcessDumpRequest> request)579 bool ProcessDumper::InitVmThread(std::shared_ptr<ProcessDumpRequest> request)
580 {
581     if (request == nullptr || process_ == nullptr) {
582         return false;
583     }
584     if (isCrash_ && request->vmPid != 0) {
585         if (getppid() != request->vmNsPid) {
586             DFXLOGE("VM process(%{public}d) should be parent pid.", request->vmNsPid);
587             ReportCrashException(request->processName, request->pid, request->uid,
588                                  CrashExceptionCode::CRASH_DUMP_EPARENTPID);
589             return false;
590         }
591         process_->vmThread_ = DfxThread::Create(request->vmPid, request->vmPid, request->vmNsPid);
592         if ((process_->vmThread_ == nullptr) || (!process_->vmThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT))) {
593             DFXLOGE("Failed to attach vm thread(%{public}d).", request->vmNsPid);
594             return false;
595         }
596 
597         process_->vmThread_->SetThreadRegs(DfxRegs::CreateFromUcontext(request->context));
598         process_->vmThread_->threadInfo_.threadName = std::string(request->threadName);
599     }
600     return true;
601 }
602 
InitKeyThread(std::shared_ptr<ProcessDumpRequest> request)603 bool ProcessDumper::InitKeyThread(std::shared_ptr<ProcessDumpRequest> request)
604 {
605     if (request == nullptr || process_ == nullptr) {
606         return false;
607     }
608     pid_t nsTid = request->tid;
609     pid_t tid = process_->ChangeTid(nsTid, true);
610     process_->keyThread_ = DfxThread::Create(process_->processInfo_.pid, tid, nsTid);
611     if ((process_->keyThread_ == nullptr) || (!process_->keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT))) {
612         DFXLOGE("Failed to attach key thread(%{public}d).", nsTid);
613         ReportCrashException(request->processName, request->pid, request->uid,
614                              CrashExceptionCode::CRASH_DUMP_EATTACH);
615         if (!isCrash_) {
616             return false;
617         }
618     }
619     if ((process_->keyThread_ != nullptr) && request->dumpMode == FUSION_MODE) {
620         ptrace(PTRACE_CONT, process_->keyThread_->threadInfo_.nsTid, 0, 0);
621     }
622 
623     if ((process_->keyThread_ != nullptr) && (request->dumpMode == SPLIT_MODE) && !isCrash_) {
624         process_->keyThread_->SetThreadRegs(DfxRegs::CreateFromUcontext(request->context));
625     }
626 
627     if ((process_->keyThread_ != nullptr) && process_->keyThread_->threadInfo_.threadName.empty()) {
628         process_->keyThread_->threadInfo_.threadName = std::string(request->threadName);
629     }
630     return true;
631 }
632 
InitUnwinder(std::shared_ptr<ProcessDumpRequest> request, pid_t &vmPid, int &dumpRes)633 bool ProcessDumper::InitUnwinder(std::shared_ptr<ProcessDumpRequest> request, pid_t &vmPid, int &dumpRes)
634 {
635     DFX_TRACE_SCOPED("InitUnwinder");
636     pid_t realPid = 0;
637     if (request->dumpMode == FUSION_MODE) {
638         ReadPids(realPid, vmPid);
639         if (realPid == 0 || vmPid == 0) {
640             ReportCrashException(request->processName, request->pid, request->uid,
641                 CrashExceptionCode::CRASH_DUMP_EREADPID);
642             DFXLOGE("Failed to read real pid!");
643             dumpRes = DumpErrorCode::DUMP_EREADPID;
644             return false;
645         }
646     }
647 
648     // frezze detach after vm process create
649     if (!isCrash_) {
650         if (process_->keyThread_ != nullptr) {
651             process_->keyThread_->Detach();
652         }
653         process_->Detach();
654         DFXLOGI("ptrace detach all tids");
655     }
656 
657     if (request->dumpMode == FUSION_MODE) {
658         unwinder_ = std::make_shared<Unwinder>(realPid, vmPid, isCrash_);
659     } else {
660         if (isCrash_) {
661             unwinder_ = std::make_shared<Unwinder>(process_->vmThread_->threadInfo_.pid);
662         } else {
663             unwinder_ = std::make_shared<Unwinder>(process_->processInfo_.pid, false);
664         }
665     }
666     if (unwinder_ == nullptr) {
667         DFXLOGE("unwinder_ is nullptr!");
668         return false;
669     }
670     if (unwinder_->GetMaps() == nullptr) {
671         ReportCrashException(request->processName, request->pid, request->uid,
672             CrashExceptionCode::CRASH_LOG_EMAPLOS);
673         DFXLOGE("Mapinfo of crashed process is not exist!");
674         dumpRes = DumpErrorCode::DUMP_ENOMAP;
675         return false;
676     }
677     return true;
678 }
679 
InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)680 int ProcessDumper::InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)
681 {
682     DFX_TRACE_SCOPED("InitProcessInfo");
683     if (request->pid <= 0) {
684         return -1;
685     }
686     process_ = DfxProcess::Create(request->pid, request->nsPid);
687     if (process_ == nullptr) {
688         return -1;
689     }
690     if (process_->processInfo_.processName.empty()) {
691         process_->processInfo_.processName = std::string(request->processName);
692     }
693     process_->processInfo_.uid = request->uid;
694     process_->recycleTid_ = request->recycleTid;
695     process_->SetFatalMessage(request->msg.body);
696 
697     if (!InitVmThread(request)) {
698         return -1;
699     }
700 
701     if (!InitKeyThread(request)) {
702         return -1;
703     }
704 
705     DFXLOGI("ptrace attach all tids");
706     bool isLeakDump = request->siginfo.si_signo == SIGLEAK_STACK;
707     if (isCrash_ && !isLeakDump) {
708         process_->InitOtherThreads();
709         process_->Attach();
710     } else {
711         if (!isLeakDump) {
712             process_->InitOtherThreads();
713             if (request->dumpMode == FUSION_MODE) {
714                 process_->Attach();
715             }
716         }
717     }
718 #if defined(PROCESSDUMP_MINIDEBUGINFO)
719     UnwinderConfig::SetEnableMiniDebugInfo(true);
720     UnwinderConfig::SetEnableLoadSymbolLazily(true);
721 #endif
722     return 0;
723 }
724 
GetLogTypeByRequest(const ProcessDumpRequest &request)725 int ProcessDumper::GetLogTypeByRequest(const ProcessDumpRequest &request)
726 {
727     switch (request.siginfo.si_signo) {
728         case SIGLEAK_STACK:
729             switch (request.msg.type) {
730                 case MESSAGE_FDSAN_DEBUG:
731                     FALLTHROUGH_INTENDED;
732                 case MESSAGE_JEMALLOC:
733                     FALLTHROUGH_INTENDED;
734                 case MESSAGE_BADFD:
735                     return FaultLoggerType::CPP_STACKTRACE;
736                 default:
737                     return FaultLoggerType::LEAK_STACKTRACE;
738             }
739         case SIGDUMP:
740             return FaultLoggerType::CPP_STACKTRACE;
741         default:
742             return FaultLoggerType::CPP_CRASH;
743     }
744 }
745 
CreateFileForCrash(int32_t pid, uint64_t time) const746 int32_t ProcessDumper::CreateFileForCrash(int32_t pid, uint64_t time) const
747 {
748     const std::string logFilePath = "/log/crash";
749     const std::string logFileType = "cppcrash";
750     const int32_t logcrashFileProp = 0640; // 0640:-rw-r-----
751     if (access(logFilePath.c_str(), F_OK) != 0) {
752         DFXLOGE("%{public}s is not exist.", logFilePath.c_str());
753         return INVALID_FD;
754     }
755     std::string logPath = logFilePath + "/" + logFileType + "-" + std::to_string(pid) + "-" + std::to_string(time);
756     int32_t fd = OHOS_TEMP_FAILURE_RETRY(open(logPath.c_str(), O_RDWR | O_CREAT, logcrashFileProp));
757     if (fd == INVALID_FD) {
758         DFXLOGE("create %{public}s failed, errno=%{public}d", logPath.c_str(), errno);
759     } else {
760         DFXLOGI("create crash path %{public}s succ.", logPath.c_str());
761     }
762     return fd;
763 }
764 
InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)765 int ProcessDumper::InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)
766 {
767     DFX_TRACE_SCOPED("InitPrintThread");
768     int fd = -1;
769     struct FaultLoggerdRequest faultloggerdRequest;
770     (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest));
771     faultloggerdRequest.type = ProcessDumper::GetLogTypeByRequest(*request);
772     faultloggerdRequest.pid = request->pid;
773     faultloggerdRequest.tid = request->tid;
774     faultloggerdRequest.uid = request->uid;
775     faultloggerdRequest.time = request->timeStamp;
776     isJsonDump_ = false;
777     jsonFd_ = -1;
778     if (isCrash_ || faultloggerdRequest.type == FaultLoggerType::LEAK_STACKTRACE) {
779         fd = RequestFileDescriptorEx(&faultloggerdRequest);
780         if (fd == -1) {
781             fd = CreateFileForCrash(request->pid, request->timeStamp);
782         }
783         DfxRingBufferWrapper::GetInstance().SetWriteFunc(ProcessDumper::WriteDumpBuf);
784     } else {
785         jsonFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF);
786         if (jsonFd_ < 0) {
787             // If fd returns -1, we try to obtain the fd that needs to return JSON style
788             fd = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
789             resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_RES);
790             DFXLOGD("write buf fd: %{public}d, write res fd: %{public}d", fd, resFd_);
791         } else {
792             resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES);
793             DFXLOGD("write json fd: %{public}d, res fd: %{public}d", jsonFd_, resFd_);
794         }
795     }
796     if (jsonFd_ > 0) {
797         isJsonDump_ = true;
798     }
799     if ((fd < 0) && (jsonFd_ < 0)) {
800         DFXLOGW("Failed to request fd from faultloggerd.");
801         ReportCrashException(request->processName, request->pid, request->uid,
802                              CrashExceptionCode::CRASH_DUMP_EWRITEFD);
803     }
804     if (!isJsonDump_) {
805         DfxRingBufferWrapper::GetInstance().SetWriteBufFd(fd);
806     }
807     DfxRingBufferWrapper::GetInstance().StartThread();
808     return isJsonDump_ ? jsonFd_ : fd;
809 }
810 
WriteDumpBuf(int fd, const char* buf, const int len)811 int ProcessDumper::WriteDumpBuf(int fd, const char* buf, const int len)
812 {
813     if (buf == nullptr) {
814         return -1;
815     }
816     return WriteLog(fd, "%s", buf);
817 }
818 
WriteDumpRes(int32_t res)819 void ProcessDumper::WriteDumpRes(int32_t res)
820 {
821     DFXLOGI("%{public}s :: res: %{public}d", __func__, res);
822     if (resFd_ > 0) {
823         ssize_t nwrite = OHOS_TEMP_FAILURE_RETRY(write(resFd_, &res, sizeof(res)));
824         if (nwrite < 0) {
825             DFXLOGE("%{public}s write fail, err:%{public}d", __func__, errno);
826         }
827         close(resFd_);
828         resFd_ = -1;
829     } else {
830         if (res != DUMP_ESUCCESS) {
831             DfxRingBufferWrapper::GetInstance().AppendMsg("Result:\n");
832             DfxRingBufferWrapper::GetInstance().AppendMsg(DfxDumpRes::ToString(res) + "\n");
833         }
834     }
835 }
836 
IsCrash() const837 bool ProcessDumper::IsCrash() const
838 {
839     return isCrash_;
840 }
841 
ReportSigDumpStats(const std::shared_ptr<ProcessDumpRequest> &request) const842 void ProcessDumper::ReportSigDumpStats(const std::shared_ptr<ProcessDumpRequest> &request) const
843 {
844     if (isCrash_) {
845         return;
846     }
847 
848     std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0);
849     auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data());
850     stat->type = PROCESS_DUMP;
851     stat->pid = request->pid;
852     stat->signalTime = request->timeStamp;
853     stat->processdumpStartTime = startTime_;
854     stat->processdumpFinishTime = finishTime_;
855     if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess),
856         request->processName, sizeof(request->processName)) != 0) {
857         DFXLOGE("Failed to copy target processName (%{public}d)", errno);
858         return;
859     }
860 
861     ReportDumpStats(stat);
862 }
863 
ReportCrashInfo(const std::string& jsonInfo)864 void ProcessDumper::ReportCrashInfo(const std::string& jsonInfo)
865 {
866     if (reporter_ != nullptr) {
867         reporter_->SetCppCrashInfo(jsonInfo);
868         reporter_->ReportToHiview();
869         reporter_->ReportToAbilityManagerService();
870     }
871 }
872 
ReportAddrSanitizer(ProcessDumpRequest &request, std::string &jsonInfo)873 void ProcessDumper::ReportAddrSanitizer(ProcessDumpRequest &request, std::string &jsonInfo)
874 {
875 #ifndef HISYSEVENT_DISABLE
876     std::string fingerPrint = request.processName;
877     std::string reason = "DEBUG SIGNAL";
878     if (process_ != nullptr && process_->keyThread_ != nullptr) {
879         constexpr size_t MAX_FRAME_CNT = 3;
880         auto& frames = process_->keyThread_->GetFrames();
881         for (size_t index = 0, cnt = 0; cnt < MAX_FRAME_CNT && index < frames.size(); index++) {
882             if (frames[index].mapName.find("ld-musl-", 0) != std::string::npos) {
883                 continue;
884             }
885             fingerPrint = fingerPrint + frames[index].funcName;
886             cnt++;
887         }
888         reason = process_->reason;
889     }
890     size_t hashVal = std::hash<std::string>()(fingerPrint);
891     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "ADDR_SANITIZER",
892                     OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
893                     "MODULE", request.processName,
894                     "PID", request.pid,
895                     "HAPPEN_TIME", request.timeStamp,
896                     "REASON", reason,
897                     "FINGERPRINT", std::to_string(hashVal));
898     DFXLOGI("%{public}s", "Report fdsan event done.");
899 #else
900     DFXLOGI("%{public}s", "Not supported for fdsan reporting.");
901 #endif
902 }
903 
ReadFdTable(const ProcessDumpRequest &request)904 void ProcessDumper::ReadFdTable(const ProcessDumpRequest &request)
905 {
906     // Non crash, leak, jemalloc do not read fdtable
907     if (!isCrash_ ||
908         (request.siginfo.si_signo == SIGLEAK_STACK &&
909          (request.msg.type == NONE ||
910           request.msg.type == MESSAGE_FATAL ||
911           request.msg.type == MESSAGE_JEMALLOC))) {
912         return;
913     }
914     process_->openFiles = GetOpenFiles(request.pid, request.nsPid, request.fdTableAddr);
915     reporter_ = std::make_shared<CppCrashReporter>(request.timeStamp, process_, request.dumpMode);
916 }
917 } // namespace HiviewDFX
918 } // namespace OHOS
919