• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/wait.h>
37 #include <ucontext.h>
38 #include <unistd.h>
39 
40 #include "cppcrash_reporter.h"
41 #include "crash_exception.h"
42 #include "dfx_config.h"
43 #include "dfx_define.h"
44 #include "dfx_dump_request.h"
45 #include "dfx_dump_res.h"
46 #include "dfx_fdsan.h"
47 #include "dfx_logger.h"
48 #include "dfx_ptrace.h"
49 #include "dfx_process.h"
50 #include "dfx_regs.h"
51 #include "dfx_ring_buffer_wrapper.h"
52 #include "dfx_stack_info_json_formatter.h"
53 #include "dfx_thread.h"
54 #include "dfx_unwind_remote.h"
55 #include "dfx_util.h"
56 #include "dfx_trace.h"
57 #include "directory_ex.h"
58 #include "elapsed_time.h"
59 #include "faultloggerd_client.h"
60 #ifndef HISYSEVENT_DISABLE
61 #include "hisysevent.h"
62 #endif
63 #include "info/fatal_message.h"
64 #include "printer.h"
65 #include "procinfo.h"
66 #include "unwinder_config.h"
67 #ifndef is_ohos_lite
68 #include "parameters.h"
69 #endif // !is_ohos_lite
70 #include "info/fatal_message.h"
71 
72 namespace OHOS {
73 namespace HiviewDFX {
74 namespace {
75 #undef LOG_DOMAIN
76 #undef LOG_TAG
77 #define LOG_DOMAIN 0xD002D11
78 #define LOG_TAG "DfxProcessDump"
79 const char *const BLOCK_CRASH_PROCESS = "faultloggerd.priv.block_crash_process.enabled";
80 const char *const GLOBAL_REGION = "const.global.region";
81 const int MAX_FILE_COUNT = 5;
82 const int ARG_MAX_NUM = 131072;
83 
IsOversea()84 static bool IsOversea()
85 {
86 #ifndef is_ohos_lite
87     static bool isOversea = OHOS::system::GetParameter(GLOBAL_REGION, "CN") != "CN";
88     return isOversea;
89 #else
90     return false;
91 #endif
92 }
93 
IsBlockCrashProcess()94 static bool IsBlockCrashProcess()
95 {
96     bool isBlockCrash = false;
97 #ifndef is_ohos_lite
98     isBlockCrash = OHOS::system::GetParameter(BLOCK_CRASH_PROCESS, "false") == "true";
99 #endif
100     return isBlockCrash;
101 }
102 
WriteData(int fd,const std::string & data,size_t blockSize)103 void WriteData(int fd, const std::string& data, size_t blockSize)
104 {
105     size_t dataSize = data.length();
106     size_t index = 0;
107     while (index < dataSize) {
108         size_t writeLength = (index + blockSize) <= dataSize ? blockSize : (dataSize - index);
109         ssize_t nwrite = OHOS_TEMP_FAILURE_RETRY(write(fd, data.substr(index, writeLength).c_str(), writeLength));
110         if (nwrite != static_cast<ssize_t>(writeLength)) {
111             DFXLOGI("%{public}s :: nwrite: %{public}zd, writeLength: %{public}zu, errno:%{public}d", __func__, nwrite,
112                 writeLength, errno);
113         }
114         index += writeLength;
115     }
116     DFXLOGI("%{public}s :: needWriteDataSize: %{public}zu, writeDataSize: %{public}zu", __func__, dataSize, index);
117 }
118 
119 using OpenFilesList = std::map<int, FDInfo>;
120 
ReadLink(std::string & src,std::string & dst)121 bool ReadLink(std::string &src, std::string &dst)
122 {
123     char buf[PATH_MAX];
124     ssize_t count = readlink(src.c_str(), buf, sizeof(buf) - 1);
125     if (count < 0) {
126         return false;
127     }
128     buf[count] = '\0';
129     dst = buf;
130     return true;
131 }
132 
CollectOpenFiles(OpenFilesList & list,pid_t pid)133 void CollectOpenFiles(OpenFilesList &list, pid_t pid)
134 {
135     std::string fdDirName = "/proc/" + std::to_string(pid) + "/fd";
136     std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(fdDirName.c_str()), closedir);
137     if (dir == nullptr) {
138         DFXLOGE("failed to open directory %{public}s: %{public}s", fdDirName.c_str(), strerror(errno));
139         return;
140     }
141 
142     struct dirent *de;
143     while ((de = readdir(dir.get())) != nullptr) {
144         if (*de->d_name == '.') {
145             continue;
146         }
147 
148         int fd = atoi(de->d_name);
149         std::string path = fdDirName + "/" + std::string(de->d_name);
150         std::string target;
151         if (ReadLink(path, target)) {
152             list[fd].path = target;
153         } else {
154             list[fd].path = "???";
155             DFXLOGE("failed to readlink %{public}s: %{public}s", path.c_str(), strerror(errno));
156         }
157     }
158 }
159 
FillFdsaninfo(OpenFilesList & list,pid_t nsPid,uint64_t fdTableAddr)160 void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr)
161 {
162     constexpr size_t fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries);
163     size_t entryOffset = offsetof(FdTable, entries);
164     uint64_t addr = fdTableAddr + entryOffset;
165     FdEntry entrys[fds];
166     if (DfxMemory::ReadProcMemByPid(nsPid, addr, entrys, sizeof(FdEntry) * fds) != sizeof(FdEntry) * fds) {
167         DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno));
168         return;
169     }
170     for (size_t i = 0; i < fds; i++) {
171         if (entrys[i].close_tag) {
172             list[i].fdsanOwner = entrys[i].close_tag;
173         }
174     }
175 
176     size_t overflowOffset = offsetof(FdTable, overflow);
177     uintptr_t overflow = 0;
178     uint64_t tmp = fdTableAddr + overflowOffset;
179     if (DfxMemory::ReadProcMemByPid(nsPid, tmp, &overflow, sizeof(overflow)) != sizeof(overflow)) {
180         return;
181     }
182     if (!overflow) {
183         return;
184     }
185 
186     size_t overflowLength;
187     if (DfxMemory::ReadProcMemByPid(nsPid, overflow, &overflowLength, sizeof(overflowLength))
188         != sizeof(overflowLength)) {
189         return;
190     }
191     if (overflowLength > ARG_MAX_NUM) {
192         return;
193     }
194 
195     std::vector<FdEntry> overflowFdEntrys(overflowLength);
196     uint64_t address = overflow + offsetof(FdTableOverflow, entries);
197     if (DfxMemory::ReadProcMemByPid(nsPid, address, overflowFdEntrys.data(), sizeof(FdEntry) * overflowLength) !=
198         sizeof(FdEntry) * overflowLength) {
199         DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno));
200         return;
201     }
202     size_t fdIndex = fds;
203     for (size_t i = 0; i < overflowLength; i++) {
204         if (overflowFdEntrys[i].close_tag) {
205             list[fdIndex].fdsanOwner = overflowFdEntrys[i].close_tag;
206         }
207         fdIndex++;
208     }
209 }
210 
DumpOpenFiles(OpenFilesList & files)211 std::string DumpOpenFiles(OpenFilesList &files)
212 {
213     std::string openFiles = "OpenFiles:\n";
214     for (auto &filePath: files) {
215         const std::string path = filePath.second.path;
216         uint64_t tag = filePath.second.fdsanOwner;
217         const char* type = fdsan_get_tag_type(tag);
218         uint64_t val = fdsan_get_tag_value(tag);
219         if (!path.empty()) {
220             openFiles += std::to_string(filePath.first) + "->" + path + " " + type + " " +
221                 std::to_string(val) + "\n";
222         } else {
223             openFiles += "OpenFilesList contain an entry (fd " +
224                 std::to_string(filePath.first) + ") with no path or owner\n";
225         }
226     }
227     return openFiles;
228 }
229 
WaitForFork(unsigned long pid,unsigned long & childPid)230 void WaitForFork(unsigned long pid, unsigned long& childPid)
231 {
232     DFXLOGI("start wait fork event happen");
233     int waitStatus = 0;
234     waitpid(pid, &waitStatus, 0); // wait fork event
235     DFXLOGI("wait for fork status %{public}d", waitStatus);
236     if (static_cast<unsigned int>(waitStatus) >> 8 == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) { // 8 : get fork event
237         ptrace(PTRACE_GETEVENTMSG, pid, NULL, &childPid);
238         DFXLOGI("next child pid %{public}lu", childPid);
239         waitpid(childPid, &waitStatus, 0); // wait child stop event
240     }
241 }
242 
ReadVmRealPid(std::shared_ptr<ProcessDumpRequest> request,unsigned long vmPid,int & realPid)243 void ReadVmRealPid(std::shared_ptr<ProcessDumpRequest> request, unsigned long vmPid, int& realPid)
244 {
245     int waitStatus = 0;
246     ptrace(PTRACE_SETOPTIONS, vmPid, NULL, PTRACE_O_TRACEEXIT); // block son exit
247     ptrace(PTRACE_CONT, vmPid, NULL, NULL);
248 
249     long data = 0;
250     DFXLOGI("start wait exit event happen");
251     waitpid(vmPid, &waitStatus, 0); // wait exit stop
252     data = ptrace(PTRACE_PEEKDATA, vmPid, reinterpret_cast<void *>(request->vmProcRealPidAddr), nullptr);
253     if (data < 0) {
254         DFXLOGI("ptrace peek data error %{public}lu %{public}d", vmPid, errno);
255     }
256     realPid = static_cast<int>(data);
257 }
258 
ReadPids(std::shared_ptr<ProcessDumpRequest> request,int & realPid,int & vmPid,std::shared_ptr<DfxProcess> proc)259 void ReadPids(std::shared_ptr<ProcessDumpRequest> request, int& realPid, int& vmPid, std::shared_ptr<DfxProcess> proc)
260 {
261     unsigned long childPid = 0;
262 
263     WaitForFork(request->tid, childPid);
264     ptrace(PTRACE_CONT, childPid, NULL, NULL);
265 
266     // frezze detach after fork child to fork vm process
267     if (request->siginfo.si_signo == SIGDUMP) {
268         if (proc->keyThread_ != nullptr) {
269             proc->keyThread_->Detach();
270         }
271         proc->Detach();
272         DFXLOGI("ptrace detach all tids");
273     }
274 
275     unsigned long sonPid = 0;
276     WaitForFork(childPid, sonPid);
277     vmPid = static_cast<int>(sonPid);
278 
279     ptrace(PTRACE_DETACH, childPid, 0, 0);
280     ReadVmRealPid(request, sonPid, realPid);
281 
282     DFXLOGI("procecdump get real pid is %{public}d vm pid is %{public}d", realPid, vmPid);
283 }
284 
InfoRemoteProcessResult(std::shared_ptr<ProcessDumpRequest> request,int result)285 void InfoRemoteProcessResult(std::shared_ptr<ProcessDumpRequest> request, int result)
286 {
287     if (request == nullptr) {
288         return;
289     }
290     if (request->childPipeFd[0] != -1) {
291         close(request->childPipeFd[0]);
292         request->childPipeFd[0] = -1;
293     }
294     if (OHOS_TEMP_FAILURE_RETRY(write(request->childPipeFd[1], &result, sizeof(result))) < 0) {
295         DFXLOGE("write to child process fail %{public}d", errno);
296     }
297 }
298 
SetProcessdumpTimeout(siginfo_t & si)299 void SetProcessdumpTimeout(siginfo_t &si)
300 {
301     if (si.si_signo != SIGDUMP) {
302         return;
303     }
304 
305     uint64_t endTime;
306     int tid;
307     ParseSiValue(si, endTime, tid);
308 
309     if (tid == 0) {
310         DFXLOGI("reset, prevent incorrect reading sival_int for tid");
311         si.si_value.sival_int = 0;
312     }
313 
314     if (endTime == 0) {
315         DFXLOGI("end time is zero, not set new alarm");
316         return;
317     }
318 
319     uint64_t curTime = GetAbsTimeMilliSeconds();
320     if (curTime >= endTime) {
321         DFXLOGI("now has timeout, processdump exit");
322 #ifndef CLANG_COVERAGE
323         _exit(0);
324 #endif
325     }
326     uint64_t diffTime = endTime - curTime;
327 
328     DFXLOGI("processdump remain time%{public}" PRIu64 "ms", diffTime);
329     if (diffTime > PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
330         DFXLOGE("dump remain time is invalid, not set timer");
331         return;
332     }
333 
334     struct itimerval timer;
335     timer.it_value.tv_sec = static_cast<int64_t>(diffTime / NUMBER_ONE_THOUSAND);
336     timer.it_value.tv_usec = static_cast<int64_t>(diffTime * NUMBER_ONE_THOUSAND % NUMBER_ONE_MILLION);
337     timer.it_interval.tv_sec = 0;
338     timer.it_interval.tv_usec = 0;
339 
340     if (setitimer(ITIMER_REAL, &timer, nullptr) != 0) {
341         DFXLOGE("start processdump timer fail %{public}d", errno);
342     }
343 }
344 
IsDebugSignal(const siginfo_t & siginfo)345 static bool IsDebugSignal(const siginfo_t& siginfo)
346 {
347     if (siginfo.si_signo != SIGLEAK_STACK) {
348         return false;
349     }
350 
351     switch (siginfo.si_code) {
352         case SIGLEAK_STACK_FDSAN:
353             FALLTHROUGH_INTENDED;
354         case SIGLEAK_STACK_JEMALLOC:
355             FALLTHROUGH_INTENDED;
356         case SIGLEAK_STACK_BADFD:
357             return true;
358         default:
359             return false;
360     }
361 }
362 
InfoCrashUnwindResult(const std::shared_ptr<ProcessDumpRequest> request,bool isUnwindSucc)363 void InfoCrashUnwindResult(const std::shared_ptr<ProcessDumpRequest> request, bool isUnwindSucc)
364 {
365     if (!isUnwindSucc) {
366         return;
367     }
368     if (ptrace(PTRACE_POKEDATA, request->nsPid, reinterpret_cast<void*>(request->unwindResultAddr),
369         CRASH_UNWIND_SUCCESS_FLAG) < 0) {
370         DFXLOGE("pok unwind success flag to nsPid %{public}d fail %{public}s", request->nsPid, strerror(errno));
371     }
372 }
373 
BlockCrashProcExit(const std::shared_ptr<ProcessDumpRequest> request)374 void BlockCrashProcExit(const std::shared_ptr<ProcessDumpRequest> request)
375 {
376     if (!IsBlockCrashProcess()) {
377         return;
378     }
379     DFXLOGI("start block crash process pid %{public}d nspid %{public}d", request->pid, request->nsPid);
380     if (ptrace(PTRACE_POKEDATA, request->nsPid, reinterpret_cast<void*>(request->blockCrashExitAddr),
381         CRASH_BLOCK_EXIT_FLAG) < 0) {
382         DFXLOGE("pok block falg to nsPid %{public}d fail %{public}s", request->nsPid, strerror(errno));
383     }
384 }
385 
IsDumpSignal(int signo)386 bool IsDumpSignal(int signo)
387 {
388     return signo == SIGDUMP || signo == SIGLEAK_STACK;
389 }
390 
IsLeakDumpSignal(int signo)391 bool IsLeakDumpSignal(int signo)
392 {
393     return signo == SIGLEAK_STACK;
394 }
395 }
396 
GetInstance()397 ProcessDumper &ProcessDumper::GetInstance()
398 {
399     static ProcessDumper ins;
400     return ins;
401 }
402 
Dump()403 void ProcessDumper::Dump()
404 {
405     startTime_ = GetTimeMillisec();
406     std::shared_ptr<ProcessDumpRequest> request = std::make_shared<ProcessDumpRequest>();
407     resDump_ = DumpProcess(request);
408 
409     std::string jsonInfo;
410     if (isJsonDump_ || isCrash_) {
411         DfxStackInfoJsonFormatter formatter(process_, request);
412         formatter.GetJsonFormatInfo(isJsonDump_, jsonInfo);
413         DFXLOGI("Finish GetJsonFormatInfo len %{public}" PRIuPTR "", jsonInfo.length());
414         if (isJsonDump_) {
415             WriteData(bufferFd_, jsonInfo, MAX_PIPE_SIZE);
416             CloseFd(bufferFd_);
417         }
418     }
419 
420     finishTime_ = GetTimeMillisec();
421     ReportSigDumpStats(request);
422 
423     if (request->siginfo.si_signo == SIGDUMP) {
424         WriteDumpRes(resDump_, request->pid);
425         CloseFd(resFd_);
426     }
427 
428     // print keythread base info to hilog
429     DfxRingBufferWrapper::GetInstance().PrintBaseInfo();
430     DfxRingBufferWrapper::GetInstance().StopThread();
431     DFXLOGI("Finish dump stacktrace for %{public}s(%{public}d:%{public}d).",
432         request->processName, request->pid, request->tid);
433     Report(request, jsonInfo);
434 
435     if (!IsDumpSignal(request->siginfo.si_signo)) {
436         InfoCrashUnwindResult(request, resDump_ == DumpErrorCode::DUMP_ESUCCESS);
437         BlockCrashProcExit(request);
438     }
439     if (process_ != nullptr) {
440         if (process_->keyThread_ != nullptr) {
441             process_->keyThread_->Detach();
442         }
443         process_->Detach();
444     }
445 }
446 
Report(std::shared_ptr<ProcessDumpRequest> request,std::string & jsonInfo)447 void ProcessDumper::Report(std::shared_ptr<ProcessDumpRequest> request, std::string &jsonInfo)
448 {
449     if (request == nullptr) {
450         DFXLOGE("request is nullptr.");
451         return;
452     }
453     if (resDump_ == DumpErrorCode::DUMP_ENOMAP || resDump_ == DumpErrorCode::DUMP_EREADPID) {
454         DFXLOGE("resDump_ is %{public}d.", resDump_);
455         return;
456     }
457     if (IsDebugSignal(request->siginfo)) {
458         ReportAddrSanitizer(*request, jsonInfo);
459         return;
460     }
461     if (isCrash_ && request->siginfo.si_signo != SIGLEAK_STACK) {
462         ReportCrashInfo(jsonInfo, *request);
463     }
464 }
465 
ReadRequestAndCheck(std::shared_ptr<ProcessDumpRequest> request)466 static int32_t ReadRequestAndCheck(std::shared_ptr<ProcessDumpRequest> request)
467 {
468     DFX_TRACE_SCOPED("ReadRequestAndCheck");
469     ElapsedTime counter("ReadRequestAndCheck", 20); // 20 : limit cost time 20 ms
470     ssize_t readCount = OHOS_TEMP_FAILURE_RETRY(read(STDIN_FILENO, request.get(), sizeof(ProcessDumpRequest)));
471     request->threadName[NAME_BUF_LEN - 1] = '\0';
472     request->processName[NAME_BUF_LEN - 1] = '\0';
473     request->msg.body[MAX_FATAL_MSG_SIZE - 1] = '\0';
474     request->appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN - 1] = '\0';
475     if (readCount != static_cast<long>(sizeof(ProcessDumpRequest))) {
476         DFXLOGE("Failed to read DumpRequest(%{public}d), readCount(%{public}zd).", errno, readCount);
477         ReportCrashException(request->processName, request->pid, request->uid,
478                              CrashExceptionCode::CRASH_DUMP_EREADREQ);
479         return DumpErrorCode::DUMP_EREADREQUEST;
480     }
481 
482     return DumpErrorCode::DUMP_ESUCCESS;
483 }
484 
GetOpenFiles(int32_t pid,int nsPid,uint64_t fdTableAddr)485 std::string GetOpenFiles(int32_t pid, int nsPid, uint64_t fdTableAddr)
486 {
487     DFX_TRACE_SCOPED("GetOpenFiles");
488     OpenFilesList openFies;
489     CollectOpenFiles(openFies, pid);
490     FillFdsaninfo(openFies, nsPid, fdTableAddr);
491     std::string fds = DumpOpenFiles(openFies);
492     DFXLOGI("get open files info finish");
493     return fds;
494 }
495 
InitRegs(std::shared_ptr<ProcessDumpRequest> request,int & dumpRes)496 void ProcessDumper::InitRegs(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes)
497 {
498     DFX_TRACE_SCOPED("InitRegs");
499     if (!DfxUnwindRemote::GetInstance().InitProcessAllThreadRegs(request, process_)) {
500         DFXLOGE("Failed to init process regs.");
501         dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
502         return;
503     }
504 
505     DFXLOGI("get all tid regs finish");
506 }
507 
UnwindWriteJit(const ProcessDumpRequest & request)508 void ProcessDumper::UnwindWriteJit(const ProcessDumpRequest &request)
509 {
510     if (!isCrash_ || !unwinder_) {
511         return;
512     }
513 
514     const auto& jitCache = unwinder_->GetJitCache();
515     if (jitCache.empty()) {
516         return;
517     }
518     struct FaultLoggerdRequest jitRequest;
519     (void)memset_s(&jitRequest, sizeof(jitRequest), 0, sizeof(jitRequest));
520     jitRequest.type = FaultLoggerType::JIT_CODE_LOG;
521     jitRequest.pid = request.pid;
522     jitRequest.tid = request.tid;
523     jitRequest.time = request.timeStamp;
524     int32_t fd = RequestFileDescriptorEx(&jitRequest);
525     if (fd == -1) {
526         DFXLOGE("request jitlog fd failed.");
527         return;
528     }
529     if (unwinder_->ArkWriteJitCodeToFile(fd) < 0) {
530         DFXLOGE("jit code write file failed.");
531     }
532     (void)close(fd);
533 }
534 
ReadStringByPtrace(pid_t tid,uintptr_t addr,size_t maxLen)535 std::string ProcessDumper::ReadStringByPtrace(pid_t tid, uintptr_t addr, size_t maxLen)
536 {
537     constexpr size_t maxReadLen = 1024 * 1024 * 1; // 1M
538     if (maxLen == 0 || maxLen > maxReadLen) {
539         DFXLOGE("maxLen(%{public}zu) is invalid value.", maxLen);
540         return "";
541     }
542     size_t bufLen = (maxLen + sizeof(long) - 1) / sizeof(long);
543     std::vector<long> buffer(bufLen, 0);
544     for (size_t i = 0; i < bufLen; i++) {
545         long ret = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr + sizeof(long) * i), nullptr);
546         if (ret == -1) {
547             DFXLOGE("read target mem by ptrace failed, errno(%{public}s).", strerror(errno));
548             break;
549         }
550         buffer[i] = ret;
551         if (ret == 0) {
552             break;
553         }
554     }
555     char* val = reinterpret_cast<char*>(buffer.data());
556     val[maxLen - 1] = '\0';
557     return std::string(val);
558 }
559 
UpdateFatalMessageWhenDebugSignal(const ProcessDumpRequest & request,pid_t vmPid)560 void ProcessDumper::UpdateFatalMessageWhenDebugSignal(const ProcessDumpRequest& request, pid_t vmPid)
561 {
562     pid_t pid = vmPid != 0 ? vmPid : request.nsPid;
563     if (request.siginfo.si_signo != SIGLEAK_STACK ||
564         !(request.siginfo.si_code == SIGLEAK_STACK_FDSAN || request.siginfo.si_code == SIGLEAK_STACK_JEMALLOC)) {
565         return;
566     }
567 
568     if (pid == 0 || process_ == nullptr) {
569         DFXLOGE("pid %{public}d, process_ is %{public}s nullptr.", pid, process_ == nullptr ? "" : "not");
570         return;
571     }
572 
573     auto debugMsgPtr = reinterpret_cast<uintptr_t>(request.siginfo.si_value.sival_ptr);
574     debug_msg_t dMsg = {0};
575     if (DfxMemory::ReadProcMemByPid(pid, debugMsgPtr, &dMsg, sizeof(dMsg)) != sizeof(debug_msg_t)) {
576         DFXLOGE("Get debug_msg_t failed.");
577         return;
578     }
579     auto msgPtr = reinterpret_cast<uintptr_t>(dMsg.msg);
580     auto lastMsg = ReadStringByPtrace(pid, msgPtr, MAX_FATAL_MSG_SIZE);
581     if (lastMsg.empty()) {
582         DFXLOGE("Get debug_msg_t.msg failed.");
583         return;
584     }
585     process_->SetFatalMessage(lastMsg);
586 }
587 
ReadCrashObjString(pid_t tid,uintptr_t addr) const588 std::string ProcessDumper::ReadCrashObjString(pid_t tid, uintptr_t addr) const
589 {
590     DFXLOGI("Start read string type of crashObj.");
591     constexpr int bufLen = 256;
592     std::string stringContent = ReadStringByPtrace(tid, addr, sizeof(long) * bufLen);
593     return stringContent;
594 }
595 
ReadCrashObjMemory(pid_t tid,uintptr_t addr,size_t length) const596 std::string ProcessDumper::ReadCrashObjMemory(pid_t tid, uintptr_t addr, size_t length) const
597 {
598     DFXLOGI("Start read memory type of crashObj, memory length(%zu).", length);
599     constexpr size_t step = sizeof(uintptr_t);
600     std::string memoryContent = StringPrintf("ExtraCrashInfo(Memory start address %018" PRIx64 "):",
601         static_cast<uint64_t>(addr));
602     size_t size = (length + step - 1) / step;
603     std::vector<uintptr_t> memory(size, 0);
604     if (DfxMemory::ReadProcMemByPid(tid, addr, memory.data(), length) != length) {
605         DFXLOGE("[%{public}d]: read target mem error %{public}s", __LINE__, strerror(errno));
606         memoryContent += "\n";
607         return memoryContent;
608     }
609     for (size_t index = 0; index < size; index++) {
610         size_t offset = index * step;
611         if (offset % 0x20 == 0) {  // Print offset every 32 bytes
612             memoryContent += StringPrintf("\n+0x%03" PRIx64 ":", static_cast<uint64_t>(offset));
613         }
614         memoryContent += StringPrintf(" %018" PRIx64, static_cast<uint64_t>(memory[index]));
615     }
616     memoryContent += "\n";
617     return memoryContent;
618 }
619 
GetCrashObj(std::shared_ptr<ProcessDumpRequest> request)620 void ProcessDumper::GetCrashObj(std::shared_ptr<ProcessDumpRequest> request)
621 {
622 #ifdef __LP64__
623     if (!isCrash_ || request->crashObj == 0 || process_ == nullptr) {
624         return;
625     }
626     uintptr_t type = request->crashObj >> 56; // 56 :: Move 56 bit to the right
627     uintptr_t addr = request->crashObj & 0xffffffffffffff;
628     std::vector<size_t> memorylengthTable = {0, 64, 256, 1024, 2048, 4096};
629     if (type == 0) {
630         process_->SetFatalMessage(ReadCrashObjString(request->nsPid, addr));
631     } else if (type < memorylengthTable.size()) {
632         process_->extraCrashInfo += ReadCrashObjMemory(request->nsPid, addr, memorylengthTable[type]);
633     }
634 #endif
635 }
636 
Unwind(std::shared_ptr<ProcessDumpRequest> request,int & dumpRes,pid_t vmPid)637 bool ProcessDumper::Unwind(std::shared_ptr<ProcessDumpRequest> request, int &dumpRes, pid_t vmPid)
638 {
639     // dump unwind should still keep main thread or aim thread is frist unwind
640     if (!isCrash_) {
641         int tid = request->siginfo.si_value.sival_int;
642         tid = tid != 0 ? tid : request->nsPid;
643         for (auto &thread : process_->GetOtherThreads()) {
644             if (thread->threadInfo_.nsTid == tid) {
645                 swap(process_->keyThread_, thread);
646                 break;
647             }
648         }
649     }
650     GetCrashObj(request);
651     UpdateFatalMessageWhenDebugSignal(*request, vmPid);
652 
653     if (!DfxUnwindRemote::GetInstance().UnwindProcess(request, process_, unwinder_, vmPid)) {
654         DFXLOGE("Failed to unwind process.");
655         dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
656         return false;
657     }
658     return true;
659 }
660 
UnwindFinish(std::shared_ptr<ProcessDumpRequest> request,pid_t vmPid)661 void ProcessDumper::UnwindFinish(std::shared_ptr<ProcessDumpRequest> request, pid_t vmPid)
662 {
663     if (process_ == nullptr) {
664         DFXLOGE("Dump process failed, please check permission and whether pid is valid.");
665         return;
666     }
667 
668     DfxUnwindRemote::GetInstance().ParseSymbol(request, process_, unwinder_);
669     DfxUnwindRemote::GetInstance().PrintUnwindResultInfo(request, process_, unwinder_, vmPid);
670     UnwindWriteJit(*request);
671 }
672 
DumpProcess(std::shared_ptr<ProcessDumpRequest> request)673 int ProcessDumper::DumpProcess(std::shared_ptr<ProcessDumpRequest> request)
674 {
675     DFX_TRACE_SCOPED("DumpProcess");
676     int dumpRes = DumpErrorCode::DUMP_ESUCCESS;
677     do {
678         if ((dumpRes = ReadRequestAndCheck(request)) != DumpErrorCode::DUMP_ESUCCESS) {
679             break;
680         }
681         SetProcessdumpTimeout(request->siginfo);
682         isCrash_ = request->siginfo.si_signo != SIGDUMP;
683         DFXLOGI("Processdump SigVal(%{public}d), TargetPid(%{public}d:%{public}d), TargetTid(%{public}d), " \
684             "threadname(%{public}s).",
685             request->siginfo.si_value.sival_int, request->pid, request->nsPid, request->tid, request->threadName);
686 
687         if (InitProcessInfo(request) < 0) {
688             DFXLOGE("Failed to init crash process info.");
689             dumpRes = DumpErrorCode::DUMP_EATTACH;
690             break;
691         }
692         InitRegs(request, dumpRes);
693         pid_t vmPid = 0;
694         if (!InitUnwinder(request, vmPid, dumpRes) && (isCrash_ && !IsLeakDumpSignal(request->siginfo.si_signo))) {
695             break;
696         }
697         if (InitPrintThread(request) < 0) {
698             DFXLOGE("Failed to init print thread.");
699             dumpRes = DumpErrorCode::DUMP_EGETFD;
700         }
701         ReadFdTable(*request);
702         if (!Unwind(request, dumpRes, vmPid)) {
703             DFXLOGE("unwind fail.");
704         }
705         UnwindFinish(request, vmPid);
706         DfxPtrace::Detach(vmPid);
707     } while (false);
708     return dumpRes;
709 }
710 
InitKeyThread(std::shared_ptr<ProcessDumpRequest> request)711 bool ProcessDumper::InitKeyThread(std::shared_ptr<ProcessDumpRequest> request)
712 {
713     if (request == nullptr || process_ == nullptr) {
714         return false;
715     }
716     pid_t nsTid = request->tid;
717     pid_t tid = process_->ChangeTid(nsTid, true);
718     process_->keyThread_ = DfxThread::Create(process_->processInfo_.pid, tid, nsTid);
719     if ((process_->keyThread_ == nullptr) || (!process_->keyThread_->Attach(PTRACE_ATTATCH_KEY_THREAD_TIMEOUT))) {
720         DFXLOGE("Failed to attach key thread(%{public}d).", nsTid);
721         ReportCrashException(request->processName, request->pid, request->uid,
722                              CrashExceptionCode::CRASH_DUMP_EATTACH);
723         if (!isCrash_) {
724             return false;
725         }
726     }
727     if (process_->keyThread_ != nullptr) {
728         InfoRemoteProcessResult(request, OPE_SUCCESS);
729         ptrace(PTRACE_SETOPTIONS, process_->keyThread_->threadInfo_.nsTid, NULL, PTRACE_O_TRACEFORK);
730         ptrace(PTRACE_CONT, process_->keyThread_->threadInfo_.nsTid, 0, 0);
731     }
732 
733     if ((process_->keyThread_ != nullptr) && process_->keyThread_->threadInfo_.threadName.empty()) {
734         process_->keyThread_->threadInfo_.threadName = std::string(request->threadName);
735     }
736     return true;
737 }
738 
InitUnwinder(std::shared_ptr<ProcessDumpRequest> request,pid_t & vmPid,int & dumpRes)739 bool ProcessDumper::InitUnwinder(std::shared_ptr<ProcessDumpRequest> request, pid_t &vmPid, int &dumpRes)
740 {
741     DFX_TRACE_SCOPED("InitUnwinder");
742     pid_t realPid = 0;
743     ReadPids(request, realPid, vmPid, process_);
744     if (realPid == 0 || vmPid == 0) {
745         ReportCrashException(request->processName, request->pid, request->uid,
746             CrashExceptionCode::CRASH_DUMP_EREADPID);
747         DFXLOGE("Failed to read real pid!");
748         dumpRes = DumpErrorCode::DUMP_EREADPID;
749         return false;
750     }
751 
752     unwinder_ = std::make_shared<Unwinder>(realPid, vmPid, isCrash_);
753     if (unwinder_ == nullptr) {
754         DFXLOGE("unwinder_ is nullptr!");
755         return false;
756     }
757     if (unwinder_->GetMaps() == nullptr) {
758         ReportCrashException(request->processName, request->pid, request->uid,
759             CrashExceptionCode::CRASH_LOG_EMAPLOS);
760         DFXLOGE("Mapinfo of crashed process is not exist!");
761         dumpRes = DumpErrorCode::DUMP_ENOMAP;
762         return false;
763     }
764     return true;
765 }
766 
InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)767 int ProcessDumper::InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)
768 {
769     DFX_TRACE_SCOPED("InitProcessInfo");
770     if (request->pid <= 0) {
771         return -1;
772     }
773     process_ = DfxProcess::Create(request->pid, request->nsPid);
774     if (process_ == nullptr) {
775         return -1;
776     }
777     if (process_->processInfo_.processName.empty()) {
778         process_->processInfo_.processName = std::string(request->processName);
779     }
780     process_->processInfo_.uid = request->uid;
781     process_->recycleTid_ = request->recycleTid;
782     if (request->msg.type == MESSAGE_FATAL || request->msg.type == MESSAGE_CALLBACK) {
783         if (!IsOversea() || IsBetaVersion() || IsDeveloperMode()) {
784             process_->SetFatalMessage(request->msg.body);
785         }
786     }
787 
788     if (!InitKeyThread(request)) {
789         return -1;
790     }
791 
792     DFXLOGI("ptrace attach all tids");
793     if (!IsLeakDumpSignal(request->siginfo.si_signo)) {
794         process_->InitOtherThreads();
795         process_->Attach();
796     }
797 #if defined(PROCESSDUMP_MINIDEBUGINFO)
798     UnwinderConfig::SetEnableMiniDebugInfo(true);
799     UnwinderConfig::SetEnableLoadSymbolLazily(true);
800 #endif
801     return 0;
802 }
803 
GetLogTypeByRequest(const ProcessDumpRequest & request)804 int ProcessDumper::GetLogTypeByRequest(const ProcessDumpRequest &request)
805 {
806     switch (request.siginfo.si_signo) {
807         case SIGLEAK_STACK:
808             switch (request.siginfo.si_code) {
809                 case SIGLEAK_STACK_FDSAN:
810                     FALLTHROUGH_INTENDED;
811                 case SIGLEAK_STACK_JEMALLOC:
812                     FALLTHROUGH_INTENDED;
813                 case SIGLEAK_STACK_BADFD:
814                     return FaultLoggerType::CPP_STACKTRACE;
815                 default:
816                     return FaultLoggerType::LEAK_STACKTRACE;
817             }
818         case SIGDUMP:
819             return FaultLoggerType::CPP_STACKTRACE;
820         default:
821             return FaultLoggerType::CPP_CRASH;
822     }
823 }
824 
CreateFileForCrash(int32_t pid,uint64_t time) const825 int32_t ProcessDumper::CreateFileForCrash(int32_t pid, uint64_t time) const
826 {
827     const std::string logFilePath = "/log/crash";
828     const std::string logFileType = "cppcrash";
829     const int32_t logcrashFileProp = 0644; // 0640:-rw-r--r--
830     if (access(logFilePath.c_str(), F_OK) != 0) {
831         DFXLOGE("%{public}s is not exist.", logFilePath.c_str());
832         return INVALID_FD;
833     }
834     std::string logPath = logFilePath + "/" + logFileType + "-" + std::to_string(pid) + "-" + std::to_string(time);
835     int32_t fd = OHOS_TEMP_FAILURE_RETRY(open(logPath.c_str(), O_RDWR | O_CREAT, logcrashFileProp));
836     if (fd == INVALID_FD) {
837         DFXLOGE("create %{public}s failed, errno=%{public}d", logPath.c_str(), errno);
838     } else {
839         DFXLOGI("create crash path %{public}s succ.", logPath.c_str());
840     }
841     return fd;
842 }
843 
RemoveFileIfNeed()844 void ProcessDumper::RemoveFileIfNeed()
845 {
846     const std::string logFilePath = "/log/crash";
847     std::vector<std::string> files;
848     OHOS::GetDirFiles(logFilePath, files);
849     if (files.size() < MAX_FILE_COUNT) {
850         return;
851     }
852 
853     std::sort(files.begin(), files.end(),
854         [](const std::string& lhs, const std::string& rhs) {
855         auto lhsSplitPos = lhs.find_last_of("-");
856         auto rhsSplitPos = rhs.find_last_of("-");
857         if (lhsSplitPos == std::string::npos || rhsSplitPos == std::string::npos) {
858             return lhs.compare(rhs) < 0;
859         }
860         return lhs.substr(lhsSplitPos).compare(rhs.substr(rhsSplitPos)) < 0;
861     });
862 
863     int deleteNum = static_cast<int>(files.size()) - (MAX_FILE_COUNT - 1);
864     for (int index = 0; index < deleteNum; index++) {
865         DFXLOGI("Now we delete file(%{public}s) due to exceed file max count.", files[index].c_str());
866         OHOS::RemoveFile(files[index]);
867     }
868 }
869 
InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)870 int ProcessDumper::InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)
871 {
872     DFX_TRACE_SCOPED("InitPrintThread");
873     struct FaultLoggerdRequest faultloggerdRequest;
874     (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest));
875     faultloggerdRequest.type = ProcessDumper::GetLogTypeByRequest(*request);
876     faultloggerdRequest.pid = request->pid;
877     faultloggerdRequest.tid = request->tid;
878     faultloggerdRequest.time = request->timeStamp;
879     if (isCrash_ || faultloggerdRequest.type == FaultLoggerType::LEAK_STACKTRACE) {
880         bufferFd_ = RequestFileDescriptorEx(&faultloggerdRequest);
881         if (bufferFd_ == -1) {
882             ProcessDumper::RemoveFileIfNeed();
883             bufferFd_ = CreateFileForCrash(request->pid, request->timeStamp);
884         }
885         DfxRingBufferWrapper::GetInstance().SetWriteFunc(ProcessDumper::WriteDumpBuf);
886     } else {
887         isJsonDump_ = request->siginfo.si_code == DUMP_TYPE_REMOTE_JSON;
888         int pipeWriteFd[] = { -1, -1 };
889         if (RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE, pipeWriteFd) == 0) {
890             bufferFd_ = pipeWriteFd[PIPE_BUF_INDEX];
891             resFd_ = pipeWriteFd[PIPE_RES_INDEX];
892         }
893     }
894 
895     if (bufferFd_ < 0) {
896         DFXLOGW("Failed to request fd from faultloggerd.");
897         ReportCrashException(request->processName, request->pid, request->uid,
898                              CrashExceptionCode::CRASH_DUMP_EWRITEFD);
899     }
900     int result = bufferFd_;
901     if (!isJsonDump_) {
902         DfxRingBufferWrapper::GetInstance().SetWriteBufFd(bufferFd_);
903         bufferFd_ = INVALID_FD; // bufferFd_ set to INVALID_FD to prevent double close fd
904     }
905     DfxRingBufferWrapper::GetInstance().StartThread();
906     return result;
907 }
908 
WriteDumpBuf(int fd,const char * buf,const int len)909 int ProcessDumper::WriteDumpBuf(int fd, const char* buf, const int len)
910 {
911     if (buf == nullptr) {
912         return -1;
913     }
914     return WriteLog(fd, "%s", buf);
915 }
916 
WriteDumpRes(int32_t res,pid_t pid)917 void ProcessDumper::WriteDumpRes(int32_t res, pid_t pid)
918 {
919     DFXLOGI("%{public}s :: res: %{public}s", __func__, DfxDumpRes::ToString(res).c_str());
920     // After skipping InitPrintThread due to ptrace failure or other reasons,
921     // retry request resFd_ to write back the result to dumpcatch
922     if (resFd_ < 0) {
923         int pipeWriteFd[] = { -1, -1 };
924         if (RequestPipeFd(pid, FaultLoggerPipeType::PIPE_FD_WRITE, pipeWriteFd) == -1) {
925             DFXLOGE("%{public}s request pipe failed, err:%{public}d", __func__, errno);
926             return;
927         }
928         CloseFd(pipeWriteFd[0]);
929         resFd_ = pipeWriteFd[1];
930     }
931 
932     ssize_t nwrite = OHOS_TEMP_FAILURE_RETRY(write(resFd_, &res, sizeof(res)));
933     if (nwrite < 0) {
934         DFXLOGE("%{public}s write fail, err:%{public}d", __func__, errno);
935     }
936 }
937 
IsCrash() const938 bool ProcessDumper::IsCrash() const
939 {
940     return isCrash_;
941 }
942 
ReportSigDumpStats(const std::shared_ptr<ProcessDumpRequest> & request) const943 void ProcessDumper::ReportSigDumpStats(const std::shared_ptr<ProcessDumpRequest> &request) const
944 {
945     if (isCrash_) {
946         return;
947     }
948 
949     std::vector<uint8_t> buf(sizeof(struct FaultLoggerdStatsRequest), 0);
950     auto stat = reinterpret_cast<struct FaultLoggerdStatsRequest*>(buf.data());
951     stat->type = PROCESS_DUMP;
952     stat->pid = request->pid;
953     stat->signalTime = request->timeStamp;
954     stat->processdumpStartTime = startTime_;
955     stat->processdumpFinishTime = finishTime_;
956     if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess),
957         request->processName, sizeof(request->processName)) != 0) {
958         DFXLOGE("Failed to copy target processName (%{public}d)", errno);
959         return;
960     }
961 
962     ReportDumpStats(stat);
963 }
964 
ReportCrashInfo(const std::string & jsonInfo,const ProcessDumpRequest & request)965 void ProcessDumper::ReportCrashInfo(const std::string& jsonInfo, const ProcessDumpRequest &request)
966 {
967     if (process_ == nullptr) {
968         return;
969     }
970     auto reporter = CppCrashReporter(request.timeStamp, process_, request.dumpMode);
971     reporter.SetCppCrashInfo(jsonInfo);
972     reporter.ReportToHiview();
973     reporter.ReportToAbilityManagerService();
974 }
975 
ReportAddrSanitizer(ProcessDumpRequest & request,std::string & jsonInfo)976 void ProcessDumper::ReportAddrSanitizer(ProcessDumpRequest &request, std::string &jsonInfo)
977 {
978 #ifndef HISYSEVENT_DISABLE
979     std::string reason = "DEBUG SIGNAL";
980     std::string summary;
981     if (process_ != nullptr && process_->keyThread_ != nullptr) {
982         reason = process_->reason;
983         summary = process_->keyThread_->ToString();
984     }
985     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "ADDR_SANITIZER",
986                     OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
987                     "MODULE", request.processName,
988                     "PID", request.pid,
989                     "UID", request.uid,
990                     "HAPPEN_TIME", request.timeStamp,
991                     "REASON", reason,
992                     "SUMMARY", summary);
993     DFXLOGI("%{public}s", "Report fdsan event done.");
994 #else
995     DFXLOGI("%{public}s", "Not supported for fdsan reporting.");
996 #endif
997 }
998 
ReadFdTable(const ProcessDumpRequest & request)999 void ProcessDumper::ReadFdTable(const ProcessDumpRequest &request)
1000 {
1001     // Non crash, leak, jemalloc do not read fdtable
1002     if (!isCrash_ ||
1003         (request.siginfo.si_signo == SIGLEAK_STACK &&
1004          request.siginfo.si_code != SIGLEAK_STACK_FDSAN &&
1005          request.siginfo.si_code != SIGLEAK_STACK_BADFD)) {
1006         return;
1007     }
1008     process_->openFiles = GetOpenFiles(request.pid, request.nsPid, request.fdTableAddr);
1009 }
1010 } // namespace HiviewDFX
1011 } // namespace OHOS
1012