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> ®s)
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