1 /*
2 * Copyright (c) 2021-2023 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 "dfx_unwind_remote.h"
17
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstring>
21 #include <elf.h>
22 #include <link.h>
23 #include <securec.h>
24
25 #include "dfx_config.h"
26 #include "dfx_define.h"
27 #include "dfx_logger.h"
28 #include "dfx_maps.h"
29 #include "dfx_process.h"
30 #include "dfx_regs.h"
31 #include "dfx_ring_buffer_wrapper.h"
32 #include "dfx_symbols.h"
33 #include "dfx_thread.h"
34 #include "dfx_util.h"
35 #include "process_dumper.h"
36 #include "printer.h"
37
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace {
UnwindThreadByParseStackIfNeed(std::shared_ptr<DfxProcess> & process,std::shared_ptr<DfxThread> & thread,std::shared_ptr<Unwinder> unwinder)41 void UnwindThreadByParseStackIfNeed(std::shared_ptr<DfxProcess> &process,
42 std::shared_ptr<DfxThread> &thread, std::shared_ptr<Unwinder> unwinder)
43 {
44 if (process == nullptr || thread == nullptr) {
45 return;
46 }
47 auto frames = unwinder->GetFrames();
48 constexpr int minFramesNum = 3;
49 size_t initSize = frames.size();
50 if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos) {
51 bool needParseStack = true;
52 thread->InitFaultStack(needParseStack);
53 auto faultStack = thread->GetFaultStack();
54 if (faultStack == nullptr || !faultStack->ParseUnwindStack(unwinder->GetMaps(), frames)) {
55 DFXLOG_ERROR("%s : Failed to parse unwind stack.", __func__);
56 return;
57 }
58 thread->SetFrames(frames);
59 std::string tip = StringPrintf(
60 " Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack",
61 initSize);
62 std::string msg = process->GetFatalMessage() + tip;
63 process->SetFatalMessage(msg);
64 }
65 }
66 }
67
GetInstance()68 DfxUnwindRemote &DfxUnwindRemote::GetInstance()
69 {
70 static DfxUnwindRemote ins;
71 return ins;
72 }
73
UnwindProcess(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder)74 bool DfxUnwindRemote::UnwindProcess(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
75 std::shared_ptr<Unwinder> unwinder)
76 {
77 bool ret = false;
78 if (process == nullptr || unwinder == nullptr) {
79 DFXLOG_WARN("%s::process or unwinder is not initialized.", __func__);
80 return ret;
81 }
82
83 std::shared_ptr<DfxThread> unwThread = process->keyThread_;
84 if (ProcessDumper::GetInstance().IsCrash() && (process->vmThread_ != nullptr)) {
85 unwThread = process->vmThread_;
86 }
87
88 do {
89 if (unwThread == nullptr) {
90 break;
91 }
92
93 // unwinding with context passed by dump request, only for crash thread or target thread.
94 unwinder->SetRegs(unwThread->GetThreadRegs());
95 ret = unwinder->UnwindRemote(unwThread->threadInfo_.nsTid,
96 ProcessDumper::GetInstance().IsCrash(),
97 DfxConfig::GetConfig().maxFrameNums);
98 if (!ret && ProcessDumper::GetInstance().IsCrash()) {
99 UnwindThreadFallback(process, unwThread, unwinder);
100 }
101 unwThread->SetFrames(unwinder->GetFrames());
102 UnwindThreadByParseStackIfNeed(process, unwThread, unwinder);
103 Printer::PrintDumpHeader(request, process, unwinder);
104 Printer::PrintThreadHeaderByConfig(process->keyThread_);
105 Printer::PrintThreadBacktraceByConfig(unwThread);
106 if (ProcessDumper::GetInstance().IsCrash()) {
107 // Registers of unwThread has been changed, we should print regs from request context.
108 Printer::PrintRegsByConfig(DfxRegs::CreateFromUcontext(request->context));
109 if (!DfxConfig::GetConfig().dumpOtherThreads) {
110 break;
111 }
112 }
113
114 auto threads = process->GetOtherThreads();
115 if (threads.empty()) {
116 break;
117 }
118
119 size_t index = 0;
120 for (auto thread : threads) {
121 if ((index == 0) && ProcessDumper::GetInstance().IsCrash()) {
122 Printer::PrintOtherThreadHeaderByConfig();
123 }
124
125 if (thread->Attach()) {
126 Printer::PrintThreadHeaderByConfig(thread);
127 unwinder->UnwindRemote(thread->threadInfo_.nsTid, false, DfxConfig::GetConfig().maxFrameNums);
128 thread->Detach();
129 thread->SetFrames(unwinder->GetFrames());
130 Printer::PrintThreadBacktraceByConfig(thread);
131 }
132 index++;
133 }
134 ret = true;
135 } while (false);
136
137 if (ProcessDumper::GetInstance().IsCrash()) {
138 Printer::PrintThreadFaultStackByConfig(process, unwThread, unwinder);
139 Printer::PrintProcessMapsByConfig(unwinder->GetMaps());
140 }
141
142 return ret;
143 }
144
UnwindThreadFallback(std::shared_ptr<DfxProcess> process,std::shared_ptr<DfxThread> thread,std::shared_ptr<Unwinder> unwinder)145 void DfxUnwindRemote::UnwindThreadFallback(std::shared_ptr<DfxProcess> process, std::shared_ptr<DfxThread> thread,
146 std::shared_ptr<Unwinder> unwinder)
147 {
148 if (unwinder->GetFrames().size() > 0) {
149 return;
150 }
151 // As we failed to init libunwind, just print pc and lr for first two frames
152 std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
153 if (regs == nullptr) {
154 DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process");
155 return;
156 }
157
158 std::shared_ptr<DfxMaps> maps = unwinder->GetMaps();
159 if (maps == nullptr) {
160 DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process");
161 return;
162 }
163
164 auto createFrame = [maps, unwinder] (size_t index, uintptr_t pc, uintptr_t sp = 0) {
165 std::shared_ptr<DfxMap> map;
166 DfxFrame frame;
167 frame.pc = pc;
168 frame.sp = sp;
169 frame.index = index;
170 if (maps->FindMapByAddr(pc, map)) {
171 frame.relPc = map->GetRelPc(pc);
172 frame.mapName = map->name;
173 } else {
174 frame.relPc = pc;
175 frame.mapName = (index == 0 ? "Not mapped pc" : "Not mapped lr");
176 }
177 unwinder->AddFrame(frame);
178 };
179
180 createFrame(0, regs->GetPc(), regs->GetSp());
181 createFrame(1, *(regs->GetReg(REG_LR)));
182 }
183 } // namespace HiviewDFX
184 } // namespace OHOS
185