1 /*
2 * Copyright (c) 2021-2024 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_maps.h"
17
18 #include <algorithm>
19 #include <cstring>
20 #include <securec.h>
21 #if is_mingw
22 #include "dfx_nonlinux_define.h"
23 #else
24 #include <sys/mman.h>
25 #endif
26
27 #include "dfx_define.h"
28 #include "dfx_elf.h"
29 #include "dfx_log.h"
30 #include "dfx_trace_dlsym.h"
31 #include "string_printf.h"
32 #include "string_util.h"
33
34 namespace OHOS {
35 namespace HiviewDFX {
36 namespace {
37 #undef LOG_DOMAIN
38 #undef LOG_TAG
39 #define LOG_DOMAIN 0xD002D11
40 #define LOG_TAG "DfxMaps"
41
GetMapsFile(pid_t pid)42 inline const std::string GetMapsFile(pid_t pid)
43 {
44 std::string path = "";
45 if ((pid == 0) || (pid == getpid())) {
46 path = std::string(PROC_SELF_MAPS_PATH);
47 } else if (pid > 0) {
48 path = StringPrintf("/proc/%d/maps", (int)pid);
49 }
50 return path;
51 }
52 }
53
Create(pid_t pid,bool crash)54 std::shared_ptr<DfxMaps> DfxMaps::Create(pid_t pid, bool crash)
55 {
56 std::string path = GetMapsFile(pid);
57 if (path == "") {
58 return nullptr;
59 }
60 auto dfxMaps = std::make_shared<DfxMaps>();
61 if (!crash) {
62 DFXLOGU("Create maps(%{public}s) with not crash, will only parse exec map", path.c_str());
63 dfxMaps->EnableOnlyExec(true);
64 }
65 if (dfxMaps->Parse(pid, path)) {
66 return dfxMaps;
67 }
68 return nullptr;
69 }
70
Create(const pid_t pid,const std::string & path)71 std::shared_ptr<DfxMaps> DfxMaps::Create(const pid_t pid, const std::string& path)
72 {
73 auto dfxMaps = std::make_shared<DfxMaps>();
74 if (dfxMaps->Parse(pid, path)) {
75 return dfxMaps;
76 }
77 return nullptr;
78 }
79
Create(const pid_t pid,std::vector<std::shared_ptr<DfxMap>> & maps,std::vector<int> & mapIndex)80 bool DfxMaps::Create(const pid_t pid, std::vector<std::shared_ptr<DfxMap>>& maps, std::vector<int>& mapIndex)
81 {
82 std::string path = GetMapsFile(pid);
83 if (path == "") {
84 return false;
85 }
86 auto dfxMaps = std::make_shared<DfxMaps>();
87 dfxMaps->EnableMapIndex(true);
88 if (!dfxMaps->Parse(pid, path)) {
89 return false;
90 }
91 maps = dfxMaps->GetMaps();
92 mapIndex = dfxMaps->GetMapIndexVec();
93 return true;
94 }
95
Parse(const pid_t pid,const std::string & path)96 bool DfxMaps::Parse(const pid_t pid, const std::string& path)
97 {
98 DFX_TRACE_SCOPED_DLSYM("ParseMaps");
99 if ((pid < 0) || (path == "")) {
100 DFXLOGE("param is error");
101 return false;
102 }
103
104 FILE* fp = nullptr;
105 fp = fopen(path.c_str(), "r");
106 if (fp == nullptr) {
107 DFXLOGE("Failed to open %{public}s, err=%{public}d", path.c_str(), errno);
108 return false;
109 }
110
111 char mapBuf[PATH_LEN] = {0};
112 int fgetCount = 0;
113 while (fgets(mapBuf, sizeof(mapBuf), fp) != nullptr) {
114 fgetCount++;
115 auto map = std::make_shared<DfxMap>();
116 if (!map->Parse(mapBuf, sizeof(mapBuf))) {
117 DFXLOGU("Failed to parse map: %{public}s", mapBuf);
118 continue;
119 }
120
121 DfxMap::FormatMapName(pid, map->name);
122 if (IsArkHapMapItem(map->name) || IsArkCodeMapItem(map->name)) {
123 AddMap(map, enableMapIndex_);
124 continue;
125 }
126 HandleSpecialMap(map);
127
128 if (onlyExec_ && !map->IsMapExec()) {
129 continue;
130 }
131 if ((!enableMapIndex_) || IsLegalMapItem(map->name, false)) {
132 AddMap(map, enableMapIndex_);
133 }
134 }
135 (void)fclose(fp);
136 if (fgetCount == 0) {
137 DFXLOGE("Failed to get maps(%{public}s), err(%{public}d).", path.c_str(), errno);
138 return false;
139 }
140 size_t mapsSize = GetMapsSize();
141 DFXLOGU("parse maps(%{public}s) completed, map size: (%{public}zu), count: (%{public}d)",
142 path.c_str(), mapsSize, fgetCount);
143 return mapsSize > 0;
144 }
145
HandleSpecialMap(const std::shared_ptr<DfxMap> & map)146 void DfxMaps::HandleSpecialMap(const std::shared_ptr<DfxMap>& map)
147 {
148 if (map == nullptr) {
149 return;
150 }
151 if (map->name == "[stack]") {
152 stackBottom_ = static_cast<uintptr_t>(map->begin);
153 stackTop_ = static_cast<uintptr_t>(map->end);
154 }
155 if (map->IsArkExecutable()) {
156 ArkStackStart_ = static_cast<uintptr_t>(map->begin);
157 ArkStackEnd_ = static_cast<uintptr_t>(map->end);
158 }
159 }
160
IsArkHapMapItem(const std::string & name)161 bool DfxMaps::IsArkHapMapItem(const std::string& name)
162 {
163 if (name.empty()) {
164 return false;
165 }
166 if (EndsWith(name, ".hap") || EndsWith(name, ".hsp") || EndsWith(name, ".hqf")) {
167 return true;
168 }
169 return false;
170 }
171
IsArkCodeMapItem(const std::string & name)172 bool DfxMaps::IsArkCodeMapItem(const std::string& name)
173 {
174 if (name.empty()) {
175 return false;
176 }
177 if (StartsWith(name, "[anon:ArkTS Code") || EndsWith(name, ".abc")) {
178 return true;
179 }
180 return false;
181 }
182
IsLegalMapItem(const std::string & name,bool withArk)183 bool DfxMaps::IsLegalMapItem(const std::string& name, bool withArk)
184 {
185 // some special
186 if (withArk && (IsArkHapMapItem(name) || IsArkCodeMapItem(name))) {
187 return true;
188 }
189 if (EndsWith(name, "[vdso]") || EndsWith(name, "[shmm]")) {
190 return true;
191 }
192 if (name.empty() || name.find(':') != std::string::npos || name.front() == '[' ||
193 name.back() == ']' || std::strncmp(name.c_str(), "/dev/", sizeof("/dev/")) == 0 ||
194 std::strncmp(name.c_str(), "/memfd:", sizeof("/memfd:")) == 0 ||
195 std::strncmp(name.c_str(), "//anon", sizeof("//anon")) == 0 ||
196 EndsWith(name, ".ttf") || EndsWith(name, ".ai")) {
197 return false;
198 }
199 return true;
200 }
201
AddMap(std::shared_ptr<DfxMap> map,bool enableMapIndex)202 void DfxMaps::AddMap(std::shared_ptr<DfxMap> map, bool enableMapIndex)
203 {
204 maps_.emplace_back(std::move(map));
205 if (enableMapIndex && !maps_.empty()) {
206 mapIndex_.emplace_back(maps_.size() - 1);
207 }
208 }
209
FindMapByAddr(uintptr_t addr,std::shared_ptr<DfxMap> & map) const210 bool DfxMaps::FindMapByAddr(uintptr_t addr, std::shared_ptr<DfxMap>& map) const
211 {
212 if ((maps_.empty()) || (addr == 0x0)) {
213 return false;
214 }
215
216 size_t first = 0;
217 size_t last = maps_.size();
218 while (first < last) {
219 size_t index = (first + last) / 2;
220 const auto& cur = maps_[index];
221 if (cur == nullptr) {
222 continue;
223 }
224 if (addr >= cur->begin && addr < cur->end) {
225 map = cur;
226 if (index > 0) {
227 map->prevMap = maps_[index - 1];
228 }
229 return true;
230 } else if (addr < cur->begin) {
231 last = index;
232 } else {
233 first = index + 1;
234 }
235 }
236 return false;
237 }
238
FindMapByFileInfo(std::string name,uint64_t offset,std::shared_ptr<DfxMap> & map) const239 bool DfxMaps::FindMapByFileInfo(std::string name, uint64_t offset, std::shared_ptr<DfxMap>& map) const
240 {
241 for (auto &iter : maps_) {
242 if (name != iter->name) {
243 continue;
244 }
245
246 if (offset >= iter->offset && (offset - iter->offset) < (iter->end - iter->begin)) {
247 DFXLOGI("Found name: %{public}s, offset 0x%{public}" PRIx64 " in map " \
248 "(%{public}" PRIx64 "-%{public}" PRIx64 " offset 0x%{public}" PRIx64 ")",
249 name.c_str(), offset, iter->begin, iter->end, iter->offset);
250 map = iter;
251 return true;
252 }
253 }
254 return false;
255 }
256
FindMapsByName(std::string name,std::vector<std::shared_ptr<DfxMap>> & maps) const257 bool DfxMaps::FindMapsByName(std::string name, std::vector<std::shared_ptr<DfxMap>>& maps) const
258 {
259 if (maps_.empty()) {
260 return false;
261 }
262 for (auto &iter : maps_) {
263 if (EndsWith(iter->name, name)) {
264 maps.emplace_back(iter);
265 }
266 }
267 return (maps.size() > 0);
268 }
269
Sort(bool less)270 void DfxMaps::Sort(bool less)
271 {
272 if (maps_.empty()) {
273 return;
274 }
275 if (less) {
276 std::sort(maps_.begin(), maps_.end(),
277 [](const std::shared_ptr<DfxMap>& a, const std::shared_ptr<DfxMap>& b) {
278 if (a == nullptr) {
279 return false;
280 } else if (b == nullptr) {
281 return true;
282 }
283 return a->begin < b->begin;
284 });
285 } else {
286 std::sort(maps_.begin(), maps_.end(),
287 [](const std::shared_ptr<DfxMap>& a, const std::shared_ptr<DfxMap>& b) {
288 if (a == nullptr) {
289 return true;
290 } else if (b == nullptr) {
291 return false;
292 }
293 return a->begin > b->begin;
294 });
295 }
296 }
297
GetStackRange(uintptr_t & bottom,uintptr_t & top)298 bool DfxMaps::GetStackRange(uintptr_t& bottom, uintptr_t& top)
299 {
300 if (stackBottom_ == 0 || stackTop_ == 0) {
301 return false;
302 }
303 bottom = stackBottom_;
304 top = stackTop_;
305 return true;
306 }
307
GetArkStackRange(uintptr_t & start,uintptr_t & end)308 bool DfxMaps::GetArkStackRange(uintptr_t& start, uintptr_t& end)
309 {
310 if (ArkStackStart_ == 0 || ArkStackEnd_ == 0) {
311 return false;
312 }
313 start = ArkStackStart_;
314 end = ArkStackEnd_;
315 return true;
316 }
317
IsArkExecutedMap(uintptr_t addr)318 bool DfxMaps::IsArkExecutedMap(uintptr_t addr)
319 {
320 std::shared_ptr<DfxMap> map = nullptr;
321 if (!FindMapByAddr(addr, map)) {
322 DFXLOGU("Not mapped map for current addr.");
323 return false;
324 }
325 return map->IsArkExecutable();
326 }
327 } // namespace HiviewDFX
328 } // namespace OHOS
329