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