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 "dfx_maps.h"
17
18 #include <algorithm>
19 #include <cinttypes>
20 #include <climits>
21 #include <cstdio>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 #include <memory>
26 #include <securec.h>
27 #include <sys/mman.h>
28 #include <string>
29 #include <sstream>
30 #include <vector>
31 #include "dfx_define.h"
32 #include "dfx_elf.h"
33 #include "dfx_memory_file.h"
34 #include "dfx_log.h"
35 #include "dfx_util.h"
36
37 namespace OHOS {
38 namespace HiviewDFX {
39 static const int MAPINFO_SIZE = 256;
40 MAYBE_UNUSED static constexpr int X86_ONE_STEP_NORMAL = 1;
41 MAYBE_UNUSED static constexpr int ARM_TWO_STEP_NORMAL = 2;
42 MAYBE_UNUSED static constexpr int ARM_FOUR_STEP_NORMAL = 4;
43 MAYBE_UNUSED static constexpr int PROT_DEVICE_MAP = 0x8000;
44
Create(const std::string mapBuf,int size)45 std::shared_ptr<DfxElfMap> DfxElfMap::Create(const std::string mapBuf, int size)
46 {
47 auto elfMap = std::make_shared<DfxElfMap>();
48
49 int pos = 0;
50 uint64_t begin = 0;
51 uint64_t end = 0;
52 uint64_t offset = 0;
53 char perms[5] = {0}; // 5:rwxp
54
55 // 7658d38000-7658d40000 rw-p 00000000 00:00 0 [anon:thread signal stack]
56 if (sscanf_s(mapBuf.c_str(), "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %*x:%*x %*d%n", &begin, &end,
57 &perms, sizeof(perms), &offset,
58 &pos) != 4) { // 4:scan size
59 DFXLOG_WARN("Fail to parse maps info.");
60 return nullptr;
61 }
62
63 elfMap->begin = begin;
64 elfMap->end = end;
65 elfMap->offset = offset;
66 elfMap->perms = std::string(perms, sizeof(perms));
67 PermsToProts(elfMap->perms, elfMap->prots);
68 TrimAndDupStr(mapBuf.substr(pos), elfMap->path);
69 if (!elfMap->IsValidPath()) {
70 elfMap->prots |= PROT_DEVICE_MAP;
71 }
72 return elfMap;
73 }
74
Create(pid_t pid)75 std::shared_ptr<DfxElfMaps> DfxElfMaps::Create(pid_t pid)
76 {
77 char path[NAME_LEN] = {0};
78 if (snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%d/maps", pid) <= 0) {
79 DFXLOG_WARN("Fail to print path.");
80 return nullptr;
81 }
82 return Create(std::string(path));
83 }
84
CreateFromLocal()85 std::shared_ptr<DfxElfMaps> DfxElfMaps::CreateFromLocal()
86 {
87 return Create(std::string("/proc/self/maps"));
88 }
89
Create(const std::string path)90 std::shared_ptr<DfxElfMaps> DfxElfMaps::Create(const std::string path)
91 {
92 char realPath[PATH_MAX] = {0};
93 if (realpath(path.c_str(), realPath) == nullptr) {
94 DFXLOG_WARN("Maps path(%s) is not exist.", path.c_str());
95 return nullptr;
96 }
97
98 FILE *fp = fopen(realPath, "r");
99 if (fp == nullptr) {
100 DFXLOG_WARN("Fail to open maps info.");
101 return nullptr;
102 }
103
104 auto dfxElfMaps = std::make_shared<DfxElfMaps>();
105 char mapBuf[MAPINFO_SIZE] = {0};
106 while (fgets(mapBuf, sizeof(mapBuf), fp) != nullptr) {
107 std::shared_ptr<DfxElfMap> map = DfxElfMap::Create(mapBuf, sizeof(mapBuf));
108 if (map == nullptr) {
109 DFXLOG_WARN("Fail to init map info:%s.", mapBuf);
110 continue;
111 } else {
112 dfxElfMaps->AddMap(map);
113 }
114 }
115 int ret = fclose(fp);
116 if (ret < 0) {
117 DFXLOG_WARN("Fail to close maps info.");
118 }
119 dfxElfMaps->Sort();
120 return dfxElfMaps;
121 }
122
Create(const char * buffer)123 std::shared_ptr<DfxElfMaps> DfxElfMaps::Create(const char* buffer)
124 {
125 if (buffer == nullptr) {
126 return nullptr;
127 }
128 std::istringstream iss(buffer);
129 std::string temp;
130 auto dfxElfMaps = std::make_shared<DfxElfMaps>();
131 while (std::getline(iss, temp)) {
132 std::shared_ptr<DfxElfMap> map = DfxElfMap::Create(temp, temp.length());
133 if (map == nullptr) {
134 DFXLOG_WARN("Fail to init map info:%s.", temp.c_str());
135 continue;
136 } else {
137 dfxElfMaps->AddMap(map);
138 }
139 }
140 dfxElfMaps->Sort();
141 return dfxElfMaps;
142 }
143
AddMap(std::shared_ptr<DfxElfMap> map)144 void DfxElfMaps::AddMap(std::shared_ptr<DfxElfMap> map)
145 {
146 maps_.push_back(map);
147 return;
148 }
149
FindMapByAddr(uintptr_t address,std::shared_ptr<DfxElfMap> & map) const150 bool DfxElfMaps::FindMapByAddr(uintptr_t address, std::shared_ptr<DfxElfMap>& map) const
151 {
152 if ((maps_.size() == 0) || (address == 0x0)) {
153 return false;
154 }
155
156 size_t first = 0;
157 size_t last = maps_.size();
158 while (first < last) {
159 size_t index = (first + last) / 2;
160 const auto& cur = maps_[index];
161 if (address >= cur->begin && address < cur->end) {
162 map = cur;
163 return true;
164 } else if (address < cur->begin) {
165 last = index;
166 } else {
167 first = index + 1;
168 }
169 }
170 return false;
171 }
172
Sort(bool less)173 void DfxElfMaps::Sort(bool less)
174 {
175 if (less) {
176 std::sort(maps_.begin(), maps_.end(),
177 [](const std::shared_ptr<DfxElfMap>& a, const std::shared_ptr<DfxElfMap>& b) {
178 return a->begin < b->begin;
179 });
180 } else {
181 std::sort(maps_.begin(), maps_.end(),
182 [](const std::shared_ptr<DfxElfMap>& a, const std::shared_ptr<DfxElfMap>& b) {
183 return a->begin > b->begin;
184 });
185 }
186 }
187
GetMaps() const188 const std::vector<std::shared_ptr<DfxElfMap>>& DfxElfMaps::GetMaps() const
189 {
190 return maps_;
191 }
192
IsValidPath()193 bool DfxElfMap::IsValidPath()
194 {
195 if (path.length() == 0) {
196 return false;
197 }
198
199 if (strncmp(path.c_str(), "/dev/", 5) == 0) { // 5:length of "/dev/"
200 return false;
201 }
202 return true;
203 }
204
PrintMap()205 std::string DfxElfMap::PrintMap()
206 {
207 char buf[LOG_BUF_LEN] = {0};
208 int ret = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "%" PRIx64 "-%" PRIx64 " %s %08" PRIx64 " %s\n", \
209 begin, end, perms.c_str(), offset, path.c_str());
210 if (ret <= 0) {
211 DFXLOG_ERROR("%s :: snprintf_s failed, line: %d.", __func__, __LINE__);
212 }
213 return std::string(buf);
214 }
215
PermsToProts(const std::string perms,uint64_t & prots)216 void DfxElfMap::PermsToProts(const std::string perms, uint64_t& prots)
217 {
218 prots = PROT_NONE;
219 // rwxp
220 if (perms.find("r") != std::string::npos) {
221 prots |= PROT_READ;
222 }
223
224 if (perms.find("w") != std::string::npos) {
225 prots |= PROT_WRITE;
226 }
227
228 if (perms.find("x") != std::string::npos) {
229 prots |= PROT_EXEC;
230 }
231 }
232
GetRelPc(uint64_t pc)233 uint64_t DfxElfMap::GetRelPc(uint64_t pc)
234 {
235 uint64_t relPc = 0;
236 if (elf == nullptr) {
237 auto memory = DfxMemoryFile::CreateFileMemory(path, 0);
238 if (memory != nullptr) {
239 elf = std::make_shared<DfxElf>(memory);
240 }
241 }
242
243 if (elf == nullptr) {
244 relPc = pc - (begin - offset);
245 } else {
246 relPc = (pc - begin) + elf->GetRealLoadOffset(offset);
247 }
248
249 #ifdef __aarch64__
250 relPc = relPc - 4; // 4 : instr offset
251 #elif defined(__x86_64__)
252 relPc = relPc - 1; // 1 : instr offset
253 #endif
254 return relPc;
255 }
256
GetPcAdjustment(uint64_t pc)257 uint32_t DfxElfMap::GetPcAdjustment(uint64_t pc)
258 {
259 if (pc <= ARM_FOUR_STEP_NORMAL) { // pc zero is abnormal case, so we don't adjust pc.
260 return 0;
261 }
262 uint32_t sz = ARM_FOUR_STEP_NORMAL;
263 #if defined(__arm__)
264 if (pc & 1) {
265 // This is a thumb instruction, it could be 2 or 4 bytes.
266 uint32_t value;
267 uint64_t adjustedPc = pc - 5;
268 if ((perms.find("r") == std::string::npos) ||
269 adjustedPc < begin || (adjustedPc + sizeof(value)) >= end ||
270 memcpy_s(&value, sizeof(value), reinterpret_cast<const void *>(adjustedPc), sizeof(value)) ||
271 (value & 0xe000f000) != 0xe000f000) {
272 sz = ARM_TWO_STEP_NORMAL;
273 }
274 }
275 #elif defined(__aarch64__)
276 sz = ARM_FOUR_STEP_NORMAL;
277 #elif defined(__x86_64__)
278 sz = X86_ONE_STEP_NORMAL;
279 #endif
280 return sz;
281 }
282 } // namespace HiviewDFX
283 } // namespace OHOS
284