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