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