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
68namespace OHOS {
69namespace HiviewDFX {
70namespace {
71#undef LOG_DOMAIN
72#undef LOG_TAG
73#define LOG_DOMAIN 0xD002D11
74#define LOG_TAG "DfxProcessDump"
75const char *const BLOCK_CRASH_PROCESS = "faultloggerd.priv.block_crash_process.enabled";
76
77static 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
86void 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__)
102const int ARG_MAX_NUM = 131072;
103#endif
104using OpenFilesList = std::map<int, FDInfo>;
105
106bool 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
118void 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__)
146void 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
198std::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
215void 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
224void 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
245void 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
292ProcessDumper &ProcessDumper::GetInstance()
293{
294    static ProcessDumper ins;
295    return ins;
296}
297
298void 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
349void 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
369static 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
388std::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
401void 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
417bool 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
430void 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
458std::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
477void 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
498bool 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
522int 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
579bool 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
603bool 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
633bool 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
680int 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
725int 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
746int32_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
765int 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
811int 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
819void 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
837bool ProcessDumper::IsCrash() const
838{
839    return isCrash_;
840}
841
842void 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
864void ProcessDumper::ReportCrashInfo(const std::string& jsonInfo)
865{
866    if (reporter_ != nullptr) {
867        reporter_->SetCppCrashInfo(jsonInfo);
868        reporter_->ReportToHiview();
869        reporter_->ReportToAbilityManagerService();
870    }
871}
872
873void 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
904void 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