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