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