1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2022-2024 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#include "dfx_unwind_async_thread.h"
16800b99b8Sopenharmony_ci
17800b99b8Sopenharmony_ci#include "crash_exception.h"
18800b99b8Sopenharmony_ci#include "dfx_config.h"
19800b99b8Sopenharmony_ci#include "dfx_log.h"
20800b99b8Sopenharmony_ci#include "dfx_memory.h"
21800b99b8Sopenharmony_ci#include "dfx_maps.h"
22800b99b8Sopenharmony_ci#include "dfx_regs.h"
23800b99b8Sopenharmony_ci#include "dfx_ring_buffer_wrapper.h"
24800b99b8Sopenharmony_ci#include "dfx_trace.h"
25800b99b8Sopenharmony_ci#ifdef PARSE_LOCK_OWNER
26800b99b8Sopenharmony_ci#include "lock_parser.h"
27800b99b8Sopenharmony_ci#endif
28800b99b8Sopenharmony_ci#include "process_dumper.h"
29800b99b8Sopenharmony_ci#include "printer.h"
30800b99b8Sopenharmony_ci#include "unique_stack_table.h"
31800b99b8Sopenharmony_ci
32800b99b8Sopenharmony_cinamespace OHOS {
33800b99b8Sopenharmony_cinamespace HiviewDFX {
34800b99b8Sopenharmony_cibool DfxUnwindAsyncThread::UnwindStack(pid_t vmPid)
35800b99b8Sopenharmony_ci{
36800b99b8Sopenharmony_ci    if (unwinder_ == nullptr || thread_ == nullptr) {
37800b99b8Sopenharmony_ci        DFXLOGE("%{public}s::thread or unwinder is not initialized.", __func__);
38800b99b8Sopenharmony_ci        return false;
39800b99b8Sopenharmony_ci    }
40800b99b8Sopenharmony_ci    // 1: get crash stack
41800b99b8Sopenharmony_ci    // unwinding with context passed by dump request, only for crash thread or target thread.
42800b99b8Sopenharmony_ci    auto regs = thread_->GetThreadRegs();
43800b99b8Sopenharmony_ci    unwinder_->SetRegs(regs);
44800b99b8Sopenharmony_ci    pid_t tid = thread_->threadInfo_.nsTid;
45800b99b8Sopenharmony_ci    DFXLOGI("%{public}s, unwind tid(%{public}d) start.", __func__, tid);
46800b99b8Sopenharmony_ci    auto tmpPid = vmPid != 0 ? vmPid : tid;
47800b99b8Sopenharmony_ci    DFX_TRACE_START("KeyThreadUnwindRemote:%d", tid);
48800b99b8Sopenharmony_ci    bool ret = unwinder_->UnwindRemote(tmpPid,
49800b99b8Sopenharmony_ci                                       regs != nullptr,
50800b99b8Sopenharmony_ci                                       DfxConfig::GetConfig().maxFrameNums);
51800b99b8Sopenharmony_ci    DFX_TRACE_FINISH();
52800b99b8Sopenharmony_ci    if (ProcessDumper::GetInstance().IsCrash()) {
53800b99b8Sopenharmony_ci        ReportUnwinderException(unwinder_->GetLastErrorCode());
54800b99b8Sopenharmony_ci        if (!ret) {
55800b99b8Sopenharmony_ci            UnwindThreadFallback();
56800b99b8Sopenharmony_ci        }
57800b99b8Sopenharmony_ci        DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
58800b99b8Sopenharmony_ci        thread_->SetFrames(unwinder_->GetFrames());
59800b99b8Sopenharmony_ci        DFX_TRACE_FINISH();
60800b99b8Sopenharmony_ci        UnwindThreadByParseStackIfNeed();
61800b99b8Sopenharmony_ci        // 2: get submitterStack
62800b99b8Sopenharmony_ci        std::vector<DfxFrame> submmiterFrames;
63800b99b8Sopenharmony_ci        GetSubmitterStack(submmiterFrames);
64800b99b8Sopenharmony_ci        // 3: merge two stack
65800b99b8Sopenharmony_ci        MergeStack(submmiterFrames);
66800b99b8Sopenharmony_ci    } else {
67800b99b8Sopenharmony_ci#ifdef PARSE_LOCK_OWNER
68800b99b8Sopenharmony_ci        DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
69800b99b8Sopenharmony_ci        thread_->SetFrames(unwinder_->GetFrames());
70800b99b8Sopenharmony_ci        DFX_TRACE_FINISH();
71800b99b8Sopenharmony_ci        LockParser::ParseLockInfo(unwinder_, tmpPid, thread_->threadInfo_.nsTid);
72800b99b8Sopenharmony_ci#else
73800b99b8Sopenharmony_ci        thread_->Detach();
74800b99b8Sopenharmony_ci        DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
75800b99b8Sopenharmony_ci        thread_->SetFrames(unwinder_->GetFrames());
76800b99b8Sopenharmony_ci        DFX_TRACE_FINISH();
77800b99b8Sopenharmony_ci#endif
78800b99b8Sopenharmony_ci    }
79800b99b8Sopenharmony_ci
80800b99b8Sopenharmony_ci    DFXLOGI("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret);
81800b99b8Sopenharmony_ci    return ret;
82800b99b8Sopenharmony_ci}
83800b99b8Sopenharmony_ci
84800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::GetSubmitterStack(std::vector<DfxFrame> &submitterFrames)
85800b99b8Sopenharmony_ci{
86800b99b8Sopenharmony_ci    if (stackId_ == 0) {
87800b99b8Sopenharmony_ci        return;
88800b99b8Sopenharmony_ci    }
89800b99b8Sopenharmony_ci    const std::shared_ptr<DfxMaps>& maps = unwinder_->GetMaps();
90800b99b8Sopenharmony_ci    if (maps == nullptr) {
91800b99b8Sopenharmony_ci        return;
92800b99b8Sopenharmony_ci    }
93800b99b8Sopenharmony_ci    std::vector<std::shared_ptr<DfxMap>> mapVec;
94800b99b8Sopenharmony_ci    if (!maps->FindMapsByName("[anon:async_stack_table]", mapVec)) {
95800b99b8Sopenharmony_ci        DFXLOGE("%{public}s::Can not find map of async stack table", __func__);
96800b99b8Sopenharmony_ci        return;
97800b99b8Sopenharmony_ci    }
98800b99b8Sopenharmony_ci    auto map = mapVec.front();
99800b99b8Sopenharmony_ci    size_t size = map->end - map->begin;
100800b99b8Sopenharmony_ci    auto tableData = std::make_shared<std::vector<uint8_t>>(size);
101800b99b8Sopenharmony_ci    size_t byte = DfxMemory::ReadProcMemByPid(thread_->threadInfo_.nsTid, map->begin, tableData->data(), size);
102800b99b8Sopenharmony_ci    if (byte != size) {
103800b99b8Sopenharmony_ci        DFXLOGE("Failed to read unique_table from target");
104800b99b8Sopenharmony_ci        return;
105800b99b8Sopenharmony_ci    }
106800b99b8Sopenharmony_ci    auto table = std::make_shared<UniqueStackTable>(tableData->data(), size, false);
107800b99b8Sopenharmony_ci    std::vector<uintptr_t> pcs;
108800b99b8Sopenharmony_ci    StackId id;
109800b99b8Sopenharmony_ci    id.value = stackId_;
110800b99b8Sopenharmony_ci    if (table->GetPcsByStackId(id, pcs)) {
111800b99b8Sopenharmony_ci        unwinder_->GetFramesByPcs(submitterFrames, pcs);
112800b99b8Sopenharmony_ci    } else {
113800b99b8Sopenharmony_ci        DFXLOGW("%{public}s::Failed to get pcs", __func__);
114800b99b8Sopenharmony_ci    }
115800b99b8Sopenharmony_ci}
116800b99b8Sopenharmony_ci
117800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::MergeStack(std::vector<DfxFrame> &submitterFrames)
118800b99b8Sopenharmony_ci{
119800b99b8Sopenharmony_ci    auto frames = thread_->GetFrames();
120800b99b8Sopenharmony_ci    frames.insert(frames.end(), submitterFrames.begin(), submitterFrames.end());
121800b99b8Sopenharmony_ci    thread_->SetFrames(frames);
122800b99b8Sopenharmony_ci}
123800b99b8Sopenharmony_ci
124800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::UnwindThreadFallback()
125800b99b8Sopenharmony_ci{
126800b99b8Sopenharmony_ci#ifndef __x86_64__
127800b99b8Sopenharmony_ci    if (unwinder_->GetFrames().size() > 0) {
128800b99b8Sopenharmony_ci        return;
129800b99b8Sopenharmony_ci    }
130800b99b8Sopenharmony_ci    // As we failed to init libunwind, just print pc and lr for first two frames
131800b99b8Sopenharmony_ci    std::shared_ptr<DfxRegs> regs = thread_->GetThreadRegs();
132800b99b8Sopenharmony_ci    if (regs == nullptr) {
133800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process");
134800b99b8Sopenharmony_ci        return;
135800b99b8Sopenharmony_ci    }
136800b99b8Sopenharmony_ci
137800b99b8Sopenharmony_ci    std::shared_ptr<DfxMaps> maps = unwinder_->GetMaps();
138800b99b8Sopenharmony_ci    if (maps == nullptr) {
139800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process");
140800b99b8Sopenharmony_ci        return;
141800b99b8Sopenharmony_ci    }
142800b99b8Sopenharmony_ci    std::shared_ptr<Unwinder> unwinder = unwinder_;
143800b99b8Sopenharmony_ci
144800b99b8Sopenharmony_ci    auto createFrame = [maps, unwinder] (size_t index, uintptr_t pc, uintptr_t sp = 0) {
145800b99b8Sopenharmony_ci        std::shared_ptr<DfxMap> map;
146800b99b8Sopenharmony_ci        DfxFrame frame;
147800b99b8Sopenharmony_ci        frame.pc = pc;
148800b99b8Sopenharmony_ci        frame.sp = sp;
149800b99b8Sopenharmony_ci        frame.index = index;
150800b99b8Sopenharmony_ci        if (maps->FindMapByAddr(pc, map)) {
151800b99b8Sopenharmony_ci            frame.relPc = map->GetRelPc(pc);
152800b99b8Sopenharmony_ci            frame.mapName = map->name;
153800b99b8Sopenharmony_ci        } else {
154800b99b8Sopenharmony_ci            frame.relPc = pc;
155800b99b8Sopenharmony_ci            frame.mapName = (index == 0 ? "Not mapped pc" : "Not mapped lr");
156800b99b8Sopenharmony_ci        }
157800b99b8Sopenharmony_ci        unwinder->AddFrame(frame);
158800b99b8Sopenharmony_ci    };
159800b99b8Sopenharmony_ci
160800b99b8Sopenharmony_ci    createFrame(0, regs->GetPc(), regs->GetSp());
161800b99b8Sopenharmony_ci    createFrame(1, *(regs->GetReg(REG_LR)));
162800b99b8Sopenharmony_ci#endif
163800b99b8Sopenharmony_ci}
164800b99b8Sopenharmony_ci
165800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::UnwindThreadByParseStackIfNeed()
166800b99b8Sopenharmony_ci{
167800b99b8Sopenharmony_ci    if (thread_ == nullptr || unwinder_ == nullptr) {
168800b99b8Sopenharmony_ci        return;
169800b99b8Sopenharmony_ci    }
170800b99b8Sopenharmony_ci    auto frames = thread_->GetFrames();
171800b99b8Sopenharmony_ci    constexpr int minFramesNum = 3;
172800b99b8Sopenharmony_ci    size_t initSize = frames.size();
173800b99b8Sopenharmony_ci    if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos ||
174800b99b8Sopenharmony_ci        frames[minFramesNum - 1].mapName.find("[Unknown]") != std::string::npos) {
175800b99b8Sopenharmony_ci        bool needParseStack = true;
176800b99b8Sopenharmony_ci        thread_->InitFaultStack(needParseStack);
177800b99b8Sopenharmony_ci        auto faultStack = thread_->GetFaultStack();
178800b99b8Sopenharmony_ci        if (faultStack == nullptr || !faultStack->ParseUnwindStack(unwinder_->GetMaps(), frames)) {
179800b99b8Sopenharmony_ci            DFXLOGE("%{public}s : Failed to parse unwind stack.", __func__);
180800b99b8Sopenharmony_ci            return;
181800b99b8Sopenharmony_ci        }
182800b99b8Sopenharmony_ci        thread_->SetFrames(frames);
183800b99b8Sopenharmony_ci        tip = StringPrintf(
184800b99b8Sopenharmony_ci            " Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack.",
185800b99b8Sopenharmony_ci            initSize);
186800b99b8Sopenharmony_ci    }
187800b99b8Sopenharmony_ci}
188800b99b8Sopenharmony_ci}
189800b99b8Sopenharmony_ci}