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