1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci 16800b99b8Sopenharmony_ci#include "dfx_unwind_remote.h" 17800b99b8Sopenharmony_ci 18800b99b8Sopenharmony_ci#include <algorithm> 19800b99b8Sopenharmony_ci#include <cstdio> 20800b99b8Sopenharmony_ci#include <cstring> 21800b99b8Sopenharmony_ci#include <elf.h> 22800b99b8Sopenharmony_ci#include <link.h> 23800b99b8Sopenharmony_ci#include <securec.h> 24800b99b8Sopenharmony_ci 25800b99b8Sopenharmony_ci#include "crash_exception.h" 26800b99b8Sopenharmony_ci#include "dfx_unwind_async_thread.h" 27800b99b8Sopenharmony_ci#include "dfx_config.h" 28800b99b8Sopenharmony_ci#include "dfx_define.h" 29800b99b8Sopenharmony_ci#include "dfx_frame_formatter.h" 30800b99b8Sopenharmony_ci#include "dfx_kernel_stack.h" 31800b99b8Sopenharmony_ci#include "dfx_logger.h" 32800b99b8Sopenharmony_ci#include "dfx_maps.h" 33800b99b8Sopenharmony_ci#include "dfx_process.h" 34800b99b8Sopenharmony_ci#include "dfx_ptrace.h" 35800b99b8Sopenharmony_ci#include "dfx_regs.h" 36800b99b8Sopenharmony_ci#include "dfx_ring_buffer_wrapper.h" 37800b99b8Sopenharmony_ci#include "dfx_symbols.h" 38800b99b8Sopenharmony_ci#include "dfx_thread.h" 39800b99b8Sopenharmony_ci#include "dfx_trace.h" 40800b99b8Sopenharmony_ci#include "dfx_util.h" 41800b99b8Sopenharmony_ci#ifdef PARSE_LOCK_OWNER 42800b99b8Sopenharmony_ci#include "lock_parser.h" 43800b99b8Sopenharmony_ci#endif 44800b99b8Sopenharmony_ci#ifndef is_ohos_lite 45800b99b8Sopenharmony_ci#include "parameter.h" 46800b99b8Sopenharmony_ci#include "parameters.h" 47800b99b8Sopenharmony_ci#endif // !is_ohos_lite 48800b99b8Sopenharmony_ci#include "process_dumper.h" 49800b99b8Sopenharmony_ci#include "printer.h" 50800b99b8Sopenharmony_ci 51800b99b8Sopenharmony_cinamespace OHOS { 52800b99b8Sopenharmony_cinamespace HiviewDFX { 53800b99b8Sopenharmony_cinamespace { 54800b99b8Sopenharmony_civoid GetThreadKernelStack(std::shared_ptr<DfxThread> thread) 55800b99b8Sopenharmony_ci{ 56800b99b8Sopenharmony_ci std::string threadKernelStack; 57800b99b8Sopenharmony_ci pid_t tid = thread->threadInfo_.nsTid; 58800b99b8Sopenharmony_ci DfxThreadStack threadStack; 59800b99b8Sopenharmony_ci if (DfxGetKernelStack(tid, threadKernelStack) == 0 && FormatThreadKernelStack(threadKernelStack, threadStack)) { 60800b99b8Sopenharmony_ci DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid); 61800b99b8Sopenharmony_ci#ifndef is_ohos_lite 62800b99b8Sopenharmony_ci if (OHOS::system::GetParameter("const.logsystem.versiontype", "false") == "beta") { 63800b99b8Sopenharmony_ci size_t step = LOG_BUF_LEN - 1; 64800b99b8Sopenharmony_ci for (size_t i = 0; i < threadKernelStack.length(); i += step) { 65800b99b8Sopenharmony_ci DFXLOGI("%{public}s", threadKernelStack.substr(i, step).c_str()); 66800b99b8Sopenharmony_ci } 67800b99b8Sopenharmony_ci } 68800b99b8Sopenharmony_ci#endif 69800b99b8Sopenharmony_ci thread->SetFrames(threadStack.frames); 70800b99b8Sopenharmony_ci } 71800b99b8Sopenharmony_ci} 72800b99b8Sopenharmony_ci} 73800b99b8Sopenharmony_ci 74800b99b8Sopenharmony_ciDfxUnwindRemote &DfxUnwindRemote::GetInstance() 75800b99b8Sopenharmony_ci{ 76800b99b8Sopenharmony_ci static DfxUnwindRemote ins; 77800b99b8Sopenharmony_ci return ins; 78800b99b8Sopenharmony_ci} 79800b99b8Sopenharmony_ci 80800b99b8Sopenharmony_cibool DfxUnwindRemote::UnwindProcess(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process, 81800b99b8Sopenharmony_ci std::shared_ptr<Unwinder> unwinder, pid_t vmPid) 82800b99b8Sopenharmony_ci{ 83800b99b8Sopenharmony_ci DFX_TRACE_SCOPED("UnwindProcess"); 84800b99b8Sopenharmony_ci DFXLOGW("start unwind process."); 85800b99b8Sopenharmony_ci if (process == nullptr || unwinder == nullptr) { 86800b99b8Sopenharmony_ci DFXLOGW("%{public}s::process or unwinder is not initialized.", __func__); 87800b99b8Sopenharmony_ci return false; 88800b99b8Sopenharmony_ci } 89800b99b8Sopenharmony_ci 90800b99b8Sopenharmony_ci SetCrashProcInfo(process->processInfo_.processName, process->processInfo_.pid, 91800b99b8Sopenharmony_ci process->processInfo_.uid); 92800b99b8Sopenharmony_ci int unwCnt = UnwindKeyThread(request, process, unwinder, vmPid) ? 1 : 0; 93800b99b8Sopenharmony_ci 94800b99b8Sopenharmony_ci // dumpt -p -t will not unwind other thread 95800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash() || request->siginfo.si_value.sival_int == 0) { 96800b99b8Sopenharmony_ci unwCnt += UnwindOtherThread(process, unwinder, vmPid); 97800b99b8Sopenharmony_ci } 98800b99b8Sopenharmony_ci 99800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash()) { 100800b99b8Sopenharmony_ci if (request->dumpMode == SPLIT_MODE) { 101800b99b8Sopenharmony_ci if (process->vmThread_ == nullptr) { 102800b99b8Sopenharmony_ci DFXLOGW("%{public}s::unwind vm thread is not initialized.", __func__); 103800b99b8Sopenharmony_ci } else { 104800b99b8Sopenharmony_ci Printer::PrintThreadFaultStackByConfig(process, process->vmThread_, unwinder); 105800b99b8Sopenharmony_ci } 106800b99b8Sopenharmony_ci } else { 107800b99b8Sopenharmony_ci if (process->keyThread_ == nullptr) { 108800b99b8Sopenharmony_ci DFXLOGW("%{public}s::unwind key thread is not initialized.", __func__); 109800b99b8Sopenharmony_ci } else { 110800b99b8Sopenharmony_ci pid_t nsTid = process->keyThread_->threadInfo_.nsTid; 111800b99b8Sopenharmony_ci process->keyThread_->threadInfo_.nsTid = vmPid; // read registers from vm process 112800b99b8Sopenharmony_ci Printer::PrintThreadFaultStackByConfig(process, process->keyThread_, unwinder); 113800b99b8Sopenharmony_ci process->keyThread_->threadInfo_.nsTid = nsTid; 114800b99b8Sopenharmony_ci } 115800b99b8Sopenharmony_ci } 116800b99b8Sopenharmony_ci Printer::PrintProcessMapsByConfig(unwinder->GetMaps()); 117800b99b8Sopenharmony_ci Printer::PrintThreadOpenFiles(process); 118800b99b8Sopenharmony_ci } 119800b99b8Sopenharmony_ci 120800b99b8Sopenharmony_ci if (isVmProcAttach) { 121800b99b8Sopenharmony_ci DfxPtrace::Detach(vmPid); 122800b99b8Sopenharmony_ci } 123800b99b8Sopenharmony_ci DFXLOGW("success unwind thread cnt is %{public}d", unwCnt); 124800b99b8Sopenharmony_ci return unwCnt > 0; 125800b99b8Sopenharmony_ci} 126800b99b8Sopenharmony_ci 127800b99b8Sopenharmony_cibool DfxUnwindRemote::UnwindKeyThread(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process, 128800b99b8Sopenharmony_ci std::shared_ptr<Unwinder> unwinder, pid_t vmPid) 129800b99b8Sopenharmony_ci{ 130800b99b8Sopenharmony_ci bool result = false; 131800b99b8Sopenharmony_ci std::shared_ptr<DfxThread> unwThread = process->keyThread_; 132800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash() && (process->vmThread_ != nullptr)) { 133800b99b8Sopenharmony_ci unwThread = process->vmThread_; 134800b99b8Sopenharmony_ci } 135800b99b8Sopenharmony_ci if (unwThread == nullptr) { 136800b99b8Sopenharmony_ci DFXLOGW("%{public}s::unwind thread is not initialized.", __func__); 137800b99b8Sopenharmony_ci return false; 138800b99b8Sopenharmony_ci } 139800b99b8Sopenharmony_ci if (request == nullptr) { 140800b99b8Sopenharmony_ci DFXLOGW("%{public}s::request is not initialized.", __func__); 141800b99b8Sopenharmony_ci return false; 142800b99b8Sopenharmony_ci } 143800b99b8Sopenharmony_ci unwinder->SetIsJitCrashFlag(ProcessDumper::GetInstance().IsCrash()); 144800b99b8Sopenharmony_ci auto unwindAsyncThread = std::make_shared<DfxUnwindAsyncThread>(unwThread, unwinder, request->stackId); 145800b99b8Sopenharmony_ci if ((vmPid != 0)) { 146800b99b8Sopenharmony_ci if (DfxPtrace::Attach(vmPid, PTRACE_ATTATCH_KEY_THREAD_TIMEOUT)) { 147800b99b8Sopenharmony_ci isVmProcAttach = true; 148800b99b8Sopenharmony_ci if (unwThread->GetThreadRegs() != nullptr) { 149800b99b8Sopenharmony_ci result = unwindAsyncThread->UnwindStack(vmPid); 150800b99b8Sopenharmony_ci } else { 151800b99b8Sopenharmony_ci GetThreadKernelStack(unwThread); 152800b99b8Sopenharmony_ci } 153800b99b8Sopenharmony_ci } 154800b99b8Sopenharmony_ci } else { 155800b99b8Sopenharmony_ci result = unwindAsyncThread->UnwindStack(); 156800b99b8Sopenharmony_ci } 157800b99b8Sopenharmony_ci 158800b99b8Sopenharmony_ci std::string fatalMsg = process->GetFatalMessage() + unwindAsyncThread->tip; 159800b99b8Sopenharmony_ci if (!unwindAsyncThread->tip.empty()) { 160800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash()) { 161800b99b8Sopenharmony_ci ReportCrashException(process->processInfo_.processName, process->processInfo_.pid, 162800b99b8Sopenharmony_ci process->processInfo_.uid, CrashExceptionCode::CRASH_UNWIND_ESTACK); 163800b99b8Sopenharmony_ci } 164800b99b8Sopenharmony_ci } 165800b99b8Sopenharmony_ci process->SetFatalMessage(fatalMsg); 166800b99b8Sopenharmony_ci Printer::PrintDumpHeader(request, process, unwinder); 167800b99b8Sopenharmony_ci Printer::PrintThreadHeaderByConfig(process->keyThread_, true); 168800b99b8Sopenharmony_ci Printer::PrintThreadBacktraceByConfig(unwThread, true); 169800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash()) { 170800b99b8Sopenharmony_ci // Registers of unwThread has been changed, we should print regs from request context. 171800b99b8Sopenharmony_ci process->regs_ = DfxRegs::CreateFromUcontext(request->context); 172800b99b8Sopenharmony_ci Printer::PrintRegsByConfig(process->regs_); 173800b99b8Sopenharmony_ci } 174800b99b8Sopenharmony_ci return result; 175800b99b8Sopenharmony_ci} 176800b99b8Sopenharmony_ci 177800b99b8Sopenharmony_ciint DfxUnwindRemote::UnwindOtherThread(std::shared_ptr<DfxProcess> process, std::shared_ptr<Unwinder> unwinder, 178800b99b8Sopenharmony_ci pid_t vmPid) 179800b99b8Sopenharmony_ci{ 180800b99b8Sopenharmony_ci if ((!DfxConfig::GetConfig().dumpOtherThreads) || (vmPid != 0 && !isVmProcAttach)) { 181800b99b8Sopenharmony_ci return 0; 182800b99b8Sopenharmony_ci } 183800b99b8Sopenharmony_ci unwinder->SetIsJitCrashFlag(false); 184800b99b8Sopenharmony_ci size_t index = 0; 185800b99b8Sopenharmony_ci int unwCnt = 0; 186800b99b8Sopenharmony_ci for (auto &thread : process->GetOtherThreads()) { 187800b99b8Sopenharmony_ci if ((index == 0) && ProcessDumper::GetInstance().IsCrash()) { 188800b99b8Sopenharmony_ci Printer::PrintOtherThreadHeaderByConfig(); 189800b99b8Sopenharmony_ci } 190800b99b8Sopenharmony_ci 191800b99b8Sopenharmony_ci if (isVmProcAttach || thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT)) { 192800b99b8Sopenharmony_ci Printer::PrintThreadHeaderByConfig(thread, false); 193800b99b8Sopenharmony_ci auto regs = thread->GetThreadRegs(); 194800b99b8Sopenharmony_ci unwinder->SetRegs(regs); 195800b99b8Sopenharmony_ci bool withRegs = regs != nullptr; 196800b99b8Sopenharmony_ci pid_t tid = thread->threadInfo_.nsTid; 197800b99b8Sopenharmony_ci DFXLOGD("%{public}s, unwind tid(%{public}d) start", __func__, tid); 198800b99b8Sopenharmony_ci if (isVmProcAttach && !withRegs) { 199800b99b8Sopenharmony_ci GetThreadKernelStack(thread); 200800b99b8Sopenharmony_ci Printer::PrintThreadBacktraceByConfig(thread, false); 201800b99b8Sopenharmony_ci thread->Detach(); 202800b99b8Sopenharmony_ci continue; 203800b99b8Sopenharmony_ci } 204800b99b8Sopenharmony_ci auto pid = (vmPid != 0 && isVmProcAttach) ? vmPid : tid; 205800b99b8Sopenharmony_ci DFX_TRACE_START("OtherThreadUnwindRemote:%d", tid); 206800b99b8Sopenharmony_ci bool ret = unwinder->UnwindRemote(pid, withRegs, DfxConfig::GetConfig().maxFrameNums); 207800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 208800b99b8Sopenharmony_ci#ifdef PARSE_LOCK_OWNER 209800b99b8Sopenharmony_ci DFX_TRACE_START("OtherThreadGetFrames:%d", tid); 210800b99b8Sopenharmony_ci thread->SetFrames(unwinder->GetFrames()); 211800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 212800b99b8Sopenharmony_ci LockParser::ParseLockInfo(unwinder, pid, tid); 213800b99b8Sopenharmony_ci#else 214800b99b8Sopenharmony_ci thread->Detach(); 215800b99b8Sopenharmony_ci DFX_TRACE_START("OtherThreadGetFrames:%d", tid); 216800b99b8Sopenharmony_ci thread->SetFrames(unwinder->GetFrames()); 217800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 218800b99b8Sopenharmony_ci#endif 219800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash()) { 220800b99b8Sopenharmony_ci ReportUnwinderException(unwinder->GetLastErrorCode()); 221800b99b8Sopenharmony_ci } 222800b99b8Sopenharmony_ci if (!ret) { 223800b99b8Sopenharmony_ci DFXLOGW("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret); 224800b99b8Sopenharmony_ci } else { 225800b99b8Sopenharmony_ci unwCnt++; 226800b99b8Sopenharmony_ci } 227800b99b8Sopenharmony_ci Printer::PrintThreadBacktraceByConfig(thread, false); 228800b99b8Sopenharmony_ci } 229800b99b8Sopenharmony_ci index++; 230800b99b8Sopenharmony_ci } 231800b99b8Sopenharmony_ci return unwCnt; 232800b99b8Sopenharmony_ci} 233800b99b8Sopenharmony_ci 234800b99b8Sopenharmony_cibool DfxUnwindRemote::InitTargetKeyThreadRegs(std::shared_ptr<ProcessDumpRequest> request, 235800b99b8Sopenharmony_ci std::shared_ptr<DfxProcess> process) 236800b99b8Sopenharmony_ci{ 237800b99b8Sopenharmony_ci auto regs = DfxRegs::CreateFromUcontext(request->context); 238800b99b8Sopenharmony_ci if (regs == nullptr) { 239800b99b8Sopenharmony_ci return false; 240800b99b8Sopenharmony_ci } 241800b99b8Sopenharmony_ci process->keyThread_->SetThreadRegs(regs); 242800b99b8Sopenharmony_ci return true; 243800b99b8Sopenharmony_ci} 244800b99b8Sopenharmony_ci 245800b99b8Sopenharmony_civoid DfxUnwindRemote::InitOtherThreadRegs(std::shared_ptr<DfxProcess> process) 246800b99b8Sopenharmony_ci{ 247800b99b8Sopenharmony_ci if (!DfxConfig::GetConfig().dumpOtherThreads) { 248800b99b8Sopenharmony_ci return; 249800b99b8Sopenharmony_ci } 250800b99b8Sopenharmony_ci 251800b99b8Sopenharmony_ci for (auto &thread : process->GetOtherThreads()) { 252800b99b8Sopenharmony_ci if (thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT)) { 253800b99b8Sopenharmony_ci thread->SetThreadRegs(DfxRegs::CreateRemoteRegs(thread->threadInfo_.nsTid)); 254800b99b8Sopenharmony_ci } 255800b99b8Sopenharmony_ci } 256800b99b8Sopenharmony_ci} 257800b99b8Sopenharmony_ci 258800b99b8Sopenharmony_cibool DfxUnwindRemote::InitProcessAllThreadRegs(std::shared_ptr<ProcessDumpRequest> request, 259800b99b8Sopenharmony_ci std::shared_ptr<DfxProcess> process) 260800b99b8Sopenharmony_ci{ 261800b99b8Sopenharmony_ci if (!InitTargetKeyThreadRegs(request, process)) { 262800b99b8Sopenharmony_ci DFXLOGE("get key thread regs fail"); 263800b99b8Sopenharmony_ci return false; 264800b99b8Sopenharmony_ci } 265800b99b8Sopenharmony_ci InitOtherThreadRegs(process); 266800b99b8Sopenharmony_ci return true; 267800b99b8Sopenharmony_ci} 268800b99b8Sopenharmony_ci} // namespace HiviewDFX 269800b99b8Sopenharmony_ci} // namespace OHOS 270