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