• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <unistd.h>
22 #if is_mingw
23 #include "dfx_nonlinux_define.h"
24 #else
25 #include <sys/mman.h>
26 #endif
27 
28 #include "dfx_define.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     std::shared_ptr<DfxMap> prevMap = nullptr;
114     while (fgets(mapBuf, sizeof(mapBuf), fp) != nullptr) {
115         fgetCount++;
116         auto map = std::make_shared<DfxMap>();
117         if (!map->Parse(mapBuf, sizeof(mapBuf))) {
118             DFXLOGU("Failed to parse map: %{public}s", mapBuf);
119             continue;
120         }
121         DfxMap::FormatMapName(pid, map->name);
122         if (map->IsMapExec()) {
123             map->prevMap = prevMap;
124         }
125         prevMap = map;
126         if (IsArkHapMapItem(map->name) || IsArkCodeMapItem(map->name)) {
127             AddMap(map, enableMapIndex_);
128             continue;
129         }
130         HandleSpecialMap(map);
131         if (onlyExec_ && !map->IsMapExec()) {
132             continue;
133         }
134         if ((!enableMapIndex_) || IsLegalMapItem(map->name, false)) {
135             AddMap(map, enableMapIndex_);
136         }
137     }
138     (void)fclose(fp);
139     if (fgetCount == 0) {
140         DFXLOGE("Failed to get maps(%{public}s), err(%{public}d).", path.c_str(), errno);
141         return false;
142     }
143     size_t mapsSize = GetMapsSize();
144     DFXLOGU("parse maps(%{public}s) completed, map size: (%{public}zu), count: (%{public}d)",
145         path.c_str(), mapsSize, fgetCount);
146     return mapsSize > 0;
147 }
148 
HandleSpecialMap(const std::shared_ptr<DfxMap> & map)149 void DfxMaps::HandleSpecialMap(const std::shared_ptr<DfxMap>& map)
150 {
151     if (map == nullptr) {
152         return;
153     }
154     if (map->name == "[stack]") {
155         stackBottom_ = static_cast<uintptr_t>(map->begin);
156         stackTop_ = static_cast<uintptr_t>(map->end);
157     }
158     if (map->IsArkExecutable() || (map->IsMapExec() && map->name.find("stub.an") != std::string::npos)) {
159         ArkStackStart_ = static_cast<uintptr_t>(map->begin);
160         ArkStackEnd_ = static_cast<uintptr_t>(map->end);
161     }
162 }
163 
IsArkHapMapItem(const std::string & name)164 bool DfxMaps::IsArkHapMapItem(const std::string& name)
165 {
166     if (name.empty()) {
167         return false;
168     }
169     if (EndsWith(name, ".hap") || EndsWith(name, ".hsp") || EndsWith(name, ".hqf")) {
170         return true;
171     }
172     return false;
173 }
174 
IsArkCodeMapItem(const std::string & name)175 bool DfxMaps::IsArkCodeMapItem(const std::string& name)
176 {
177     if (name.empty()) {
178         return false;
179     }
180     if (StartsWith(name, "[anon:ArkTS Code") || EndsWith(name, ".abc")) {
181         return true;
182     }
183     return false;
184 }
185 
IsLegalMapItem(const std::string & name,bool withArk)186 bool DfxMaps::IsLegalMapItem(const std::string& name, bool withArk)
187 {
188     // some special
189     if (withArk && (IsArkHapMapItem(name) || IsArkCodeMapItem(name))) {
190         return true;
191     }
192     if (EndsWith(name, "[vdso]") || EndsWith(name, "[shmm]")) {
193         return true;
194     }
195 
196     if (StartsWith(name, "[anon:JSVM_JIT") || StartsWith(name, "[anon:ARKWEB_JIT") || StartsWith(name, "[anon:v8")) {
197         return true;
198     }
199     if (name.empty() || name.find(':') != std::string::npos || name.front() == '[' ||
200         name.back() == ']' || std::strncmp(name.c_str(), "/dev/", sizeof("/dev/")) == 0 ||
201         std::strncmp(name.c_str(), "/memfd:", sizeof("/memfd:")) == 0 ||
202         std::strncmp(name.c_str(), "//anon", sizeof("//anon")) == 0 ||
203         EndsWith(name, ".ttf") || EndsWith(name, ".ai")) {
204         return false;
205     }
206     return true;
207 }
208 
AddMap(std::shared_ptr<DfxMap> map,bool enableMapIndex)209 void DfxMaps::AddMap(std::shared_ptr<DfxMap> map, bool enableMapIndex)
210 {
211     maps_.emplace_back(std::move(map));
212     if (enableMapIndex && !maps_.empty()) {
213         mapIndex_.emplace_back(maps_.size() - 1);
214     }
215 }
FindMapIndexByAddr(uintptr_t addr) const216 int DfxMaps::FindMapIndexByAddr(uintptr_t addr) const
217 {
218     size_t first = 0;
219     size_t last = maps_.size();
220     while (first < last) {
221         size_t index = (first + last) / 2;
222         const auto& cur = maps_[index];
223         if (cur == nullptr) {
224             continue;
225         }
226         if (addr >= cur->begin && addr < cur->end) {
227             return index;
228         } else if (addr < cur->begin) {
229             last = index;
230         } else {
231             first = index + 1;
232         }
233     }
234     return -1;
235 }
236 
FindMapByAddr(uintptr_t addr,std::shared_ptr<DfxMap> & map) const237 bool DfxMaps::FindMapByAddr(uintptr_t addr, std::shared_ptr<DfxMap>& map) const
238 {
239     if ((maps_.empty()) || (addr == 0x0)) {
240         return false;
241     }
242     int findMapIndex = FindMapIndexByAddr(addr);
243     if (findMapIndex >= 0) {
244         map = maps_[findMapIndex];
245     }
246     if (findMapIndex >= 1) {
247         map->prevMap = maps_[findMapIndex - 1];
248     }
249     return findMapIndex >= 0;
250 }
251 
FindMapGroupByAddr(uintptr_t addr,std::set<DfxMap> & maps) const252 bool DfxMaps::FindMapGroupByAddr(uintptr_t addr, std::set<DfxMap>& maps) const
253 {
254     if ((maps_.empty()) || (addr == 0x0)) {
255         return false;
256     }
257     int findMapIndex = FindMapIndexByAddr(addr);
258     if (findMapIndex == -1 || maps_[findMapIndex] == nullptr) {
259         return false;
260     }
261     maps.emplace(*maps_[findMapIndex]);
262     if (maps_[findMapIndex]->inode == 0) { // anno page
263         return true;
264     }
265     // Find other segments mapped to the same file
266     for (int index = findMapIndex - 1; index >= 0; --index) { // search up
267         if (maps_[index] == nullptr) {
268             continue;
269         }
270         if (maps_[index]->inode != maps_[findMapIndex]->inode) {
271             break;
272         }
273         maps.emplace(*maps_[index]);
274     }
275 
276     for (size_t index = static_cast<size_t>(findMapIndex + 1); index < maps_.size(); ++index) { // search down
277         if (maps_[index] == nullptr) {
278             continue;
279         }
280         if (maps_[index]->inode != maps_[findMapIndex]->inode) {
281             break;
282         }
283         maps.emplace(*maps_[index]);
284     }
285 
286     return true;
287 }
288 
FindMapByFileInfo(std::string name,uint64_t offset,std::shared_ptr<DfxMap> & map) const289 bool DfxMaps::FindMapByFileInfo(std::string name, uint64_t offset, std::shared_ptr<DfxMap>& map) const
290 {
291     for (auto &iter : maps_) {
292         if (name != iter->name) {
293             continue;
294         }
295 
296         if (offset >= iter->offset && (offset - iter->offset) < (iter->end - iter->begin)) {
297             DFXLOGI("Found name: %{public}s, offset 0x%{public}" PRIx64 " in map " \
298                 "(%{public}" PRIx64 "-%{public}" PRIx64 " offset 0x%{public}" PRIx64 ")",
299                 name.c_str(), offset, iter->begin, iter->end, iter->offset);
300             map = iter;
301             return true;
302         }
303     }
304     return false;
305 }
306 
FindMapsByName(std::string name,std::vector<std::shared_ptr<DfxMap>> & maps) const307 bool DfxMaps::FindMapsByName(std::string name, std::vector<std::shared_ptr<DfxMap>>& maps) const
308 {
309     if (maps_.empty()) {
310         return false;
311     }
312     for (auto &iter : maps_) {
313         if (EndsWith(iter->name, name)) {
314             maps.emplace_back(iter);
315         }
316     }
317     return (maps.size() > 0);
318 }
319 
Sort(bool less)320 void DfxMaps::Sort(bool less)
321 {
322     if (maps_.empty()) {
323         return;
324     }
325     if (less) {
326         std::sort(maps_.begin(), maps_.end(),
327             [](const std::shared_ptr<DfxMap>& a, const std::shared_ptr<DfxMap>& b) {
328             if (a == nullptr) {
329                 return false;
330             } else if (b == nullptr) {
331                 return true;
332             }
333             return a->begin < b->begin;
334         });
335     } else {
336         std::sort(maps_.begin(), maps_.end(),
337             [](const std::shared_ptr<DfxMap>& a, const std::shared_ptr<DfxMap>& b) {
338             if (a == nullptr) {
339                 return true;
340             } else if (b == nullptr) {
341                 return false;
342             }
343             return a->begin > b->begin;
344         });
345     }
346 }
347 
GetStackRange(uintptr_t & bottom,uintptr_t & top)348 bool DfxMaps::GetStackRange(uintptr_t& bottom, uintptr_t& top)
349 {
350     if (stackBottom_ == 0 || stackTop_ == 0) {
351         return false;
352     }
353     bottom = stackBottom_;
354     top = stackTop_;
355     return true;
356 }
357 
GetArkStackRange(uintptr_t & start,uintptr_t & end)358 bool DfxMaps::GetArkStackRange(uintptr_t& start, uintptr_t& end)
359 {
360     if (ArkStackStart_ == 0 || ArkStackEnd_ == 0) {
361         return false;
362     }
363     start = ArkStackStart_;
364     end = ArkStackEnd_;
365     return true;
366 }
367 
IsArkExecutedMap(uintptr_t addr)368 bool DfxMaps::IsArkExecutedMap(uintptr_t addr)
369 {
370     std::shared_ptr<DfxMap> map = nullptr;
371     if (!FindMapByAddr(addr, map)) {
372         DFXLOGU("Not mapped map for current addr.");
373         return false;
374     }
375     return map->IsArkExecutable();
376 }
377 } // namespace HiviewDFX
378 } // namespace OHOS
379