• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 /* This files contains process dump thread module. */
17 
18 #include "dfx_thread.h"
19 
20 #include <cerrno>
21 #include <climits>
22 #include <cstring>
23 #include <securec.h>
24 #include <sstream>
25 #include <sys/ptrace.h>
26 #include <sys/wait.h>
27 #include "dfx_config.h"
28 #include "dfx_define.h"
29 #include "dfx_fault_stack.h"
30 #include "dfx_logger.h"
31 #include "dfx_regs.h"
32 #include "dfx_util.h"
33 
34 namespace OHOS {
35 namespace HiviewDFX {
DfxThread(pid_t pid,pid_t tid,pid_t nsTid,const ucontext_t & context)36 DfxThread::DfxThread(pid_t pid, pid_t tid, pid_t nsTid, const ucontext_t &context)
37     :isCrashThread_(false), pid_(pid), tid_(tid), nsTid_(nsTid), unwStopReason_(-1)
38 {
39     threadStatus_ = ThreadStatus::THREAD_STATUS_INVALID;
40     std::shared_ptr<DfxRegs> reg;
41 #if defined(__arm__)
42     reg = std::make_shared<DfxRegsArm>(context);
43 #elif defined(__aarch64__)
44     reg = std::make_shared<DfxRegsArm64>(context);
45 #elif defined(__x86_64__)
46     reg = std::make_shared<DfxRegsX86_64>(context);
47 #endif
48     regs_ = reg;
49 
50     ReadThreadName();
51     threadStatus_ = ThreadStatus::THREAD_STATUS_INIT;
52 }
53 
DfxThread(pid_t pid,pid_t tid,pid_t nsTid)54 DfxThread::DfxThread(pid_t pid, pid_t tid, pid_t nsTid)
55     :isCrashThread_(false), pid_(pid), tid_(tid), nsTid_(nsTid), unwStopReason_(-1)
56 {
57     regs_ = nullptr;
58     ReadThreadName();
59     threadStatus_ = ThreadStatus::THREAD_STATUS_INIT;
60 }
61 
ReadThreadName()62 void DfxThread::ReadThreadName()
63 {
64     char path[NAME_LEN] = {0};
65     if (snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%d/comm", tid_) <= 0) {
66         return;
67     }
68 
69     std::string pathName = path;
70     std::string buf;
71     ReadStringFromFile(pathName, buf, NAME_LEN);
72     TrimAndDupStr(buf, threadName_);
73 }
74 
IsThreadInitialized()75 bool DfxThread::IsThreadInitialized()
76 {
77     return threadStatus_ == ThreadStatus::THREAD_STATUS_ATTACHED;
78 }
79 
~DfxThread()80 DfxThread::~DfxThread()
81 {
82     threadStatus_ = ThreadStatus::THREAD_STATUS_INVALID;
83 }
84 
GetIsCrashThread() const85 bool DfxThread::GetIsCrashThread() const
86 {
87     return isCrashThread_;
88 }
89 
SetIsCrashThread(bool isCrashThread)90 void DfxThread::SetIsCrashThread(bool isCrashThread)
91 {
92     isCrashThread_ = isCrashThread;
93 }
94 
GetProcessId() const95 pid_t DfxThread::GetProcessId() const
96 {
97     return pid_;
98 }
99 
GetThreadId() const100 pid_t DfxThread::GetThreadId() const
101 {
102     return tid_;
103 }
104 
GetThreadName() const105 std::string DfxThread::GetThreadName() const
106 {
107     return threadName_;
108 }
109 
SetThreadName(const std::string & threadName)110 void DfxThread::SetThreadName(const std::string &threadName)
111 {
112     threadName_ = threadName;
113 }
114 
GetThreadRegs() const115 std::shared_ptr<DfxRegs> DfxThread::GetThreadRegs() const
116 {
117     return regs_;
118 }
119 
GetThreadDfxFrames() const120 std::vector<std::shared_ptr<DfxFrame>> DfxThread::GetThreadDfxFrames() const
121 {
122     return dfxFrames_;
123 }
124 
SetThreadRegs(const std::shared_ptr<DfxRegs> & regs)125 void DfxThread::SetThreadRegs(const std::shared_ptr<DfxRegs> &regs)
126 {
127     regs_ = regs;
128 }
129 
GetAvailableFrame()130 std::shared_ptr<DfxFrame> DfxThread::GetAvailableFrame()
131 {
132     std::shared_ptr<DfxFrame> frame = std::make_shared<DfxFrame>();
133     dfxFrames_.push_back(frame);
134     return frame;
135 }
136 
PrintThread(const int32_t fd,bool isSignalDump)137 void DfxThread::PrintThread(const int32_t fd, bool isSignalDump)
138 {
139     if (dfxFrames_.size() == 0) {
140         DfxLogWarn("No frame print for tid %d.", tid_);
141         return;
142     }
143 
144     PrintThreadBacktraceByConfig(fd);
145     if (isSignalDump == false) {
146         PrintThreadRegisterByConfig();
147         PrintThreadFaultStackByConfig();
148     }
149 }
150 
SetThreadUnwStopReason(int reason)151 void DfxThread::SetThreadUnwStopReason(int reason)
152 {
153     unwStopReason_ = reason;
154 }
155 
CreateFaultStack(int32_t vmPid)156 void DfxThread::CreateFaultStack(int32_t vmPid)
157 {
158     faultstack_ = std::unique_ptr<FaultStack>(new FaultStack(vmPid));
159     faultstack_->CollectStackInfo(regs_, dfxFrames_);
160 }
161 
Detach()162 void DfxThread::Detach()
163 {
164     if (threadStatus_ == ThreadStatus::THREAD_STATUS_ATTACHED) {
165         ptrace(PTRACE_CONT, nsTid_, 0, 0);
166         ptrace(PTRACE_DETACH, nsTid_, NULL, NULL);
167         threadStatus_ = ThreadStatus::THREAD_STATUS_DETACHED;
168     }
169 }
170 
GetRealTid() const171 pid_t DfxThread::GetRealTid() const
172 {
173     return nsTid_;
174 }
175 
SetThreadId(pid_t tid)176 void DfxThread::SetThreadId(pid_t tid)
177 {
178     tid_ = tid;
179 }
180 
Attach()181 bool DfxThread::Attach()
182 {
183     if (threadStatus_ == ThreadStatus::THREAD_STATUS_ATTACHED) {
184         return true;
185     }
186 
187     if (ptrace(PTRACE_SEIZE, nsTid_, 0, 0) != 0) {
188         DfxLogWarn("Failed to seize thread(%d:%d), errno=%d", tid_, nsTid_, errno);
189         return false;
190     }
191 
192     if (ptrace(PTRACE_INTERRUPT, nsTid_, 0, 0) != 0) {
193         DfxLogWarn("Failed to interrupt thread(%d:%d), errno=%d", tid_, nsTid_, errno);
194         ptrace(PTRACE_DETACH, nsTid_, NULL, NULL);
195         return false;
196     }
197 
198     errno = 0;
199     while (waitpid(nsTid_, nullptr, __WALL) < 0) {
200         if (EINTR != errno) {
201             ptrace(PTRACE_DETACH, nsTid_, NULL, NULL);
202             DfxLogWarn("Failed to wait thread(%d:%d) attached, errno=%d.", tid_, nsTid_, errno);
203             return false;
204         }
205         errno = 0;
206     }
207     threadStatus_ = ThreadStatus::THREAD_STATUS_ATTACHED;
208     return true;
209 }
210 
ToString() const211 std::string DfxThread::ToString() const
212 {
213     if (dfxFrames_.size() == 0) {
214         return "No frame info";
215     }
216 
217     std::stringstream threadInfoStream;
218     threadInfoStream << "Thread name:" << threadName_ << std::endl;
219     for (size_t i = 0; i < dfxFrames_.size(); i++) {
220         if (dfxFrames_[i] == nullptr) {
221             continue;
222         }
223         threadInfoStream << dfxFrames_[i]->ToString();
224     }
225 
226     return threadInfoStream.str();
227 }
228 
PrintThreadBacktraceByConfig(const int32_t fd)229 void DfxThread::PrintThreadBacktraceByConfig(const int32_t fd)
230 {
231     if (DfxConfig::GetInstance().GetDisplayBacktrace()) {
232         WriteLog(fd, "Tid:%d, Name:%s\n", tid_, threadName_.c_str());
233         PrintFrames(dfxFrames_);
234     } else {
235         DfxLogDebug("hidden backtrace");
236     }
237 }
238 
PrintThreadRegisterByConfig()239 std::string DfxThread::PrintThreadRegisterByConfig()
240 {
241     if (DfxConfig::GetInstance().GetDisplayRegister()) {
242         if (regs_) {
243             return regs_->PrintRegs();
244         }
245     } else {
246         DfxLogDebug("hidden register");
247     }
248     return "";
249 }
250 
PrintThreadFaultStackByConfig()251 void DfxThread::PrintThreadFaultStackByConfig()
252 {
253     if (DfxConfig::GetInstance().GetDisplayFaultStack() && isCrashThread_) {
254         if (faultstack_ != nullptr) {
255             faultstack_->Print();
256         }
257     } else {
258         DfxLogDebug("hidden faultStack");
259     }
260 }
261 
ClearLastFrame()262 void DfxThread::ClearLastFrame()
263 {
264     dfxFrames_.pop_back();
265 }
266 
AddFrame(std::shared_ptr<DfxFrame> frame)267 void DfxThread::AddFrame(std::shared_ptr<DfxFrame> frame)
268 {
269     dfxFrames_.push_back(frame);
270 }
271 } // namespace HiviewDFX
272 } // nampespace OHOS
273