• 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_thread.h"
17 
18 #include <cerrno>
19 #include <chrono>
20 #include <climits>
21 #include <cstring>
22 #include <securec.h>
23 #include <sstream>
24 #include <sys/ptrace.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include "dfx_config.h"
28 #include "dfx_define.h"
29 #include "dfx_frame_format.h"
30 #include "dfx_log.h"
31 #include "dfx_util.h"
32 #include "procinfo.h"
33 
34 namespace OHOS {
35 namespace HiviewDFX {
Create(pid_t pid,pid_t tid,pid_t nsTid)36 std::shared_ptr<DfxThread> DfxThread::Create(pid_t pid, pid_t tid, pid_t nsTid)
37 {
38     auto thread = std::make_shared<DfxThread>(pid, tid, nsTid);
39     return thread;
40 }
41 
DfxThread(pid_t pid,pid_t tid,pid_t nsTid)42 DfxThread::DfxThread(pid_t pid, pid_t tid, pid_t nsTid) : regs_(nullptr)
43 {
44     InitThreadInfo(pid, tid, nsTid);
45 }
46 
InitThreadInfo(pid_t pid,pid_t tid,pid_t nsTid)47 void DfxThread::InitThreadInfo(pid_t pid, pid_t tid, pid_t nsTid)
48 {
49     threadInfo_.pid = pid;
50     threadInfo_.tid = tid;
51     threadInfo_.nsTid = nsTid;
52     ReadThreadName(threadInfo_.tid, threadInfo_.threadName);
53     threadStatus = ThreadStatus::THREAD_STATUS_INIT;
54 }
55 
~DfxThread()56 DfxThread::~DfxThread()
57 {
58     threadStatus = ThreadStatus::THREAD_STATUS_INVALID;
59 }
60 
GetThreadRegs() const61 std::shared_ptr<DfxRegs> DfxThread::GetThreadRegs() const
62 {
63     return regs_;
64 }
65 
SetThreadRegs(const std::shared_ptr<DfxRegs> & regs)66 void DfxThread::SetThreadRegs(const std::shared_ptr<DfxRegs> &regs)
67 {
68     regs_ = regs;
69 }
70 
AddFrame(std::shared_ptr<DfxFrame> frame)71 void DfxThread::AddFrame(std::shared_ptr<DfxFrame> frame)
72 {
73     frames_.push_back(frame);
74 }
75 
GetFrames() const76 const std::vector<std::shared_ptr<DfxFrame>>& DfxThread::GetFrames() const
77 {
78     return frames_;
79 }
80 
ToString() const81 std::string DfxThread::ToString() const
82 {
83     if (frames_.size() == 0) {
84         return "No frame info";
85     }
86 
87     std::stringstream ss;
88     ss << "Thread name:" << threadInfo_.threadName << "" << std::endl;
89     for (size_t i = 0; i < frames_.size(); i++) {
90         if (frames_[i] == nullptr) {
91             continue;
92         }
93         ss << DfxFrameFormat::GetFrameStr(frames_[i]);
94     }
95     return ss.str();
96 }
97 
Detach()98 void DfxThread::Detach()
99 {
100     if (threadStatus == ThreadStatus::THREAD_STATUS_ATTACHED) {
101         ptrace(PTRACE_CONT, threadInfo_.nsTid, 0, 0);
102         ptrace(PTRACE_DETACH, threadInfo_.nsTid, NULL, NULL);
103         threadStatus = ThreadStatus::THREAD_STATUS_INIT;
104     }
105 }
106 
Attach()107 bool DfxThread::Attach()
108 {
109     if (threadStatus == ThreadStatus::THREAD_STATUS_ATTACHED) {
110         return true;
111     }
112 
113     if (ptrace(PTRACE_SEIZE, threadInfo_.nsTid, 0, 0) != 0) {
114         DFXLOG_WARN("Failed to seize thread(%d:%d) from (%d:%d), errno=%d",
115             threadInfo_.tid, threadInfo_.nsTid, getuid(), getgid(), errno);
116         return false;
117     }
118 
119     if (ptrace(PTRACE_INTERRUPT, threadInfo_.nsTid, 0, 0) != 0) {
120         DFXLOG_WARN("Failed to interrupt thread(%d:%d) from (%d:%d), errno=%d",
121             threadInfo_.tid, threadInfo_.nsTid, getuid(), getgid(), errno);
122         ptrace(PTRACE_DETACH, threadInfo_.nsTid, NULL, NULL);
123         return false;
124     }
125 
126     int64_t startTime = std::chrono::duration_cast<std::chrono::milliseconds>(
127         std::chrono::system_clock::now().time_since_epoch()).count();
128     do {
129         if (waitpid(threadInfo_.nsTid, nullptr, WNOHANG) > 0) {
130             break;
131         }
132         int64_t curTime = std::chrono::duration_cast<std::chrono::milliseconds>(
133             std::chrono::system_clock::now().time_since_epoch()).count();
134         if (curTime - startTime > 1000) { // 1000 : 1s timeout
135             ptrace(PTRACE_DETACH, threadInfo_.nsTid, NULL, NULL);
136             DFXLOG_WARN("Failed to wait thread(%d:%d) attached.", threadInfo_.tid, threadInfo_.nsTid);
137             return false;
138         }
139         usleep(5); // 5 : sleep 5us
140     } while (true);
141     threadStatus = ThreadStatus::THREAD_STATUS_ATTACHED;
142     return true;
143 }
144 } // namespace HiviewDFX
145 } // nampespace OHOS
146