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 "catchframe_local.h"
17
18 #include <cerrno>
19 #include <climits>
20 #include <csignal>
21 #include <cstdlib>
22 #include <cstring>
23 #include <ctime>
24 #include <memory>
25
26 #include <dirent.h>
27 #include <unistd.h>
28
29 #include <sys/types.h>
30
31 #include "dfx_define.h"
32 #include "dfx_log.h"
33 #include "dfx_util.h"
34 #include "securec.h"
35 #include "strings.h"
36 #include "libunwind.h"
37 #include "libunwind_i-ohos.h"
38 #include "dfx_symbols.h"
39 #include "backtrace_local_context.h"
40 #include "backtrace_local_thread.h"
41 // forward declaration
42 struct unw_addr_space;
43 typedef struct unw_addr_space *unw_addr_space_t;
44 namespace OHOS {
45 namespace HiviewDFX {
46 unw_addr_space_t as_ {nullptr};
47 std::shared_ptr<DfxSymbols> symbol_ {nullptr};
48
DfxCatchFrameLocal()49 DfxCatchFrameLocal::DfxCatchFrameLocal()
50 {
51 pid_ = 0;
52 (void)GetProcStatus(procInfo_);
53 }
54
DfxCatchFrameLocal(int32_t pid)55 DfxCatchFrameLocal::DfxCatchFrameLocal(int32_t pid) : pid_(pid)
56 {
57 (void)GetProcStatus(procInfo_);
58 }
59
~DfxCatchFrameLocal()60 DfxCatchFrameLocal::~DfxCatchFrameLocal()
61 {
62 BacktraceLocalContext::GetInstance().CleanUp();
63 }
64
InitFrameCatcher()65 bool DfxCatchFrameLocal::InitFrameCatcher()
66 {
67 std::unique_lock<std::mutex> lck(mutex_);
68 if (as_ != nullptr) {
69 return true;
70 }
71
72 unw_init_local_address_space(&as_);
73 if (as_ == nullptr) {
74 return false;
75 }
76
77 symbol_ = std::make_shared<DfxSymbols>();
78 return true;
79 }
80
DestroyFrameCatcher()81 void DfxCatchFrameLocal::DestroyFrameCatcher()
82 {
83 std::unique_lock<std::mutex> lck(mutex_);
84 if (as_ != nullptr) {
85 unw_destroy_local_address_space(as_);
86 as_ = nullptr;
87 }
88 symbol_ = nullptr;
89 }
90
ReleaseThread(int tid)91 bool DfxCatchFrameLocal::ReleaseThread(int tid)
92 {
93 BacktraceLocalContext::GetInstance().ReleaseThread(tid);
94 return true;
95 }
96
CatchFrame(std::map<int,std::vector<DfxFrame>> & mapFrames,bool releaseThread)97 bool DfxCatchFrameLocal::CatchFrame(std::map<int, std::vector<DfxFrame>>& mapFrames, bool releaseThread)
98 {
99 if (as_ == nullptr || symbol_ == nullptr) {
100 return false;
101 }
102
103 if (pid_ != procInfo_.pid) {
104 DFXLOG_ERROR("CatchFrame :: only support local pid.");
105 return false;
106 }
107
108 std::vector<int> tids;
109 std::vector<int> nstids;
110 if (!GetTidsByPid(pid_, tids, nstids)) {
111 return false;
112 }
113
114 std::vector<DfxFrame> frames;
115 for (size_t i = 0; i < nstids.size(); ++i) {
116 if (tids[i] == gettid()) {
117 CatchFrameCurrTid(frames, releaseThread);
118 } else {
119 CatchFrameLocalTid(nstids[i], frames, releaseThread);
120 }
121 mapFrames[nstids[i]] = frames;
122 }
123 return (mapFrames.size() > 0);
124 }
125
CatchFrame(int tid,std::vector<DfxFrame> & frames,bool releaseThread)126 bool DfxCatchFrameLocal::CatchFrame(int tid, std::vector<DfxFrame>& frames, bool releaseThread)
127 {
128 if (as_ == nullptr || symbol_ == nullptr) {
129 return false;
130 }
131
132 if (tid <= 0 || pid_ != procInfo_.pid) {
133 DFXLOG_ERROR("CatchFrame :: only support local pid.");
134 return false;
135 }
136
137 if (tid == gettid()) {
138 return CatchFrameCurrTid(frames, releaseThread);
139 }
140
141 int nstid = tid;
142 if (procInfo_.ns) {
143 TidToNstid(pid_, tid, nstid);
144 } else {
145 if (!IsThreadInPid(pid_, nstid)) {
146 DFXLOG_ERROR("CatchFrame :: target tid is not in our task.");
147 return false;
148 }
149 }
150 return CatchFrameLocalTid(nstid, frames, releaseThread);
151 }
152
CatchFrameCurrTid(std::vector<DfxFrame> & frames,bool releaseThread)153 bool DfxCatchFrameLocal::CatchFrameCurrTid(std::vector<DfxFrame>& frames, bool releaseThread)
154 {
155 std::unique_lock<std::mutex> lck(mutex_);
156
157 int skipFrameNum = 1; // skip current frame
158 BacktraceLocalThread thread(BACKTRACE_CURRENT_THREAD);
159 if (!thread.Unwind(as_, symbol_, skipFrameNum, false, releaseThread)) {
160 return false;
161 }
162
163 frames.clear();
164 frames = thread.GetFrames();
165 return true;
166 }
167
CatchFrameLocalTid(int tid,std::vector<DfxFrame> & frames,bool releaseThread)168 bool DfxCatchFrameLocal::CatchFrameLocalTid(int tid, std::vector<DfxFrame>& frames, bool releaseThread)
169 {
170 std::unique_lock<std::mutex> lck(mutex_);
171
172 int skipFrameNum = 1; // skip current frame
173 BacktraceLocalThread thread(tid);
174 if (!thread.Unwind(as_, symbol_, skipFrameNum, false, releaseThread)) {
175 return false;
176 }
177
178 frames.clear();
179 frames = thread.GetFrames();
180 return true;
181 }
182 } // namespace HiviewDFX
183 } // namespace OHOS
184