• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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