• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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