• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #define HILOG_TAG "RuntimeThread"
16 
17 #include "virtual_thread.h"
18 
19 #include <cinttypes>
20 #include <iostream>
21 #include <sstream>
22 #if !is_mingw
23 #include <sys/mman.h>
24 #endif
25 
26 #include "symbols_file.h"
27 #include "utilities.h"
28 #include "virtual_runtime.h"
29 namespace OHOS {
30 namespace Developtools {
31 namespace HiPerf {
32 #ifdef DEBUG_TIME
33 
IsSorted() const34 bool VirtualThread::IsSorted() const
35 {
36     for (std::size_t index = 1; index < memMaps_.size(); ++index) {
37         if (memMaps_[memMapsIndexs_[index - 1]]->end > memMaps_[memMapsIndexs_[index]]->begin) {
38             std::cout << "memMaps_ order error:\n"
39                       << "    " << memMaps_[memMapsIndexs_[index - 1]]->begin << "-"
40                       << memMaps_[memMapsIndexs_[index - 1]]->end
41                       << "    " << memMaps_[memMapsIndexs_[index]]->begin << "-"
42                       << memMaps_[memMapsIndexs_[index]]->end;
43             return false;
44         }
45     }
46     return true;
47 }
48 #endif
49 
FindMapIndexByAddr(uint64_t addr) const50 int64_t VirtualThread::FindMapIndexByAddr(uint64_t addr) const
51 {
52     HLOGM("try found vaddr 0x%" PRIx64 "in maps %zu", addr, memMaps_.size());
53     const int64_t illegal = -1;
54     if (memMaps_.size() == 0) {
55         return illegal;
56     }
57     if (memMaps_[memMapsIndexs_[0]]->begin > addr) {
58         return illegal;
59     }
60     if (memMaps_[memMapsIndexs_[memMapsIndexs_.size() -  1]]->end <= addr) {
61         return illegal;
62     }
63     constexpr int divisorNum {2};
64     std::size_t left {0};
65     std::size_t right {memMapsIndexs_.size()};
66     std::size_t mid = (right - left) / divisorNum + left;
67     while (left < right) {
68         if (addr < memMaps_[memMapsIndexs_[mid]]->end) {
69             right = mid;
70             mid = (right - left) / divisorNum + left;
71             continue;
72         }
73         if (addr >= memMaps_[memMapsIndexs_[mid]]->end) {
74             left = mid + 1;
75             mid = (right - left) / divisorNum + left;
76             continue;
77         }
78     }
79     if (addr >= memMaps_[memMapsIndexs_[left]]->begin && addr < memMaps_[memMapsIndexs_[left]]->end) {
80         if (left > 0) {
81             memMaps_[memMapsIndexs_[left]]->prevMap = memMaps_[memMapsIndexs_[left - 1]];
82         }
83         return static_cast<int64_t>(memMapsIndexs_[left]);
84     }
85     return illegal;
86 }
87 
FindMapByAddr(uint64_t addr) const88 std::shared_ptr<DfxMap> VirtualThread::FindMapByAddr(uint64_t addr) const
89 {
90     HLOGM("try found vaddr 0x%" PRIx64 "in maps %zu", addr, memMaps_.size());
91     if (memMaps_.size() == 0) {
92         return nullptr;
93     }
94     if (memMaps_[memMapsIndexs_[0]]->begin > addr) {
95         return nullptr;
96     }
97     if (memMaps_[memMapsIndexs_[memMapsIndexs_.size() - 1]]->end <= addr) {
98         return nullptr;
99     }
100     constexpr int divisorNum {2};
101     std::size_t left {0};
102     std::size_t right {memMapsIndexs_.size()};
103     std::size_t mid = (right - left) / divisorNum + left;
104     while (left < right) {
105         if (addr < memMaps_[memMapsIndexs_[mid]]->end) {
106             right = mid;
107             mid = (right - left) / divisorNum + left;
108             continue;
109         }
110         if (addr >= memMaps_[memMapsIndexs_[mid]]->end) {
111             left = mid + 1;
112             mid = (right - left) / divisorNum + left;
113             continue;
114         }
115     }
116     if (addr >= memMaps_[memMapsIndexs_[left]]->begin && addr < memMaps_[memMapsIndexs_[left]]->end) {
117         if (left > 0) {
118             memMaps_[memMapsIndexs_[left]]->prevMap = memMaps_[memMapsIndexs_[left - 1]];
119         }
120         return memMaps_[memMapsIndexs_[left]];
121     }
122     return nullptr;
123 }
124 
FindMapByFileInfo(const std::string name,uint64_t offset) const125 std::shared_ptr<DfxMap> VirtualThread::FindMapByFileInfo(const std::string name, uint64_t offset) const
126 {
127     for (auto &map : memMaps_) {
128         if (name != map->name) {
129             continue;
130         }
131         // check begin and length
132         if (offset >= map->offset && (offset - map->offset) < (map->end - map->begin)) {
133             HLOGMMM("found fileoffset 0x%" PRIx64 " in map (0x%" PRIx64 " - 0x%" PRIx64
134                     " pageoffset 0x%" PRIx64 ")  from %s",
135                     offset, map->begin, map->end, map->offset, map->name.c_str());
136             return map;
137         }
138     }
139     HLOGM("NOT found offset 0x%" PRIx64 " in maps %zu ", offset, memMaps_.size());
140     return nullptr;
141 }
142 
FindSymbolsFileByMap(std::shared_ptr<DfxMap> inMap) const143 SymbolsFile *VirtualThread::FindSymbolsFileByMap(std::shared_ptr<DfxMap> inMap) const
144 {
145     for (auto &symbolsFile : symbolsFiles_) {
146         if (symbolsFile->filePath_ == inMap->name) {
147             HLOGM("found symbol for map '%s'", inMap->name.c_str());
148             if (symbolsFile->LoadDebugInfo(inMap)) {
149                 HLOGM("found symbol for map '%s'", inMap->name.c_str());
150                 return symbolsFile.get();
151             }
152             break;
153         }
154     }
155 
156 #ifdef DEBUG_MISS_SYMBOL
157     if (find(missedSymbolFile_.begin(), missedSymbolFile_.end(), inMap.name) ==
158         missedSymbolFile_.end()) {
159         missedSymbolFile_.emplace_back(inMap.name);
160         HLOGW("NOT found symbol for map '%s'", inMap.name.c_str());
161         for (const auto &file : symbolsFiles_) {
162             HLOGW(" we have '%s'", file->filePath_.c_str());
163         }
164     }
165 #endif
166     return nullptr;
167 }
ReportVaddrMapMiss(uint64_t vaddr) const168 void VirtualThread::ReportVaddrMapMiss(uint64_t vaddr) const
169 {
170 #ifdef HIPERF_DEBUG
171     if (DebugLogger::logDisabled_) {
172         return;
173     }
174     if (DebugLogger::GetInstance()->GetLogLevel() <= LEVEL_VERBOSE) {
175         if (missedRuntimeVaddr_.find(vaddr) == missedRuntimeVaddr_.end()) {
176             missedRuntimeVaddr_.insert(vaddr);
177             HLOGV("vaddr %" PRIx64 " not found in any map", vaddr);
178             for (auto &map : memMaps_) {
179                 HLOGV("map %s ", map->ToString().c_str());
180             }
181         }
182     }
183 #endif
184 }
185 
ReadRoMemory(uint64_t vaddr,uint8_t * data,size_t size) const186 bool VirtualThread::ReadRoMemory(uint64_t vaddr, uint8_t *data, size_t size) const
187 {
188     uint64_t pageIndex = vaddr >> 12;
189     uint64_t memMapIndex = -1;
190     const int64_t exceptRet = -1;
191     const uint64_t illegal = -1;
192     auto pageFile = vaddr4kPageCache_.find(pageIndex);
193     if (pageFile != vaddr4kPageCache_.end()) {
194         memMapIndex = pageFile->second;
195     } else {
196         int64_t retIndex = FindMapIndexByAddr(vaddr);
197         memMapIndex = static_cast<uint64_t>(retIndex);
198         // add to 4k page cache table
199         if (retIndex != exceptRet && memMapIndex < memMaps_.size()) {
200             const_cast<VirtualThread *>(this)->vaddr4kPageCache_[pageIndex] = memMapIndex;
201         }
202     }
203     if (memMapIndex != illegal) {
204         auto map = memMaps_[memMapIndex];
205         if (map->elf == nullptr) {
206             SymbolsFile* symFile = FindSymbolsFileByMap(map);
207             if (symFile == nullptr) {
208                 return false;
209             }
210             map->elf = symFile->GetElfFile();
211         }
212         if (map->elf != nullptr) {
213             // default base offset is zero
214             uint64_t foff = vaddr - map->begin + map->offset - map->elf->GetBaseOffset();
215             if (map->elf->Read(foff, data, size)) {
216                 return true;
217             } else {
218                 return false;
219             }
220         } else {
221             HLOGW("find addr %" PRIx64 "in map but not loaded symbole %s", vaddr, map->name.c_str());
222         }
223     } else {
224 #ifdef HIPERF_DEBUG
225         ReportVaddrMapMiss(vaddr);
226 #endif
227     }
228     return false;
229 }
230 
231 #if defined(is_mingw) && is_mingw
ParseMap()232 void VirtualThread::ParseMap()
233 {
234     // only linux support read maps in runtime
235     return;
236 }
237 #else
ParseMap()238 void VirtualThread::ParseMap()
239 {
240     if (!(OHOS::HiviewDFX::DfxMaps::Create(pid_, memMaps_, memMapsIndexs_))) {
241         HLOGE("VirtualThread Failed to Parse Map.");
242     }
243     SortMemMaps();
244 }
245 #endif
246 
FixHMBundleMap()247 void VirtualThread::FixHMBundleMap()
248 {
249     // fix bundle path in map
250     for (auto &map : memMaps_) {
251         NeedAdaptHMBundlePath(map->name, name_);
252     }
253 }
254 
255 constexpr const int MMAP_LINE_TOKEN_INDEX_FLAG = 1;
256 constexpr const int MMAP_LINE_TOKEN_INDEX_OFFSET = 2;
257 constexpr const int MMAP_LINE_TOKEN_INDEX_NAME = 5;
258 constexpr const int MMAP_LINE_MAX_TOKEN = 6;
ParseServiceMap(const std::string & filename)259 void VirtualThread::ParseServiceMap(const std::string &filename)
260 {
261     std::string mapPath = StringPrintf("/proc/%d/maps", pid_);
262     std::string mapContent = ReadFileToString(mapPath);
263     uint64_t begin = 0;
264     uint64_t end = 0;
265     if (mapContent.size() == 0) {
266         HLOGW("Parse %s failed, content empty", mapPath.c_str());
267         return;
268     }
269     std::istringstream s(mapContent);
270     std::string line;
271     while (std::getline(s, line)) {
272         std::vector<std::string> mapTokens = StringSplit(line, " ");
273         if (mapTokens.size() == MMAP_LINE_MAX_TOKEN &&
274             mapTokens[MMAP_LINE_TOKEN_INDEX_NAME] == name_) {
275             HLOGM("map line: %s", line.c_str());
276             std::vector<std::string> addrRanges = StringSplit(mapTokens[0], "-");
277             begin = std::stoull(addrRanges[0], nullptr, NUMBER_FORMAT_HEX_BASE);
278             end = std::stoull(addrRanges[1], nullptr, NUMBER_FORMAT_HEX_BASE);
279             break;
280         }
281     }
282     CreateMapItem(filename, begin, end - begin, 0);
283 }
284 
ParseDevhostMap(pid_t devhost)285 void VirtualThread::ParseDevhostMap(pid_t devhost)
286 {
287     std::string mapPath = StringPrintf("/proc/%d/maps", devhost);
288     std::string mapContent = ReadFileToString(mapPath);
289     std::string filename;
290     uint64_t begin, end, offset;
291     if (mapContent.size() > 0) {
292         std::istringstream s(mapContent);
293         std::string line;
294         while (std::getline(s, line)) {
295             // 2fe40000-311e1000 r-xp 00000000 00:01 217 /lib/libdh-linux.so.5.10.97-oh
296             // 0                 1    2        3     4   5
297             std::vector<std::string> mapTokens = StringSplit(line, " ");
298             if (mapTokens.size() < MMAP_LINE_MAX_TOKEN) {
299                 continue;
300             }
301             HLOGM("map line: %s", line.c_str());
302 
303             // 2fe40000-311e1000
304             constexpr const int MMAP_ADDR_RANGE_TOKEN = 2;
305             std::vector<std::string> addrRanges = StringSplit(mapTokens[0], "-");
306             if (addrRanges.size() != MMAP_ADDR_RANGE_TOKEN) {
307                 continue;
308             }
309             // 2fe40000 / 311e1000
310             try {
311                 begin = std::stoull(addrRanges[0], nullptr, NUMBER_FORMAT_HEX_BASE);
312                 end = std::stoull(addrRanges[1], nullptr, NUMBER_FORMAT_HEX_BASE);
313                 offset = std::stoull(mapTokens[MMAP_LINE_TOKEN_INDEX_OFFSET],
314                                      nullptr, NUMBER_FORMAT_HEX_BASE);
315             } catch (...) {
316                 continue;
317             }
318 
319             constexpr const int MMAP_PROT_CHARS = 4;
320             constexpr const int MAP_PROT_EXEC_INDEX = 2;
321             // --x-
322             if (mapTokens[MMAP_LINE_TOKEN_INDEX_FLAG].size() != MMAP_PROT_CHARS ||
323                 mapTokens[MMAP_LINE_TOKEN_INDEX_FLAG][MAP_PROT_EXEC_INDEX] != 'x') {
324                 continue;
325             }
326 
327             const std::string ANON_PREFIX = "[anon:[";
328             const std::string ANON_POSTFIX = "]]";
329             filename = mapTokens[MMAP_LINE_TOKEN_INDEX_NAME];
330             if (filename == "shmm") {
331                 continue;
332             }
333             if (filename.find(ANON_PREFIX) != std::string::npos) {
334                 // '[anon:[liblinux/devhost.ko]]' to '/liblinux/devhost.ko'
335                 filename = filename.substr(ANON_PREFIX.size(),
336                                            filename.size() - ANON_PREFIX.size() -
337                                            ANON_POSTFIX.size());
338                 filename = "/" + filename;
339             } else if (filename.find(DEVHOST_LINUX_FILE_NAME) != std::string::npos) {
340                 // '/lib/libdh-linux.so.5.10.97-oh' to '/lib/libdh-linux.so'
341                 filename = DEVHOST_LINUX_FILE_NAME;
342             }
343             CreateMapItem(filename, begin, end - begin, offset);
344         }
345     }
346     SortMemMaps();
347 }
348 
SortMemMaps()349 void VirtualThread::SortMemMaps()
350 {
351     for (int currPos = 1; currPos < static_cast<int>(memMaps_.size()); ++currPos) {
352         int targetPos = currPos - 1;
353         while (targetPos >= 0 and memMaps_[memMapsIndexs_[currPos]]->end < memMaps_[memMapsIndexs_[targetPos]]->end) {
354             --targetPos;
355         }
356         if (targetPos < currPos - 1) {
357             auto target = memMapsIndexs_[currPos];
358             for (int k = currPos - 1; k > targetPos; --k) {
359                 memMapsIndexs_[k + 1] = memMapsIndexs_[k];
360             }
361             memMapsIndexs_[targetPos + 1] = target;
362         }
363     }
364 }
365 
CreateMapItem(const std::string filename,uint64_t begin,uint64_t len,uint64_t offset)366 void VirtualThread::CreateMapItem(const std::string filename, uint64_t begin, uint64_t len,
367                                   uint64_t offset)
368 {
369     if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(filename)) {
370         return; // skip some memmap
371     }
372     std::shared_ptr<DfxMap> map = memMaps_.emplace_back(std::make_shared<DfxMap>(begin, begin + len, offset,
373         "", filename));
374     memMapsIndexs_.emplace_back(memMaps_.size() - 1);
375     HLOGD(" %u:%u create a new map(total %zu) at '%s' (0x%" PRIx64 "-0x%" PRIx64 ")@0x%" PRIx64 " ",
376           pid_, tid_, memMaps_.size(), map->name.c_str(), map->begin, map->end, map->offset);
377     SortMemMaps();
378 }
379 } // namespace HiPerf
380 } // namespace Developtools
381 } // namespace OHOS
382