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 "crash_exception.h"
26 #include "dfx_unwind_async_thread.h"
27 #include "dfx_config.h"
28 #include "dfx_define.h"
29 #include "dfx_frame_formatter.h"
30 #include "dfx_kernel_stack.h"
31 #include "dfx_logger.h"
32 #include "dfx_maps.h"
33 #include "dfx_process.h"
34 #include "dfx_ptrace.h"
35 #include "dfx_regs.h"
36 #include "dfx_ring_buffer_wrapper.h"
37 #include "dfx_symbols.h"
38 #include "dfx_thread.h"
39 #include "dfx_trace.h"
40 #include "dfx_util.h"
41 #ifdef PARSE_LOCK_OWNER
42 #include "lock_parser.h"
43 #endif
44 #include "process_dumper.h"
45 #include "printer.h"
46
47 namespace OHOS {
48 namespace HiviewDFX {
49 namespace {
GetThreadKernelStack(std::shared_ptr<DfxThread> thread)50 void GetThreadKernelStack(std::shared_ptr<DfxThread> thread)
51 {
52 std::string threadKernelStack;
53 pid_t tid = thread->threadInfo_.nsTid;
54 DfxThreadStack threadStack;
55 if (DfxGetKernelStack(tid, threadKernelStack) == 0 && FormatThreadKernelStack(threadKernelStack, threadStack)) {
56 DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid);
57 if (IsBetaVersion()) {
58 DFXLOGI("%{public}s", threadKernelStack.c_str());
59 }
60 thread->SetParseSymbolNecessity(false);
61 thread->SetFrames(threadStack.frames);
62 }
63 }
64 }
65
GetInstance()66 DfxUnwindRemote &DfxUnwindRemote::GetInstance()
67 {
68 static DfxUnwindRemote ins;
69 return ins;
70 }
71
ParseSymbol(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder)72 void DfxUnwindRemote::ParseSymbol(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
73 std::shared_ptr<Unwinder> unwinder)
74 {
75 if (request == nullptr || process == nullptr || unwinder == nullptr) {
76 return;
77 }
78
79 std::shared_ptr<DfxThread> unwThread = process->keyThread_;
80 DFX_TRACE_START("ParseSymbol keyThread:%d", unwThread->threadInfo_.nsTid);
81 unwThread->ParseSymbol(unwinder);
82 DFX_TRACE_FINISH();
83 if (ProcessDumper::GetInstance().IsCrash() || request->siginfo.si_value.sival_int == 0) {
84 for (auto &thread : process->GetOtherThreads()) {
85 DFX_TRACE_START("ParseSymbol otherThread:%d", thread->threadInfo_.nsTid);
86 thread->ParseSymbol(unwinder);
87 DFX_TRACE_FINISH();
88 }
89 }
90 }
91
PrintUnwindResultInfo(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder,pid_t vmPid)92 void DfxUnwindRemote::PrintUnwindResultInfo(std::shared_ptr<ProcessDumpRequest> request,
93 std::shared_ptr<DfxProcess> process,
94 std::shared_ptr<Unwinder> unwinder,
95 pid_t vmPid)
96 {
97 if (request == nullptr || process == nullptr || unwinder == nullptr) {
98 return;
99 }
100
101 // print key thread
102 Printer::PrintDumpHeader(request, process, unwinder);
103 Printer::PrintThreadHeaderByConfig(process->keyThread_, true);
104 Printer::PrintThreadBacktraceByConfig(process->keyThread_, true);
105 if (ProcessDumper::GetInstance().IsCrash()) {
106 Printer::PrintRegsByConfig(process->regs_);
107 Printer::PrintLongInformation(process->extraCrashInfo);
108 }
109
110 // print other thread
111 if (ProcessDumper::GetInstance().IsCrash() || request->siginfo.si_value.sival_int == 0) {
112 size_t index = 0;
113 for (auto &thread : process->GetOtherThreads()) {
114 if ((index == 0) && ProcessDumper::GetInstance().IsCrash()) {
115 Printer::PrintOtherThreadHeaderByConfig();
116 }
117 Printer::PrintThreadHeaderByConfig(thread, false);
118 Printer::PrintThreadBacktraceByConfig(thread, false);
119 index++;
120 }
121 }
122
123 if (ProcessDumper::GetInstance().IsCrash()) {
124 if (process->keyThread_ == nullptr) {
125 DFXLOGW("%{public}s::unwind key thread is not initialized.", __func__);
126 } else {
127 pid_t nsTid = process->keyThread_->threadInfo_.nsTid;
128 process->keyThread_->threadInfo_.nsTid = vmPid; // read registers from vm process
129 Printer::PrintThreadFaultStackByConfig(process->keyThread_);
130 process->keyThread_->threadInfo_.nsTid = nsTid;
131 }
132 Printer::PrintProcessMapsByConfig(unwinder->GetMaps());
133 Printer::PrintLongInformation(process->openFiles);
134 }
135 }
136
UnwindProcess(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder,pid_t vmPid)137 bool DfxUnwindRemote::UnwindProcess(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
138 std::shared_ptr<Unwinder> unwinder, pid_t vmPid)
139 {
140 DFX_TRACE_SCOPED("UnwindProcess");
141 if (process == nullptr || unwinder == nullptr) {
142 DFXLOGW("%{public}s::process or unwinder is not initialized.", __func__);
143 return false;
144 }
145
146 unwinder->EnableFillFrames(false);
147 SetCrashProcInfo(process->processInfo_.processName, process->processInfo_.pid,
148 process->processInfo_.uid);
149 int unwCnt = UnwindKeyThread(request, process, unwinder, vmPid) ? 1 : 0;
150
151 // dumpt -p -t will not unwind other thread
152 if (ProcessDumper::GetInstance().IsCrash() || request->siginfo.si_value.sival_int == 0) {
153 unwCnt += UnwindOtherThread(process, unwinder, vmPid);
154 }
155
156 if (ProcessDumper::GetInstance().IsCrash() && process->keyThread_ != nullptr) {
157 pid_t nsTid = process->keyThread_->threadInfo_.nsTid;
158 process->keyThread_->threadInfo_.nsTid = vmPid; // read registers from vm process
159 Printer::CollectThreadFaultStackByConfig(process, process->keyThread_, unwinder);
160 process->keyThread_->threadInfo_.nsTid = nsTid;
161 }
162 DFXLOGI("success unwind thread cnt is %{public}d", unwCnt);
163 return unwCnt > 0;
164 }
165
UnwindKeyThread(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder,pid_t vmPid)166 bool DfxUnwindRemote::UnwindKeyThread(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
167 std::shared_ptr<Unwinder> unwinder, pid_t vmPid)
168 {
169 bool result = false;
170 std::shared_ptr<DfxThread> unwThread = process->keyThread_;
171 if (unwThread == nullptr) {
172 DFXLOGW("%{public}s::unwind thread is not initialized.", __func__);
173 return false;
174 }
175 if (request == nullptr) {
176 DFXLOGW("%{public}s::request is not initialized.", __func__);
177 return false;
178 }
179 unwinder->SetIsJitCrashFlag(ProcessDumper::GetInstance().IsCrash());
180 auto unwindAsyncThread = std::make_shared<DfxUnwindAsyncThread>(unwThread, unwinder, request->stackId);
181 if ((vmPid != 0)) {
182 isVmProcAttach = true;
183 if (unwThread->GetThreadRegs() != nullptr) {
184 result = unwindAsyncThread->UnwindStack(vmPid);
185 } else {
186 GetThreadKernelStack(unwThread);
187 }
188 } else {
189 result = unwindAsyncThread->UnwindStack();
190 }
191
192 if (!unwindAsyncThread->unwindFailTip.empty()) {
193 ReportCrashException(process->processInfo_.processName, process->processInfo_.pid,
194 process->processInfo_.uid, CrashExceptionCode::CRASH_UNWIND_ESTACK);
195 process->SetFatalMessage(unwindAsyncThread->unwindFailTip);
196 }
197 if (ProcessDumper::GetInstance().IsCrash()) {
198 // Registers of unwThread has been changed, we should print regs from request context.
199 process->regs_ = DfxRegs::CreateFromUcontext(request->context);
200 }
201 return result;
202 }
203
UnwindOtherThread(std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder,pid_t vmPid)204 int DfxUnwindRemote::UnwindOtherThread(std::shared_ptr<DfxProcess> process, std::shared_ptr<Unwinder> unwinder,
205 pid_t vmPid)
206 {
207 if ((!DfxConfig::GetConfig().dumpOtherThreads) || (vmPid != 0 && !isVmProcAttach)) {
208 return 0;
209 }
210 unwinder->SetIsJitCrashFlag(false);
211 int unwCnt = 0;
212 for (auto &thread : process->GetOtherThreads()) {
213 if (isVmProcAttach || thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT)) {
214 auto regs = thread->GetThreadRegs();
215 unwinder->SetRegs(regs);
216 bool withRegs = regs != nullptr;
217 pid_t tid = thread->threadInfo_.nsTid;
218 DFXLOGD("%{public}s, unwind tid(%{public}d) start", __func__, tid);
219 if (isVmProcAttach && !withRegs) {
220 GetThreadKernelStack(thread);
221 continue;
222 }
223 auto pid = (vmPid != 0 && isVmProcAttach) ? vmPid : tid;
224 DFX_TRACE_START("OtherThreadUnwindRemote:%d", tid);
225 bool ret = unwinder->UnwindRemote(pid, withRegs, DfxConfig::GetConfig().maxFrameNums);
226 DFX_TRACE_FINISH();
227 DFX_TRACE_START("OtherThreadGetFrames:%d", tid);
228 thread->SetFrames(unwinder->GetFrames());
229 DFX_TRACE_FINISH();
230 #ifdef PARSE_LOCK_OWNER
231 LockParser::ParseLockInfo(unwinder, pid, tid);
232 #endif
233 if (ProcessDumper::GetInstance().IsCrash()) {
234 ReportUnwinderException(unwinder->GetLastErrorCode());
235 }
236 if (!ret) {
237 DFXLOGW("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret);
238 } else {
239 unwCnt++;
240 }
241 }
242 }
243 return unwCnt;
244 }
245
InitTargetKeyThreadRegs(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process)246 bool DfxUnwindRemote::InitTargetKeyThreadRegs(std::shared_ptr<ProcessDumpRequest> request,
247 std::shared_ptr<DfxProcess> process)
248 {
249 auto regs = DfxRegs::CreateFromUcontext(request->context);
250 if (regs == nullptr) {
251 return false;
252 }
253 process->keyThread_->SetThreadRegs(regs);
254 return true;
255 }
256
InitOtherThreadRegs(std::shared_ptr<DfxProcess> process)257 void DfxUnwindRemote::InitOtherThreadRegs(std::shared_ptr<DfxProcess> process)
258 {
259 if (!DfxConfig::GetConfig().dumpOtherThreads) {
260 return;
261 }
262
263 for (auto &thread : process->GetOtherThreads()) {
264 if (thread->Attach(PTRACE_ATTATCH_OTHER_THREAD_TIMEOUT)) {
265 thread->SetThreadRegs(DfxRegs::CreateRemoteRegs(thread->threadInfo_.nsTid));
266 }
267 }
268 }
269
InitProcessAllThreadRegs(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process)270 bool DfxUnwindRemote::InitProcessAllThreadRegs(std::shared_ptr<ProcessDumpRequest> request,
271 std::shared_ptr<DfxProcess> process)
272 {
273 if (!InitTargetKeyThreadRegs(request, process)) {
274 DFXLOGE("get key thread regs fail");
275 return false;
276 }
277 InitOtherThreadRegs(process);
278 return true;
279 }
280 } // namespace HiviewDFX
281 } // namespace OHOS
282