• 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 <fstream>
21 #include <securec.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_elf.h"
30 #include "dfx_log.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 }
42 
GetMapsFile(pid_t pid)43 const std::string DfxMaps::GetMapsFile(pid_t pid)
44 {
45     if (pid < 0) {
46         return "";
47     }
48     std::string path;
49     if ((pid == 0) || (pid == getpid())) {
50         path = std::string(PROC_SELF_MAPS_PATH);
51     } else {
52         path = StringPrintf("/proc/%d/maps", (int)pid);
53     }
54     return path;
55 }
56 
Create(pid_t pid)57 std::shared_ptr<DfxMaps> DfxMaps::Create(pid_t pid)
58 {
59     std::string path = GetMapsFile(pid);
60     if (path == "") {
61         return nullptr;
62     }
63     return Create(pid, path);
64 }
65 
Create(const pid_t pid,std::vector<std::shared_ptr<DfxMap>> & maps,std::vector<int> & mapIndex)66 bool DfxMaps::Create(const pid_t pid, std::vector<std::shared_ptr<DfxMap>>& maps, std::vector<int>& mapIndex)
67 {
68     std::string path = GetMapsFile(pid);
69     if (path == "") {
70         return false;
71     }
72     auto dfxMaps = Create(pid, path, true);
73     if (dfxMaps == nullptr) {
74         LOGE("Create maps error, path: %s", path.c_str());
75         return false;
76     }
77     maps = dfxMaps->GetMaps();
78     mapIndex = dfxMaps->GetMapIndexVec();
79     return true;
80 }
81 
Create(const pid_t pid,const std::string & path,bool enableMapIndex)82 std::shared_ptr<DfxMaps> DfxMaps::Create(const pid_t pid, const std::string& path, bool enableMapIndex)
83 {
84     std::string realPath = path;
85     if (!RealPath(path, realPath)) {
86         DFXLOG_WARN("Failed to realpath %s", path.c_str());
87         return nullptr;
88     }
89 
90     std::ifstream ifs;
91     ifs.open(realPath, std::ios::in);
92     if (ifs.fail()) {
93         DFXLOG_WARN("Failed to open %s", realPath.c_str());
94         return nullptr;
95     }
96 
97     auto dfxMaps = std::make_shared<DfxMaps>();
98     std::string mapBuf;
99     while (getline(ifs, mapBuf)) {
100         std::shared_ptr<DfxMap> map = DfxMap::Create(mapBuf, mapBuf.length());
101         if (map == nullptr) {
102             DFXLOG_WARN("Failed to init map info:%s.", mapBuf.c_str());
103             continue;
104         } else {
105             if (map->name == "[stack]") {
106                 dfxMaps->stackBottom_ = (uintptr_t)map->begin;
107                 dfxMaps->stackTop_ = (uintptr_t)map->end;
108             }
109             FormatMapName(pid, map->name);
110             if ((!enableMapIndex) || IsLegalMapItem(map->name)) {
111                 dfxMaps->AddMap(map, enableMapIndex);
112             }
113         }
114     }
115     ifs.close();
116     if (!enableMapIndex) {
117         dfxMaps->Sort();
118     }
119     return dfxMaps;
120 }
121 
FormatMapName(pid_t pid,std::string & mapName)122 void DfxMaps::FormatMapName(pid_t pid, std::string& mapName)
123 {
124     // format sandbox file path, add '/proc/xxx/root' prefix
125     if (StartsWith(mapName, "/data/storage/") && (pid != getpid())) {
126         mapName = "/proc/" + std::to_string(pid) + "/root" + mapName;
127     }
128 }
129 
UnFormatMapName(std::string & mapName)130 void DfxMaps::UnFormatMapName(std::string& mapName)
131 {
132     // unformat sandbox file path, drop '/proc/xxx/root' prefix
133     if (StartsWith(mapName, "/proc/")) {
134         auto startPos = mapName.find("/data/storage/");
135         if (startPos != std::string::npos) {
136             mapName = mapName.substr(startPos);
137         }
138     }
139 }
140 
IsLegalMapItem(const std::string & name)141 bool DfxMaps::IsLegalMapItem(const std::string& name)
142 {
143     // some special
144     if (StartsWith(name, "[anon:ArkTS Code]")) {
145         return true;
146     }
147     if (EndsWith(name, "[vdso]")) {
148         return true;
149     }
150     if (name.empty() || name.find(':') != std::string::npos || name.front() == '[' ||
151         name.back() == ']' || std::strncmp(name.c_str(), "/dev/", sizeof("/dev/")) == 0 ||
152         std::strncmp(name.c_str(), "/memfd:", sizeof("/memfd:")) == 0 ||
153         std::strncmp(name.c_str(), "//anon", sizeof("//anon")) == 0 ||
154         EndsWith(name, ".ttf") || EndsWith(name, ".ai")) {
155         return false;
156     }
157     return true;
158 }
159 
AddMap(std::shared_ptr<DfxMap> map,bool enableMapIndex)160 void DfxMaps::AddMap(std::shared_ptr<DfxMap> map, bool enableMapIndex)
161 {
162     maps_.emplace_back(map);
163     if (enableMapIndex) {
164         mapIndex_.emplace_back(maps_.size() - 1);
165     }
166 }
167 
FindMapByAddr(uintptr_t addr,std::shared_ptr<DfxMap> & map) const168 bool DfxMaps::FindMapByAddr(uintptr_t addr, std::shared_ptr<DfxMap>& map) const
169 {
170     if ((maps_.empty()) || (addr == 0x0)) {
171         return false;
172     }
173 
174     size_t first = 0;
175     size_t last = maps_.size();
176     while (first < last) {
177         size_t index = (first + last) / 2;
178         const auto& cur = maps_[index];
179         if (addr >= cur->begin && addr < cur->end) {
180             map = cur;
181             if (index > 0) {
182                 map->prevMap = maps_[index - 1];
183             }
184             return true;
185         } else if (addr < cur->begin) {
186             last = index;
187         } else {
188             first = index + 1;
189         }
190     }
191     return false;
192 }
193 
FindMapByFileInfo(std::string name,uint64_t offset,std::shared_ptr<DfxMap> & map) const194 bool DfxMaps::FindMapByFileInfo(std::string name, uint64_t offset, std::shared_ptr<DfxMap>& map) const
195 {
196     for (auto &iter : maps_) {
197         if (name != iter->name) {
198             continue;
199         }
200 
201         if (offset >= iter->offset && (offset - iter->offset) < (iter->end - iter->begin)) {
202             LOGI("Found name: %s, offset 0x%" PRIx64 " in map (%" PRIx64 "-%" PRIx64 " offset 0x%" PRIx64 ")",
203                 name.c_str(), offset, iter->begin, iter->end, iter->offset);
204             map = iter;
205             return true;
206         }
207     }
208     return false;
209 }
210 
FindMapsByName(std::string name,std::vector<std::shared_ptr<DfxMap>> & maps) const211 bool DfxMaps::FindMapsByName(std::string name, std::vector<std::shared_ptr<DfxMap>>& maps) const
212 {
213     if (maps_.empty()) {
214         return false;
215     }
216     for (auto &iter : maps_) {
217         if (EndsWith(iter->name, name)) {
218             maps.emplace_back(iter);
219         }
220     }
221     return (maps.size() > 0);
222 }
223 
Sort(bool less)224 void DfxMaps::Sort(bool less)
225 {
226     if (less) {
227         std::sort(maps_.begin(), maps_.end(),
228             [](const std::shared_ptr<DfxMap>& a, const std::shared_ptr<DfxMap>& b) {
229             if (a == nullptr) {
230                 return false;
231             } else if (b == nullptr) {
232                 return true;
233             }
234             return a->begin < b->begin;
235         });
236     } else {
237         std::sort(maps_.begin(), maps_.end(),
238             [](const std::shared_ptr<DfxMap>& a, const std::shared_ptr<DfxMap>& b) {
239             if (a == nullptr) {
240                 return true;
241             } else if (b == nullptr) {
242                 return false;
243             }
244             return a->begin > b->begin;
245         });
246     }
247 }
248 
GetStackRange(uintptr_t & bottom,uintptr_t & top)249 bool DfxMaps::GetStackRange(uintptr_t& bottom, uintptr_t& top)
250 {
251     if (stackBottom_ == 0 || stackTop_ == 0) {
252         return false;
253     }
254     bottom = stackBottom_;
255     top = stackTop_;
256     return true;
257 }
258 
IsArkExecutedMap(uintptr_t addr)259 bool DfxMaps::IsArkExecutedMap(uintptr_t addr)
260 {
261     std::shared_ptr<DfxMap> map = nullptr;
262     if (!FindMapByAddr(addr, map)) {
263         LOGU("Not mapped map for current addr.");
264         return false;
265     }
266 
267     return map->IsArkExecutable();
268 }
269 } // namespace HiviewDFX
270 } // namespace OHOS
271