• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 #include "dfx_unwind_async_thread.h"
16 
17 #include "crash_exception.h"
18 #include "dfx_config.h"
19 #include "dfx_log.h"
20 #include "dfx_memory.h"
21 #include "dfx_maps.h"
22 #include "dfx_regs.h"
23 #include "dfx_ring_buffer_wrapper.h"
24 #include "dfx_trace.h"
25 #ifdef PARSE_LOCK_OWNER
26 #include "lock_parser.h"
27 #endif
28 #include "process_dumper.h"
29 #include "printer.h"
30 #include "unique_stack_table.h"
31 
32 namespace OHOS {
33 namespace HiviewDFX {
UnwindStack(pid_t vmPid)34 bool DfxUnwindAsyncThread::UnwindStack(pid_t vmPid)
35 {
36     if (unwinder_ == nullptr || thread_ == nullptr) {
37         DFXLOGE("%{public}s::thread or unwinder is not initialized.", __func__);
38         return false;
39     }
40     // 1: get crash stack
41     // unwinding with context passed by dump request, only for crash thread or target thread.
42     auto regs = thread_->GetThreadRegs();
43     unwinder_->SetRegs(regs);
44     pid_t tid = thread_->threadInfo_.nsTid;
45     DFXLOGI("%{public}s, unwind tid(%{public}d) start.", __func__, tid);
46     auto tmpPid = vmPid != 0 ? vmPid : tid;
47     DFX_TRACE_START("KeyThreadUnwindRemote:%d", tid);
48     bool ret = unwinder_->UnwindRemote(tmpPid,
49                                        regs != nullptr,
50                                        DfxConfig::GetConfig().maxFrameNums);
51     DFX_TRACE_FINISH();
52     if (ProcessDumper::GetInstance().IsCrash()) {
53         ReportUnwinderException(unwinder_->GetLastErrorCode());
54         if (!ret) {
55             UnwindThreadFallback();
56         }
57         DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
58         thread_->SetFrames(unwinder_->GetFrames());
59         DFX_TRACE_FINISH();
60         UnwindThreadByParseStackIfNeed();
61         // 2: get submitterStack
62         std::vector<DfxFrame> submmiterFrames;
63         GetSubmitterStack(submmiterFrames);
64         // 3: merge two stack
65         MergeStack(submmiterFrames);
66     } else {
67 #ifdef PARSE_LOCK_OWNER
68         DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
69         thread_->SetFrames(unwinder_->GetFrames());
70         DFX_TRACE_FINISH();
71         LockParser::ParseLockInfo(unwinder_, tmpPid, thread_->threadInfo_.nsTid);
72 #else
73         DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
74         thread_->SetFrames(unwinder_->GetFrames());
75         DFX_TRACE_FINISH();
76 #endif
77     }
78 
79     DFXLOGI("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret);
80     return ret;
81 }
82 
GetSubmitterStack(std::vector<DfxFrame> & submitterFrames)83 void DfxUnwindAsyncThread::GetSubmitterStack(std::vector<DfxFrame> &submitterFrames)
84 {
85     if (stackId_ == 0) {
86         return;
87     }
88     const std::shared_ptr<DfxMaps>& maps = unwinder_->GetMaps();
89     if (maps == nullptr) {
90         return;
91     }
92     std::vector<std::shared_ptr<DfxMap>> mapVec;
93     if (!maps->FindMapsByName("[anon:async_stack_table]", mapVec)) {
94         DFXLOGE("%{public}s::Can not find map of async stack table", __func__);
95         return;
96     }
97     auto map = mapVec.front();
98     size_t size = map->end - map->begin;
99     auto tableData = std::make_shared<std::vector<uint8_t>>(size);
100     size_t byte = DfxMemory::ReadProcMemByPid(thread_->threadInfo_.nsTid, map->begin, tableData->data(), size);
101     if (byte != size) {
102         DFXLOGE("Failed to read unique_table from target");
103         return;
104     }
105     auto table = std::make_shared<UniqueStackTable>(tableData->data(), size, false);
106     std::vector<uintptr_t> pcs;
107     StackId id;
108     id.value = stackId_;
109     if (table->GetPcsByStackId(id, pcs)) {
110         unwinder_->GetFramesByPcs(submitterFrames, pcs);
111     } else {
112         DFXLOGW("%{public}s::Failed to get pcs", __func__);
113     }
114 }
115 
MergeStack(std::vector<DfxFrame> & submitterFrames)116 void DfxUnwindAsyncThread::MergeStack(std::vector<DfxFrame> &submitterFrames)
117 {
118     auto frames = thread_->GetFrames();
119     frames.insert(frames.end(), submitterFrames.begin(), submitterFrames.end());
120     thread_->SetFrames(frames);
121 }
122 
UnwindThreadFallback()123 void DfxUnwindAsyncThread::UnwindThreadFallback()
124 {
125 #ifndef __x86_64__
126     if (unwinder_->GetFrames().size() > 0) {
127         return;
128     }
129     // As we failed to init libunwind, just print pc and lr for first two frames
130     std::shared_ptr<DfxRegs> regs = thread_->GetThreadRegs();
131     if (regs == nullptr) {
132         DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process");
133         return;
134     }
135 
136     std::shared_ptr<DfxMaps> maps = unwinder_->GetMaps();
137     if (maps == nullptr) {
138         DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process");
139         return;
140     }
141     std::shared_ptr<Unwinder> unwinder = unwinder_;
142 
143     auto createFrame = [maps, unwinder] (size_t index, uintptr_t pc, uintptr_t sp = 0) {
144         std::shared_ptr<DfxMap> map;
145         DfxFrame frame;
146         frame.pc = pc;
147         frame.sp = sp;
148         frame.index = index;
149         if (maps->FindMapByAddr(pc, map)) {
150             frame.relPc = map->GetRelPc(pc);
151             frame.mapName = map->name;
152         } else {
153             frame.relPc = pc;
154             frame.mapName = (index == 0 ? "Not mapped pc" : "Not mapped lr");
155         }
156         unwinder->AddFrame(frame);
157     };
158 
159     createFrame(0, regs->GetPc(), regs->GetSp());
160     createFrame(1, *(regs->GetReg(REG_LR)));
161 #endif
162 }
163 
UnwindThreadByParseStackIfNeed()164 void DfxUnwindAsyncThread::UnwindThreadByParseStackIfNeed()
165 {
166     if (thread_ == nullptr || unwinder_ == nullptr) {
167         return;
168     }
169     auto frames = thread_->GetFrames();
170     constexpr int minFramesNum = 3;
171     size_t initSize = frames.size();
172     if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos ||
173         frames[minFramesNum - 1].mapName.find("[Unknown]") != std::string::npos) {
174         bool needParseStack = true;
175         thread_->InitFaultStack(needParseStack);
176         auto faultStack = thread_->GetFaultStack();
177         if (faultStack == nullptr || !faultStack->ParseUnwindStack(unwinder_->GetMaps(), frames)) {
178             DFXLOGE("%{public}s : Failed to parse unwind stack.", __func__);
179             return;
180         }
181         thread_->SetFrames(frames);
182         unwindFailTip = StringPrintf(
183             "Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack.",
184             initSize);
185     }
186 }
187 }
188 }